nap_core/provider/
remote.rs1use anyhow::{Context, Result};
8use tracing::info;
9
10use super::{Provider, ProviderStatus, ProviderType};
11
12pub struct RemoteProvider {
14 url_base: String,
15 workspace_id: String,
16 auth_token: Option<String>,
17}
18
19impl RemoteProvider {
20 pub fn new(url_base: &str, workspace_id: &str) -> Self {
22 Self {
23 url_base: url_base.to_string(),
24 workspace_id: workspace_id.to_string(),
25 auth_token: std::env::var("NAP_REMOTE_AUTH_TOKEN").ok(),
26 }
27 }
28
29 pub fn new_with_default_workspace(url_base: &str) -> Self {
31 Self {
32 url_base: url_base.to_string(),
33 workspace_id: super::get_default_workspace_id(),
34 auth_token: std::env::var("NAP_REMOTE_AUTH_TOKEN").ok(),
35 }
36 }
37
38 pub fn with_auth_token(mut self, token: &str) -> Self {
40 self.auth_token = Some(token.to_string());
41 self
42 }
43
44 fn http_health_url(&self) -> Result<String> {
49 let (scheme, rest) = if self.url_base.starts_with("lore://") {
51 ("http", &self.url_base[7..]) } else if self.url_base.starts_with("lores://") {
53 ("https", &self.url_base[8..]) } else {
55 anyhow::bail!("Invalid Lore URL format: {}", self.url_base);
56 };
57
58 let host = if rest.contains(':') {
60 rest.split(':').next().unwrap()
62 } else {
63 rest
64 };
65
66 let http_port = 41339;
68
69 Ok(format!("{}://{}:{}/health_check", scheme, host, http_port))
70 }
71}
72
73#[async_trait::async_trait]
74impl Provider for RemoteProvider {
75 fn provider_type(&self) -> ProviderType {
76 ProviderType::Remote
77 }
78
79 fn name(&self) -> &str {
80 "Remote Lore Server"
81 }
82
83 async fn initialize(&self) -> Result<()> {
84 info!("Initializing Remote provider for {}", self.url_base);
85 info!("Remote provider initialized");
86 Ok(())
87 }
88
89 async fn ensure_ready(&self) -> Result<()> {
90 info!("Ensuring Remote provider is ready");
91
92 self.initialize().await?;
93
94 let health_url = self.http_health_url()?;
96 let response = reqwest::get(&health_url)
97 .await
98 .context("Failed to connect to remote Lore server")?;
99
100 if !response.status().is_success() {
101 anyhow::bail!(
102 "Remote Lore server health check failed: {}",
103 response.status()
104 );
105 }
106
107 info!("Remote provider is ready");
108 Ok(())
109 }
110
111 fn lore_url_base(&self) -> Result<String> {
112 Ok(self.url_base.clone())
113 }
114
115 fn workspace_id(&self) -> &str {
116 &self.workspace_id
117 }
118
119 async fn health_check(&self) -> Result<bool> {
120 let health_url = self.http_health_url()?;
121 match reqwest::get(&health_url).await {
122 Ok(response) => Ok(response.status().is_success()),
123 Err(_) => Ok(false),
124 }
125 }
126
127 async fn status(&self) -> Result<ProviderStatus> {
128 let healthy = self.health_check().await.unwrap_or(false);
129
130 let message = if healthy {
131 "Connected".to_string()
132 } else {
133 "Server unreachable".to_string()
134 };
135
136 Ok(ProviderStatus {
137 provider_type: self.provider_type(),
138 ready: healthy,
139 healthy,
140 url_base: self.url_base.clone(),
141 workspace_id: self.workspace_id.clone(),
142 message,
143 })
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_remote_provider_creation() {
153 let provider = RemoteProvider::new("lore://localhost:41337", "default");
154 assert_eq!(provider.provider_type(), ProviderType::Remote);
155 assert_eq!(provider.name(), "Remote Lore Server");
156 assert_eq!(provider.workspace_id(), "default");
157 assert_eq!(provider.url_base, "lore://localhost:41337");
158 }
159
160 #[test]
161 fn test_remote_provider_custom_auth() {
162 let provider = RemoteProvider::new("lore://localhost:41337", "default")
163 .with_auth_token("custom-token");
164 assert_eq!(provider.auth_token, Some("custom-token".to_string()));
165 }
166
167 #[test]
168 fn test_http_health_url() {
169 let provider = RemoteProvider::new("lore://localhost:41337", "default");
170 assert_eq!(
171 provider.http_health_url().unwrap(),
172 "http://localhost:41339/health_check"
173 );
174
175 let provider = RemoteProvider::new("lores://example.com:41337", "default");
176 assert_eq!(
177 provider.http_health_url().unwrap(),
178 "https://example.com:41339/health_check"
179 );
180
181 let provider = RemoteProvider::new("lore://192.168.0.27", "default");
183 assert_eq!(
184 provider.http_health_url().unwrap(),
185 "http://192.168.0.27:41339/health_check"
186 );
187 }
188}