holger-server-lib 0.6.5

Holger server library: config, wiring, gRPC service, Rust API
use std::sync::Arc;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use repository_file_rust::RustRepoFile as RustRepo;
use repository_znippy_rust::RustRepoZnippy;
use repository_znippy_maven::MavenRepoZnippy;
use repository_znippy_python::PipRepoZnippy;
use repository_znippy_npm::NpmRepoZnippy;
use repository_znippy_nuget::NugetRepoZnippy;
use repository_znippy_go::GoRepoZnippy;
use repository_znippy_gem::GemRepoZnippy;
use repository_znippy_deb::DebRepoZnippy;
use repository_znippy_rpm::RpmRepoZnippy;
use repository_znippy_helm::HelmRepoZnippy;
use repository_file_oci::OciRepoFile;
use repository_znippy_docker::DockerRepoZnippy;
use repository_znippy_conda::CondaRepoZnippy;
use repository_znippy_composer::ComposerRepoZnippy;
use repository_znippy_package::ZnippyRepoZnippy;
use traits::RepositoryBackendTrait;
use crate::{ExposedEndpoint, StorageEndpoint};

#[derive(Serialize, Deserialize)]
pub struct Repository {
    // Parsed from RON
    pub ron_name: String,
    pub ron_repo_type: String,        // rust/java/python/raw
    pub ron_upstreams: Vec<String>,   // empty means no upstreams
    pub ron_in: Option<RepositoryIO>,
    pub ron_out: Option<RepositoryIO>,

    /// Optional path to a znippy archive (.znippy file)
    #[serde(default)]
    pub ron_archive_path: Option<String>,

    /// Optional storage directory for file-backed (writable) repos.
    /// Defaults to /var/lib/holger/{ron_name} when omitted.
    #[serde(default)]
    pub ron_data_dir: Option<String>,

    /// Public base URL used in config.json `dl` for the disk-backed Rust repo.
    /// E.g. `https://holger.example.com`.  Defaults to `https://127.0.0.1:8443`
    /// when omitted.
    #[serde(default)]
    pub ron_base_url: Option<String>,

    // Wired in second pass
    #[serde(skip_serializing, skip_deserializing, default)]
    pub backend_repository: Option<Arc<dyn RepositoryBackendTrait>>,
    


    #[serde(skip_serializing, skip_deserializing, default)]
    pub wired_upstreams: Vec<*const Repository>, // or &Repository pinned after build
}
impl Repository {
    pub fn backend_from_config(&mut self) -> anyhow::Result<()> {
        // Build a znippy-backed repo that requires an archive path.
        macro_rules! znippy_backed {
            ($ty:ty, $label:expr) => {{
                if let Some(archive_path) = &self.ron_archive_path {
                    let repo = <$ty>::with_archive(
                        self.ron_name.clone(),
                        PathBuf::from(archive_path),
                    )?;
                    self.backend_repository = Some(Arc::new(repo));
                } else {
                    anyhow::bail!(concat!($label, " repository requires ron_archive_path to a znippy archive"));
                }
                Ok(())
            }};
        }

        match self.ron_repo_type.as_str() {
            "rust" => {
                if let Some(archive_path) = &self.ron_archive_path {
                    let base_url = self
                        .ron_base_url
                        .clone()
                        .unwrap_or_else(|| "https://127.0.0.1:8443".to_string());
                    let repo = RustRepoZnippy::with_archive_and_url(
                        self.ron_name.clone(),
                        PathBuf::from(archive_path),
                        base_url,
                    )?;
                    self.backend_repository = Some(Arc::new(repo));
                } else {
                    // Writable, disk-backed dev backend. Requires a storage dir.
                    let dir = self.ron_data_dir.clone().ok_or_else(|| {
                        anyhow::anyhow!(
                            "Rust file-backed repository requires ron_data_dir (storage directory)"
                        )
                    })?;
                    let base_url = self
                        .ron_base_url
                        .clone()
                        .unwrap_or_else(|| "https://127.0.0.1:8443".to_string());
                    let repo = RustRepo::new(self.ron_name.clone(), PathBuf::from(dir), base_url);
                    self.backend_repository = Some(Arc::new(repo));
                }
                Ok(())
            }
            "maven3" => znippy_backed!(MavenRepoZnippy, "Maven3"),
            "pip" => znippy_backed!(PipRepoZnippy, "Pip"),
            "npm" => znippy_backed!(NpmRepoZnippy, "Npm"),
            "nuget" => znippy_backed!(NugetRepoZnippy, "Nuget"),
            "go" => znippy_backed!(GoRepoZnippy, "Go"),
            "gem" => znippy_backed!(GemRepoZnippy, "Gem"),
            "deb" => znippy_backed!(DebRepoZnippy, "Deb"),
            "rpm" => znippy_backed!(RpmRepoZnippy, "Rpm"),
            "helm" => znippy_backed!(HelmRepoZnippy, "Helm"),
            "docker" => znippy_backed!(DockerRepoZnippy, "Docker"),
            // Writable OCI registry (Distribution Spec v2). Push target for the
            // modern Helm flow (`helm push oci://…`) and any OCI artifact; needs
            // no archive — it owns a disk-backed, content-addressed store.
            "oci" => {
                let dir = self
                    .ron_data_dir
                    .clone()
                    .unwrap_or_else(|| format!("/var/lib/holger/{}", self.ron_name));
                let repo = OciRepoFile::new(self.ron_name.clone(), PathBuf::from(dir))?;
                self.backend_repository = Some(Arc::new(repo));
                Ok(())
            }
            "conda" => znippy_backed!(CondaRepoZnippy, "Conda"),
            "composer" => znippy_backed!(ComposerRepoZnippy, "Composer"),
            "znippy" => znippy_backed!(ZnippyRepoZnippy, "Znippy"),
            other => anyhow::bail!("Unsupported repository type: {}", other),
        }
    }

}




#[derive(Serialize, Deserialize)]
pub struct RepositoryIO {
    pub ron_storage_endpoint: String,
    pub ron_exposed_endpoint: String,


    #[serde(skip_serializing, skip_deserializing, default = "std::ptr::null")]
    pub wired_storage: *const StorageEndpoint,
    #[serde(skip_serializing, skip_deserializing, default = "std::ptr::null")]
    pub wired_exposed: *const ExposedEndpoint,
}