//! Core extension registry service implementation use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; use anyhow::Result; use serde::{Deserialize, Serialize}; use sha2::Digest; use tokio::sync::RwLock; /// OCI image manifest #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ImageManifest { /// Schema version pub schema_version: u32, /// Media type pub media_type: String, /// Image config digest (sha256:...) pub config: ManifestConfig, /// Image layers pub layers: Vec, } /// Image configuration reference #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ManifestConfig { /// Digest (sha256:...) pub digest: String, /// Size in bytes pub size: u64, /// Media type pub media_type: String, } /// Image layer #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Layer { /// Layer digest (sha256:...) pub digest: String, /// Size in bytes pub size: u64, /// Media type pub media_type: String, } /// Push blob request #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PushBlobRequest { /// Blob content pub content: Vec, /// Content digest for validation pub digest: String, } /// Push blob response #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PushBlobResponse { /// Blob digest pub digest: String, /// Blob size in bytes pub size: u64, } /// Pull manifest response #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PullManifestResponse { /// Image manifest pub manifest: ImageManifest, /// Manifest digest pub digest: String, /// Content type pub content_type: String, } /// Extension metadata #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ExtensionMetadata { /// Extension name pub name: String, /// Extension version pub version: String, /// Extension description pub description: String, /// Supported platforms (e.g., ["linux/amd64", "linux/arm64"]) pub platforms: Vec, } /// Core extension registry service pub struct ExtensionRegistry { /// Server address addr: SocketAddr, /// Stored blobs (digest -> content) blobs: Arc>>>, /// Stored manifests (repo:tag -> manifest) manifests: Arc>>, /// Extension metadata registry extensions: Arc>>, } impl ExtensionRegistry { /// Create new extension registry pub fn new(addr: SocketAddr) -> Self { Self { addr, blobs: Arc::new(RwLock::new(HashMap::new())), manifests: Arc::new(RwLock::new(HashMap::new())), extensions: Arc::new(RwLock::new(HashMap::new())), } } /// Get service address pub fn addr(&self) -> SocketAddr { self.addr } /// Check if blob exists pub async fn blob_exists(&self, digest: &str) -> Result { let blobs = self.blobs.read().await; Ok(blobs.contains_key(digest)) } /// Push blob to registry pub async fn push_blob(&self, req: PushBlobRequest) -> Result { let size = req.content.len() as u64; let mut blobs = self.blobs.write().await; blobs.insert(req.digest.clone(), req.content); Ok(PushBlobResponse { digest: req.digest, size, }) } /// Pull blob from registry pub async fn pull_blob(&self, digest: &str) -> Result> { let blobs = self.blobs.read().await; blobs .get(digest) .cloned() .ok_or_else(|| anyhow::anyhow!("Blob not found: {}", digest)) } /// Check if manifest exists pub async fn manifest_exists(&self, reference: &str) -> Result { let manifests = self.manifests.read().await; Ok(manifests.contains_key(reference)) } /// Put image manifest pub async fn put_manifest(&self, reference: String, manifest: ImageManifest) -> Result { let digest = format!( "sha256:{}", hex::encode(sha2::Sha256::digest(&serde_json::to_vec(&manifest)?)) ); let mut manifests = self.manifests.write().await; manifests.insert(reference, manifest); Ok(digest) } /// Get image manifest pub async fn get_manifest(&self, reference: &str) -> Result { let manifests = self.manifests.read().await; let manifest = manifests .get(reference) .cloned() .ok_or_else(|| anyhow::anyhow!("Manifest not found: {}", reference))?; let digest = format!( "sha256:{}", hex::encode(sha2::Sha256::digest(&serde_json::to_vec(&manifest)?)) ); Ok(PullManifestResponse { manifest, digest, content_type: "application/vnd.docker.distribution.manifest.v2+json".to_string(), }) } /// Register extension pub async fn register_extension(&self, metadata: ExtensionMetadata) -> Result<()> { let mut extensions = self.extensions.write().await; extensions.insert(metadata.name.clone(), metadata); Ok(()) } /// Get extension metadata pub async fn get_extension(&self, name: &str) -> Result { let extensions = self.extensions.read().await; extensions .get(name) .cloned() .ok_or_else(|| anyhow::anyhow!("Extension not found: {}", name)) } /// List all extensions pub async fn list_extensions(&self) -> Result> { let extensions = self.extensions.read().await; Ok(extensions.values().cloned().collect()) } /// Health check endpoint pub async fn health_check(&self) -> Result<()> { Ok(()) } } impl Default for ExtensionRegistry { fn default() -> Self { Self::new("127.0.0.1:8084".parse().unwrap()) } }