use crate::backend_config::BackendConfig;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use modelexpress_common::models::{ModelProvider, ModelStatus};
use std::sync::Arc;
pub mod kubernetes;
pub mod redis;
pub type RegistryResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
#[derive(Debug, Clone, PartialEq)]
pub struct ModelRecord {
pub model_name: String,
pub provider: ModelProvider,
pub status: ModelStatus,
pub created_at: DateTime<Utc>,
pub last_used_at: DateTime<Utc>,
pub message: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ClaimOutcome {
Claimed,
AlreadyExists(ModelStatus),
}
#[cfg_attr(test, mockall::automock)]
#[async_trait]
pub trait RegistryBackend: Send + Sync {
async fn connect(&self) -> RegistryResult<()>;
async fn get_status(&self, model_name: &str) -> RegistryResult<Option<ModelStatus>>;
async fn get_model_record(&self, model_name: &str) -> RegistryResult<Option<ModelRecord>>;
async fn set_status(
&self,
model_name: &str,
provider: ModelProvider,
status: ModelStatus,
message: Option<String>,
) -> RegistryResult<()>;
async fn touch_model(&self, model_name: &str) -> RegistryResult<()>;
async fn delete_model(&self, model_name: &str) -> RegistryResult<()>;
async fn get_models_by_last_used(&self, limit: Option<u32>)
-> RegistryResult<Vec<ModelRecord>>;
async fn get_status_counts(&self) -> RegistryResult<(u32, u32, u32)>;
async fn try_claim_for_download(
&self,
model_name: &str,
provider: ModelProvider,
) -> RegistryResult<ClaimOutcome>;
async fn try_reset_error_for_retry(
&self,
model_name: &str,
provider: ModelProvider,
) -> RegistryResult<bool>;
}
pub async fn create_registry_backend(
config: BackendConfig,
) -> RegistryResult<Arc<dyn RegistryBackend>> {
match config {
BackendConfig::Redis { url } => {
let backend = redis::RedisRegistryBackend::new(&url);
backend.connect().await?;
Ok(Arc::new(backend) as Arc<dyn RegistryBackend>)
}
BackendConfig::Kubernetes { namespace } => {
let backend = kubernetes::KubernetesRegistryBackend::new(&namespace).await?;
backend.connect().await?;
Ok(Arc::new(backend) as Arc<dyn RegistryBackend>)
}
}
}