添加qiming-rcoder模块

This commit is contained in:
Codex
2026-06-01 13:54:52 +08:00
parent 8092c4b1f8
commit 4b1a580132
539 changed files with 151650 additions and 0 deletions

View File

@@ -0,0 +1,303 @@
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<T> = Result<T, DockerError>;
/// 默认的 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<String>,
arm64_image: Option<String>,
amd64_image: Option<String>,
default_image: Option<String>,
) -> 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<Arc<DockerManager>> = 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<dyn ContainerRuntime>
///
/// 支持 Docker 和 Kubernetes 运行时
#[cfg(feature = "kubernetes")]
pub async fn get_global_runtime(
) -> container_runtime_api::ContainerRuntimeResult<Arc<dyn container_runtime_api::ContainerRuntime>> {
crate::runtime::RuntimeManager::get().await
}
/// 获取全局 DockerManager 实例
///
/// 注意:此函数仅在 Docker 模式下返回有效的 DockerManager。
/// 如果需要同时支持 Docker 和 K8s请使用 get_global_runtime()
///
/// 如果未初始化,会自动初始化
pub async fn get_global_docker_manager() -> DockerResult<Arc<DockerManager>> {
#[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, R>(f: F) -> DockerResult<R>
where
F: FnOnce(&Arc<DockerManager>) -> R,
{
let manager = get_global_docker_manager().await?;
Ok(f(&manager))
}
}