gglib_core/ports/model_registrar.rs
1//! Model registrar port definition.
2//!
3//! This port defines the interface for registering downloaded models
4//! in the database. It breaks the circular dependency between download
5//! and core services by allowing the download crate to depend on a trait
6//! rather than concrete `AppCore`.
7
8use async_trait::async_trait;
9use std::path::Path;
10
11use super::RepositoryError;
12use super::download::ResolvedFile;
13use crate::domain::Model;
14use crate::download::Quantization;
15
16/// Information about a completed download for model registration.
17///
18/// This is a pure data transfer object containing all information
19/// needed to register a model after download completes.
20#[derive(Debug, Clone)]
21pub struct CompletedDownload {
22 /// Path to the primary downloaded file (first shard for sharded models).
23 pub primary_path: std::path::PathBuf,
24 /// All downloaded file paths (multiple for sharded models).
25 pub all_paths: Vec<std::path::PathBuf>,
26 /// The resolved quantization.
27 pub quantization: Quantization,
28 /// Repository ID (e.g., "unsloth/Llama-3-GGUF").
29 pub repo_id: String,
30 /// Commit SHA at time of download.
31 pub commit_sha: String,
32 /// Whether this was a sharded download.
33 pub is_sharded: bool,
34 /// Ordered list of all file paths for sharded models (None for single-file models).
35 pub file_paths: Option<Vec<std::path::PathBuf>>,
36 /// `HuggingFace` tags for the model.
37 pub hf_tags: Vec<String>,
38 /// File entries with OIDs from `HuggingFace` (for `model_files` table).
39 pub hf_file_entries: Vec<ResolvedFile>,
40}
41
42impl CompletedDownload {
43 /// Get the primary file path for database registration.
44 ///
45 /// For sharded models, this returns the first shard path
46 /// (required by llama-server for loading split models).
47 pub fn db_path(&self) -> &Path {
48 &self.primary_path
49 }
50}
51
52/// Port for registering downloaded models in the database.
53///
54/// This trait is implemented by core services and injected into
55/// the download manager, allowing model registration without
56/// coupling to `AppCore` directly.
57///
58/// # Usage
59///
60/// ```ignore
61/// let registrar: Arc<dyn ModelRegistrarPort> = /* ... */;
62/// let download = CompletedDownload { ... };
63/// let model = registrar.register_model(&download).await?;
64/// ```
65#[async_trait]
66pub trait ModelRegistrarPort: Send + Sync {
67 /// Register a downloaded model in the database.
68 ///
69 /// Parses GGUF metadata from the downloaded file and creates a database entry.
70 /// For sharded models, the primary (first shard) path is used for registration.
71 ///
72 /// # Arguments
73 ///
74 /// * `download` - The completed download information
75 ///
76 /// # Returns
77 ///
78 /// Returns the created `Model` on success.
79 async fn register_model(&self, download: &CompletedDownload) -> Result<Model, RepositoryError>;
80}