mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
e639e8c4bd
## Why Connector metadata is consumed by connector discovery, ChatGPT integration, core, and TUI code. Treating app-server's wire DTO as the shared domain model reverses the intended dependency direction. ## What changed - Added connector-owned app branding, review, screenshot, metadata, and info types. - Added explicit conversions in app-server and TUI while preserving app-server's wire payloads. - Removed production app-server-protocol dependencies from connectors and ChatGPT connector code. ## Stack This is PR 4 of 6, stacked on [PR #29722](https://github.com/openai/codex/pull/29722). Review only the delta from `codex/split-config-layer-types`. Next: [PR #29724](https://github.com/openai/codex/pull/29724). ## Validation - Connector and tools coverage passed. - App-server app-list coverage passed: 13 tests.
113 lines
3.4 KiB
Rust
113 lines
3.4 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use sha1::Digest;
|
|
use sha1::Sha1;
|
|
use tracing::warn;
|
|
|
|
use crate::AppInfo;
|
|
use crate::ConnectorDirectoryCacheKey;
|
|
|
|
pub(crate) const CONNECTOR_DIRECTORY_DISK_CACHE_SCHEMA_VERSION: u8 = 1;
|
|
const CONNECTOR_DIRECTORY_DISK_CACHE_DIR: &str = "cache/codex_app_directory";
|
|
|
|
#[derive(Clone)]
|
|
pub struct ConnectorDirectoryCacheContext {
|
|
pub(crate) codex_home: PathBuf,
|
|
pub(crate) cache_key: ConnectorDirectoryCacheKey,
|
|
}
|
|
|
|
impl ConnectorDirectoryCacheContext {
|
|
pub fn new(codex_home: PathBuf, cache_key: ConnectorDirectoryCacheKey) -> Self {
|
|
Self {
|
|
codex_home,
|
|
cache_key,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn cache_path(&self) -> PathBuf {
|
|
let cache_key_json = serde_json::to_string(&self.cache_key).unwrap_or_default();
|
|
let cache_key_hash = sha1_hex(&cache_key_json);
|
|
self.codex_home
|
|
.join(CONNECTOR_DIRECTORY_DISK_CACHE_DIR)
|
|
.join(format!("{cache_key_hash}.json"))
|
|
}
|
|
}
|
|
|
|
pub(crate) enum CachedConnectorDirectoryDiskLoad {
|
|
Hit { connectors: Vec<AppInfo> },
|
|
Missing,
|
|
Invalid,
|
|
}
|
|
|
|
pub(crate) fn load_cached_directory_connectors_from_disk(
|
|
cache_context: &ConnectorDirectoryCacheContext,
|
|
) -> CachedConnectorDirectoryDiskLoad {
|
|
let cache_path = cache_context.cache_path();
|
|
let bytes = match std::fs::read(&cache_path) {
|
|
Ok(bytes) => bytes,
|
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
|
return CachedConnectorDirectoryDiskLoad::Missing;
|
|
}
|
|
Err(err) => {
|
|
warn!(
|
|
cache_path = %cache_path.display(),
|
|
"failed to read connector directory disk cache: {err}"
|
|
);
|
|
return CachedConnectorDirectoryDiskLoad::Invalid;
|
|
}
|
|
};
|
|
let cache: ConnectorDirectoryDiskCache = match serde_json::from_slice(&bytes) {
|
|
Ok(cache) => cache,
|
|
Err(err) => {
|
|
warn!(
|
|
cache_path = %cache_path.display(),
|
|
"failed to parse connector directory disk cache: {err}"
|
|
);
|
|
let _ = std::fs::remove_file(cache_path);
|
|
return CachedConnectorDirectoryDiskLoad::Invalid;
|
|
}
|
|
};
|
|
if cache.schema_version != CONNECTOR_DIRECTORY_DISK_CACHE_SCHEMA_VERSION {
|
|
let _ = std::fs::remove_file(cache_path);
|
|
return CachedConnectorDirectoryDiskLoad::Invalid;
|
|
}
|
|
|
|
CachedConnectorDirectoryDiskLoad::Hit {
|
|
connectors: cache.connectors,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn write_cached_directory_connectors_to_disk(
|
|
cache_context: &ConnectorDirectoryCacheContext,
|
|
connectors: &[AppInfo],
|
|
) {
|
|
let cache_path = cache_context.cache_path();
|
|
if let Some(parent) = cache_path.parent()
|
|
&& std::fs::create_dir_all(parent).is_err()
|
|
{
|
|
return;
|
|
}
|
|
let Ok(bytes) = serde_json::to_vec_pretty(&ConnectorDirectoryDiskCache {
|
|
schema_version: CONNECTOR_DIRECTORY_DISK_CACHE_SCHEMA_VERSION,
|
|
connectors: connectors.to_vec(),
|
|
}) else {
|
|
return;
|
|
};
|
|
let _ = std::fs::write(cache_path, bytes);
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
struct ConnectorDirectoryDiskCache {
|
|
schema_version: u8,
|
|
connectors: Vec<AppInfo>,
|
|
}
|
|
|
|
fn sha1_hex(value: &str) -> String {
|
|
let mut hasher = Sha1::new();
|
|
hasher.update(value.as_bytes());
|
|
let sha1 = hasher.finalize();
|
|
format!("{sha1:x}")
|
|
}
|