Skip to main content

nap_core/provider/
local.rs

1// SPDX-FileCopyrightText: 2026 Digital Creations
2// SPDX-License-Identifier: MIT
3//! Local provider for Lore server
4//!
5//! Manages a local Lore daemon for repository operations.
6
7use anyhow::Result;
8use std::path::Path;
9use std::sync::Arc;
10use tracing::info;
11
12use super::{Provider, ProviderStatus, ProviderType};
13use crate::server::ServerManager;
14
15/// Local provider that manages a local Lore daemon
16pub struct LocalProvider {
17    server_manager: Arc<ServerManager>,
18    workspace_id: String,
19}
20
21impl LocalProvider {
22    /// Create a new local provider
23    pub fn new(nap_home: &Path) -> Self {
24        let server_manager = Arc::new(ServerManager::new(nap_home));
25        Self {
26            server_manager,
27            workspace_id: super::get_default_workspace_id(),
28        }
29    }
30
31    /// Set custom workspace ID
32    pub fn with_workspace_id(mut self, workspace_id: &str) -> Self {
33        self.workspace_id = workspace_id.to_string();
34        self
35    }
36}
37
38#[async_trait::async_trait]
39impl Provider for LocalProvider {
40    fn provider_type(&self) -> ProviderType {
41        ProviderType::Local
42    }
43
44    fn name(&self) -> &str {
45        "Local Lore Server"
46    }
47
48    async fn initialize(&self) -> Result<()> {
49        info!("Initializing Local provider");
50
51        // Ensure Lore is installed
52        self.server_manager.ensure_installed()?;
53
54        // Ensure Lore is configured
55        self.server_manager.ensure_configured()?;
56
57        info!("Local provider initialized");
58        Ok(())
59    }
60
61    async fn ensure_ready(&self) -> Result<()> {
62        info!("Ensuring Local provider is ready");
63
64        // Initialize if needed
65        self.initialize().await?;
66
67        // Ensure server is running
68        self.server_manager.ensure_running().await?;
69
70        info!("Local provider is ready");
71        Ok(())
72    }
73
74    fn lore_url_base(&self) -> Result<String> {
75        Ok("lore://localhost:41337".to_string())
76    }
77
78    fn workspace_id(&self) -> &str {
79        &self.workspace_id
80    }
81
82    async fn health_check(&self) -> Result<bool> {
83        self.server_manager.health_check().await
84    }
85
86    async fn status(&self) -> Result<ProviderStatus> {
87        let server_status = self.server_manager.status().await?;
88        let healthy = self.health_check().await.unwrap_or(false);
89
90        Ok(ProviderStatus {
91            provider_type: self.provider_type(),
92            ready: server_status.is_ready(),
93            healthy,
94            url_base: self.lore_url_base()?,
95            workspace_id: self.workspace_id.clone(),
96            message: server_status.status_message(),
97        })
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104    use tempfile::TempDir;
105
106    #[test]
107    fn test_local_provider_creation() {
108        let temp_dir = TempDir::new().unwrap();
109        let provider = LocalProvider::new(temp_dir.path());
110        assert_eq!(provider.provider_type(), ProviderType::Local);
111        assert_eq!(provider.name(), "Local Lore Server");
112        assert_eq!(provider.workspace_id(), "default");
113    }
114
115    #[test]
116    fn test_local_provider_custom_workspace() {
117        let temp_dir = TempDir::new().unwrap();
118        let provider = LocalProvider::new(temp_dir.path()).with_workspace_id("custom-workspace");
119        assert_eq!(provider.workspace_id(), "custom-workspace");
120    }
121}