Codex Handbook
cloud-config/src/bundle_loader.rs 71 lines
use crate::backend::BackendBundleClient;use crate::service::CLOUD_CONFIG_BUNDLE_TIMEOUT;use crate::service::CloudConfigBundleService;use codex_config::CloudConfigBundleLoadError;use codex_config::CloudConfigBundleLoadErrorCode;use codex_config::CloudConfigBundleLoader;use codex_config::types::AuthCredentialsStoreMode;use codex_login::AuthKeyringBackendKind;use codex_login::AuthManager;use std::path::PathBuf;use std::sync::Arc;use std::sync::Mutex;use std::sync::OnceLock;use tokio::task::JoinHandle;fn refresher_task_slot() -> &'static Mutex<Option<JoinHandle<()>>> {    static REFRESHER_TASK: OnceLock<Mutex<Option<JoinHandle<()>>>> = OnceLock::new();    REFRESHER_TASK.get_or_init(|| Mutex::new(None))}pub fn cloud_config_bundle_loader(    auth_manager: Arc<AuthManager>,    chatgpt_base_url: String,    codex_home: PathBuf,) -> CloudConfigBundleLoader {    let service = CloudConfigBundleService::new(        auth_manager,        Arc::new(BackendBundleClient::new(chatgpt_base_url)),        codex_home,        CLOUD_CONFIG_BUNDLE_TIMEOUT,    );    let refresh_service = service.clone();    let task = tokio::spawn(async move { service.load_startup_bundle_with_timeout().await });    let refresh_task =        tokio::spawn(async move { refresh_service.refresh_cache_in_background().await });    let mut refresher_guard = refresher_task_slot().lock().unwrap_or_else(|err| {        tracing::warn!("cloud config bundle refresher task slot was poisoned");        err.into_inner()    });    if let Some(existing_task) = refresher_guard.replace(refresh_task) {        existing_task.abort();    }    CloudConfigBundleLoader::new(async move {        task.await.map_err(|err| {            tracing::error!(error = %err, "Cloud config bundle task failed");            CloudConfigBundleLoadError::new(                CloudConfigBundleLoadErrorCode::Internal,                /*status_code*/ None,                format!("cloud config bundle load failed: {err}"),            )        })?    })}pub async fn cloud_config_bundle_loader_for_storage(    codex_home: PathBuf,    enable_codex_api_key_env: bool,    credentials_store_mode: AuthCredentialsStoreMode,    keyring_backend_kind: AuthKeyringBackendKind,    chatgpt_base_url: String,) -> CloudConfigBundleLoader {    let auth_manager = AuthManager::shared(        codex_home.clone(),        enable_codex_api_key_env,        credentials_store_mode,        Some(chatgpt_base_url.clone()),        keyring_backend_kind,    )    .await;    cloud_config_bundle_loader(auth_manager, chatgpt_base_url, codex_home)}