use thiserror::Error; pub mod container_self_inspector; pub mod container_state_actor; pub mod container_stop; pub mod image_selector; pub mod manager; pub mod path; pub mod types; pub mod utils; // 新增模块 pub mod container_builder; pub mod health; pub mod network; pub mod runtime_selection; // Runtime abstraction (Docker/K8s selection) pub mod runtime; pub use container_self_inspector::*; pub use container_state_actor::*; pub use manager::*; pub use types::*; pub use utils::*; // 公共导出新模块 pub use container_builder::{ContainerConfigBuilder, MountProcessor}; pub use health::{ HttpHealthChecker, ServiceHealthChecker, ServiceHealthStatus, wait_for_service_ready, }; pub use network::{NetworkDetector, build_network_name, parse_project_from_network}; pub use path::{ HostPathResolver, get_host_path_resolver, normalize_path, resolve_container_path_to_host, }; /// Docker manager error type #[derive(Error, Debug)] pub enum DockerError { #[error("docker connection failed: {0}")] ConnectionError(String), #[error("container creation failed: {0}")] ContainerCreationError(String), #[error("container start failed: {0}")] ContainerStartError(String), #[error("container stop failed: {0}")] ContainerStopError(String), #[error("container removal failed: {0}")] ContainerRemoveError(String), #[error("image pull failed: {0}")] ImagePullError(String), #[error("configuration error: {0}")] ConfigurationError(String), #[error("IO error: {0}")] IoError(#[from] std::io::Error), #[error("serialization error: {0}")] SerializationError(#[from] serde_json::Error), #[error("timestamp parsing failed: {0}")] InvalidTimestamp(String), #[error("docker API call timeout: {0}")] Timeout(String), #[error("bollard docker error: {0}")] BollardError(#[from] bollard::errors::Error), } /// Docker 管理器结果类型 pub type DockerResult = Result; /// 默认的 Docker 镜像配置常量 pub mod default_images { /// ARM64 架构的默认镜像 pub const ARM64: &str = "registry.yichamao.com/agent-runner:latest-arm64"; /// AMD64 架构的默认镜像 pub const AMD64: &str = "registry.yichamao.com/agent-runner:latest-amd64"; /// 默认回退镜像(当无法检测架构或架构不匹配时使用) pub const DEFAULT: &str = "registry.yichamao.com/agent-runner:latest"; } /// 默认的 Docker 镜像(根据架构自动选择) /// /// 注意:此函数使用硬编码的默认值,建议使用 `get_docker_image_from_config()` /// 从配置中读取镜像地址 pub fn default_docker_image() -> String { let platform = crate::utils::DockerUtils::auto_detect_platform(); match platform.as_str() { "linux/arm64" => default_images::ARM64.to_string(), "linux/amd64" => default_images::AMD64.to_string(), _ => default_images::DEFAULT.to_string(), // 默认回退 } } /// 获取默认的 ARM64 镜像 pub fn default_arm64_image() -> String { default_images::ARM64.to_string() } /// 获取默认的 AMD64 镜像 pub fn default_amd64_image() -> String { default_images::AMD64.to_string() } /// 获取默认的回退镜像 pub fn default_fallback_image() -> String { default_images::DEFAULT.to_string() } /// 从 rcoder 配置获取 Docker 镜像 /// /// # 参数 /// * `image` - 通用镜像(优先使用,如果指定则忽略架构特定镜像) /// * `arm64_image` - ARM64 架构专用镜像 /// * `amd64_image` - AMD64 架构专用镜像 /// * `default_image` - 默认回退镜像(当无法检测架构或架构不匹配时使用) pub fn get_docker_image_from_config( image: Option, arm64_image: Option, amd64_image: Option, default_image: Option, ) -> String { let platform = crate::utils::DockerUtils::auto_detect_platform(); // 优先使用通用镜像 if let Some(img) = image { return img; } // 根据架构使用特定镜像 match platform.as_str() { "linux/arm64" => arm64_image.unwrap_or_else(|| { default_image.unwrap_or_else(|| default_images::DEFAULT.to_string()) }), "linux/amd64" => amd64_image.unwrap_or_else(|| { default_image.unwrap_or_else(|| default_images::DEFAULT.to_string()) }), _ => default_image.unwrap_or_else(|| default_images::DEFAULT.to_string()), } } /// 默认的平台(使用自动检测) pub fn default_platform() -> String { crate::utils::DockerUtils::auto_detect_platform() } /// 默认的工作目录 pub const DEFAULT_WORK_DIR: &str = "/app"; /// 默认的网络模式 pub const DEFAULT_NETWORK_MODE: &str = "bridge"; /// RCoder 专用网络名称(基础名称,不含 project name 前缀) /// Docker Compose 会自动添加 project name 前缀,实际网络名称为 {project_name}_{network_name} /// 例如: rcoder_agent-network, myapp_agent-network /// /// ⚠️ 注意:实际使用时必须动态检测主容器所在的网络,不能硬编码 pub const RCODER_NETWORK_BASE_NAME: &str = "agent-network"; /// 全局 Docker 管理器实例 pub mod global { use super::*; #[cfg(feature = "kubernetes")] use crate::runtime_selection::RuntimeType; use std::sync::Arc; use tokio::sync::OnceCell; use tracing::{debug, info}; /// 全局 DockerManager 单例(用于向后兼容) static GLOBAL_DOCKER_MANAGER: OnceCell> = OnceCell::const_new(); /// 初始化全局 DockerManager pub async fn init_global_docker_manager() -> DockerResult<()> { let config = DockerManagerConfig::default(); let manager = Arc::new(DockerManager::new(config).await?); GLOBAL_DOCKER_MANAGER.set(manager).map_err(|_| { DockerError::IoError(std::io::Error::new( std::io::ErrorKind::AlreadyExists, "global DockerManager already initialized", )) })?; info!("DockerManager initialized"); Ok(()) } /// 使用自定义配置初始化全局 DockerManager /// /// 注意:此函数保持向后兼容。对于 K8s 支持,请使用 init_global_runtime() #[cfg(feature = "kubernetes")] pub async fn init_global_docker_manager_with_config( config: DockerManagerConfig, ) -> DockerResult<()> { let runtime_type = RuntimeType::from_env(); crate::runtime::RuntimeManager::init(config.clone()) .await .map_err(|e| DockerError::ConfigurationError(e.to_string()))?; info!("Runtime initialized with config"); if runtime_type == RuntimeType::Docker { let manager = Arc::new(DockerManager::new(config).await?); GLOBAL_DOCKER_MANAGER.set(manager).map_err(|_| { DockerError::IoError(std::io::Error::new( std::io::ErrorKind::AlreadyExists, "global DockerManager already initialized", )) })?; info!("DockerManager initialized with config"); } Ok(()) } /// 使用自定义配置初始化全局 DockerManager(无 K8s 支持) #[cfg(not(feature = "kubernetes"))] pub async fn init_global_docker_manager_with_config( config: DockerManagerConfig, ) -> DockerResult<()> { // Initialize RuntimeManager so RUNTIME_INSTANCE is set // This allows RuntimeManager::get() to work in docker compose mode crate::runtime::RuntimeManager::init(config.clone()) .await .map_err(|e| DockerError::ConfigurationError(e.to_string()))?; info!("Runtime initialized with config"); let manager = Arc::new(DockerManager::new(config).await?); GLOBAL_DOCKER_MANAGER.set(manager).map_err(|_| { DockerError::IoError(std::io::Error::new( std::io::ErrorKind::AlreadyExists, "global DockerManager already initialized", )) })?; info!("DockerManager initialized with config"); Ok(()) } /// 初始化全局运行时(RuntimeManager) /// /// 根据 CONTAINER_RUNTIME 环境变量选择 Docker 或 Kubernetes 运行时 #[cfg(feature = "kubernetes")] pub async fn init_global_runtime( config: DockerManagerConfig, ) -> container_runtime_api::ContainerRuntimeResult<()> { crate::runtime::RuntimeManager::init(config).await } /// 获取全局运行时实例(Arc) /// /// 支持 Docker 和 Kubernetes 运行时 #[cfg(feature = "kubernetes")] pub async fn get_global_runtime( ) -> container_runtime_api::ContainerRuntimeResult> { crate::runtime::RuntimeManager::get().await } /// 获取全局 DockerManager 实例 /// /// 注意:此函数仅在 Docker 模式下返回有效的 DockerManager。 /// 如果需要同时支持 Docker 和 K8s,请使用 get_global_runtime() /// /// 如果未初始化,会自动初始化 pub async fn get_global_docker_manager() -> DockerResult> { #[cfg(feature = "kubernetes")] if RuntimeType::from_env() == RuntimeType::Kubernetes { return Err(DockerError::ConfigurationError( "DockerManager is unavailable in Kubernetes runtime mode. Use RuntimeManager::get()" .to_string(), )); } if GLOBAL_DOCKER_MANAGER.get().is_none() { debug!("DockerManager not initialized, starting initialize"); init_global_docker_manager().await?; } GLOBAL_DOCKER_MANAGER.get().cloned().ok_or_else(|| { DockerError::IoError(std::io::Error::new( std::io::ErrorKind::NotFound, "unable to get global DockerManager", )) }) } /// 使用全局 DockerManager 执行操作(向后兼容) pub async fn with_global_docker_manager(f: F) -> DockerResult where F: FnOnce(&Arc) -> R, { let manager = get_global_docker_manager().await?; Ok(f(&manager)) } }