1pub mod cache_manager;
6pub mod config_manager;
7pub mod dependency_resolver;
8pub mod fingerprint_validator;
9pub mod network_validator;
10pub mod proto_processor;
11pub mod service_discovery;
12pub mod user_interface;
13use actr_protocol::{ActrType, discovery_response::TypeEntry};
14pub use cache_manager::DefaultCacheManager;
15pub use config_manager::TomlConfigManager;
16pub use dependency_resolver::DefaultDependencyResolver;
17pub use fingerprint_validator::DefaultFingerprintValidator;
18pub use network_validator::DefaultNetworkValidator;
19pub use proto_processor::DefaultProtoProcessor;
20pub use service_discovery::NetworkServiceDiscovery;
21pub use user_interface::ConsoleUI;
22
23use actr_config::Config;
24use anyhow::Result;
25use async_trait::async_trait;
26use serde::{Deserialize, Serialize};
27use std::path::{Path, PathBuf};
28use std::time::Duration;
29
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
36pub struct DependencySpec {
37 pub alias: String,
38 pub name: String,
39 pub actr_type: Option<ActrType>,
40 pub fingerprint: Option<String>,
41}
42
43#[derive(Debug, Clone)]
45pub struct ResolvedDependency {
46 pub spec: DependencySpec,
47 pub fingerprint: String,
48 pub proto_files: Vec<ProtoFile>,
49}
50
51#[derive(Debug, Clone)]
53pub struct ProtoFile {
54 pub name: String,
55 pub path: PathBuf,
56 pub content: String,
57 pub services: Vec<ServiceDefinition>,
58}
59
60#[derive(Debug, Clone)]
62pub struct ServiceDefinition {
63 pub name: String,
64 pub methods: Vec<MethodDefinition>,
65}
66
67#[derive(Debug, Clone)]
69pub struct MethodDefinition {
70 pub name: String,
71 pub input_type: String,
72 pub output_type: String,
73}
74
75#[derive(Debug, Clone)]
77pub struct ServiceInfo {
78 pub name: String,
80 pub tags: Vec<String>,
81 pub fingerprint: String,
82 pub actr_type: ActrType,
83 pub published_at: Option<i64>,
84 pub description: Option<String>,
85 pub methods: Vec<MethodDefinition>,
86}
87
88#[derive(Debug, Clone)]
90pub struct ServiceDetails {
91 pub info: ServiceInfo,
92 pub proto_files: Vec<ProtoFile>,
93 pub dependencies: Vec<String>,
94}
95
96#[derive(Debug, Clone, PartialEq)]
98pub struct Fingerprint {
99 pub algorithm: String,
100 pub value: String,
101}
102
103#[derive(Debug, Clone)]
105pub struct ValidationReport {
106 pub is_valid: bool,
107 pub config_validation: ConfigValidation,
108 pub dependency_validation: Vec<DependencyValidation>,
109 pub network_validation: Vec<NetworkValidation>,
110 pub fingerprint_validation: Vec<FingerprintValidation>,
111 pub conflicts: Vec<ConflictReport>,
112}
113
114#[derive(Debug, Clone)]
115pub struct ConfigValidation {
116 pub is_valid: bool,
117 pub errors: Vec<String>,
118 pub warnings: Vec<String>,
119}
120
121#[derive(Debug, Clone)]
122pub struct DependencyValidation {
123 pub dependency: String,
124 pub is_available: bool,
125 pub error: Option<String>,
126}
127
128#[derive(Debug, Clone)]
129pub struct NetworkValidation {
130 pub is_reachable: bool,
131 pub health: HealthStatus,
132 pub latency_ms: Option<u64>,
133 pub error: Option<String>,
134 pub is_applicable: bool,
135}
136
137#[derive(Debug, Clone)]
138pub struct FingerprintValidation {
139 pub dependency: String,
140 pub expected: Fingerprint,
141 pub actual: Option<Fingerprint>,
142 pub is_valid: bool,
143 pub error: Option<String>,
144}
145
146#[derive(Debug, Clone)]
147pub struct ConflictReport {
148 pub dependency_a: String,
149 pub dependency_b: String,
150 pub conflict_type: ConflictType,
151 pub description: String,
152}
153
154#[derive(Debug, Clone)]
155pub enum ConflictType {
156 VersionConflict,
157 FingerprintMismatch,
158 CircularDependency,
159}
160
161impl ValidationReport {
162 pub fn is_success(&self) -> bool {
163 self.is_valid
164 && self.config_validation.is_valid
165 && self.dependency_validation.iter().all(|d| d.is_available)
166 && self
167 .network_validation
168 .iter()
169 .all(|n| !n.is_applicable || n.is_reachable)
170 && self.fingerprint_validation.iter().all(|f| f.is_valid)
171 && self.conflicts.is_empty()
172 }
173}
174
175#[async_trait]
181pub trait ConfigManager: Send + Sync {
182 async fn load_config(&self, path: &Path) -> Result<Config>;
184
185 async fn save_config(&self, config: &Config, path: &Path) -> Result<()>;
187
188 async fn update_dependency(&self, spec: &DependencySpec) -> Result<()>;
190
191 async fn validate_config(&self) -> Result<ConfigValidation>;
193
194 fn get_project_root(&self) -> &Path;
196
197 async fn backup_config(&self) -> Result<ConfigBackup>;
199
200 async fn restore_backup(&self, backup: ConfigBackup) -> Result<()>;
202
203 async fn remove_backup(&self, backup: ConfigBackup) -> Result<()>;
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct PackageConfig {
209 pub name: String,
210 pub version: String,
211 #[serde(rename = "type")]
212 pub package_type: Option<String>,
213}
214
215#[derive(Debug, Clone)]
217pub struct ConfigBackup {
218 pub original_path: PathBuf,
219 pub backup_path: PathBuf,
220 pub timestamp: std::time::SystemTime,
221}
222
223#[async_trait]
229pub trait DependencyResolver: Send + Sync {
230 async fn resolve_spec(&self, config: &Config) -> Result<Vec<DependencySpec>>;
232
233 async fn resolve_dependencies(
235 &self,
236 specs: &[DependencySpec],
237 service_details: &[ServiceDetails],
238 ) -> Result<Vec<ResolvedDependency>>;
239
240 async fn check_conflicts(&self, deps: &[ResolvedDependency]) -> Result<Vec<ConflictReport>>;
242
243 async fn build_dependency_graph(&self, deps: &[ResolvedDependency]) -> Result<DependencyGraph>;
245}
246
247#[derive(Debug, Clone)]
248pub struct DependencyGraph {
249 pub nodes: Vec<String>,
250 pub edges: Vec<(String, String)>,
251 pub has_cycles: bool,
252}
253
254#[async_trait]
260pub trait ServiceDiscovery: Send + Sync {
261 async fn discover_services(&self, filter: Option<&ServiceFilter>) -> Result<Vec<ServiceInfo>>;
263
264 async fn get_service_details(&self, name: &str) -> Result<ServiceDetails>;
266
267 async fn check_service_availability(&self, name: &str) -> Result<AvailabilityStatus>;
269
270 async fn get_service_proto(&self, name: &str) -> Result<Vec<ProtoFile>>;
272}
273
274#[derive(Debug, Clone)]
275pub struct ServiceFilter {
276 pub name_pattern: Option<String>,
277 pub version_range: Option<String>,
278 pub tags: Option<Vec<String>>,
279}
280
281#[derive(Debug, Clone)]
282pub struct AvailabilityStatus {
283 pub is_available: bool,
284 pub last_seen: Option<std::time::SystemTime>,
285 pub health: HealthStatus,
286}
287
288#[derive(Debug, Clone)]
289pub enum HealthStatus {
290 Healthy,
291 Degraded,
292 Unhealthy,
293 Unknown,
294}
295
296#[async_trait]
302pub trait NetworkValidator: Send + Sync {
303 async fn check_connectivity(
305 &self,
306 service_name: &str,
307 options: &NetworkCheckOptions,
308 ) -> Result<ConnectivityStatus>;
309
310 async fn verify_service_health(
312 &self,
313 service_name: &str,
314 options: &NetworkCheckOptions,
315 ) -> Result<HealthStatus>;
316
317 async fn test_latency(
319 &self,
320 service_name: &str,
321 options: &NetworkCheckOptions,
322 ) -> Result<LatencyInfo>;
323
324 async fn batch_check(
326 &self,
327 service_names: &[String],
328 options: &NetworkCheckOptions,
329 ) -> Result<Vec<NetworkCheckResult>>;
330}
331
332#[derive(Debug, Clone)]
333pub struct ConnectivityStatus {
334 pub is_reachable: bool,
335 pub response_time_ms: Option<u64>,
336 pub error: Option<String>,
337}
338
339#[derive(Debug, Clone)]
340pub struct LatencyInfo {
341 pub min_ms: u64,
342 pub max_ms: u64,
343 pub avg_ms: u64,
344 pub samples: u32,
345}
346
347#[derive(Debug, Clone)]
348pub struct NetworkCheckResult {
349 pub connectivity: ConnectivityStatus,
350 pub health: HealthStatus,
351 pub latency: Option<LatencyInfo>,
352}
353
354#[derive(Debug, Clone)]
356pub struct NetworkCheckOptions {
357 pub timeout: Duration,
358}
359
360impl NetworkCheckOptions {
361 pub fn with_timeout(timeout: Duration) -> Self {
362 Self { timeout }
363 }
364
365 pub fn with_timeout_secs(timeout_secs: u64) -> Self {
366 Self::with_timeout(Duration::from_secs(timeout_secs))
367 }
368}
369
370impl Default for NetworkCheckOptions {
371 fn default() -> Self {
372 Self {
373 timeout: Duration::from_secs(5),
374 }
375 }
376}
377
378#[async_trait]
384pub trait FingerprintValidator: Send + Sync {
385 async fn compute_service_fingerprint(&self, service: &ServiceInfo) -> Result<Fingerprint>;
387
388 async fn verify_fingerprint(
390 &self,
391 expected: &Fingerprint,
392 actual: &Fingerprint,
393 ) -> Result<bool>;
394
395 async fn compute_project_fingerprint(&self, project_path: &Path) -> Result<Fingerprint>;
397
398 async fn generate_lock_fingerprint(&self, deps: &[ResolvedDependency]) -> Result<Fingerprint>;
400}
401
402#[async_trait]
408pub trait ProtoProcessor: Send + Sync {
409 async fn discover_proto_files(&self, path: &Path) -> Result<Vec<ProtoFile>>;
411
412 async fn parse_proto_services(&self, files: &[ProtoFile]) -> Result<Vec<ServiceDefinition>>;
414
415 async fn generate_code(&self, input: &Path, output: &Path) -> Result<GenerationResult>;
417
418 async fn validate_proto_syntax(&self, files: &[ProtoFile]) -> Result<ValidationReport>;
420}
421
422#[derive(Debug, Clone)]
423pub struct GenerationResult {
424 pub generated_files: Vec<PathBuf>,
425 pub warnings: Vec<String>,
426 pub errors: Vec<String>,
427}
428
429#[async_trait]
435pub trait CacheManager: Send + Sync {
436 async fn get_cached_proto(&self, service_name: &str) -> Result<Option<CachedProto>>;
438
439 async fn cache_proto(&self, service_name: &str, proto: &[ProtoFile]) -> Result<()>;
441
442 async fn invalidate_cache(&self, service_name: &str) -> Result<()>;
444
445 async fn clear_cache(&self) -> Result<()>;
447
448 async fn get_cache_stats(&self) -> Result<CacheStats>;
450}
451
452#[derive(Debug, Clone)]
453pub struct CachedProto {
454 pub files: Vec<ProtoFile>,
455 pub fingerprint: Fingerprint,
456 pub cached_at: std::time::SystemTime,
457 pub expires_at: Option<std::time::SystemTime>,
458}
459
460#[derive(Debug, Clone)]
461pub struct CacheStats {
462 pub total_entries: usize,
463 pub total_size_bytes: u64,
464 pub hit_rate: f64,
465 pub miss_rate: f64,
466}
467
468#[async_trait]
474pub trait UserInterface: Send + Sync {
475 async fn prompt_input(&self, prompt: &str) -> Result<String>;
477
478 async fn confirm(&self, message: &str) -> Result<bool>;
480
481 async fn select_from_list(&self, items: &[String], prompt: &str) -> Result<usize>;
483
484 async fn display_service_table(
486 &self,
487 items: &[ServiceInfo],
488 headers: &[&str],
489 formatter: fn(&ServiceInfo) -> Vec<String>,
490 );
491
492 async fn show_progress(&self, message: &str) -> Result<Box<dyn ProgressBar>>;
494}
495
496pub trait ProgressBar: Send + Sync {
498 fn update(&self, progress: f64);
499 fn set_message(&self, message: &str);
500 fn finish(&self);
501}
502
503impl From<TypeEntry> for ServiceInfo {
504 fn from(entry: TypeEntry) -> Self {
505 let name = entry.name.clone();
506 let tags = entry.tags.clone();
507 let actr_type = entry.actr_type.clone();
508
509 Self {
510 name,
511 actr_type,
512 tags,
513 published_at: entry.published_at,
514 fingerprint: entry.service_fingerprint,
515 description: entry.description,
516 methods: Vec::new(),
517 }
518 }
519}