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};
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35pub struct DependencySpec {
36 pub alias: String,
37 pub name: String,
38 pub actr_type: Option<ActrType>,
39 pub fingerprint: Option<String>,
40}
41
42#[derive(Debug, Clone)]
44pub struct ResolvedDependency {
45 pub spec: DependencySpec,
46 pub fingerprint: String,
47 pub proto_files: Vec<ProtoFile>,
48}
49
50#[derive(Debug, Clone)]
52pub struct ProtoFile {
53 pub name: String,
54 pub path: PathBuf,
55 pub content: String,
56 pub services: Vec<ServiceDefinition>,
57}
58
59#[derive(Debug, Clone)]
61pub struct ServiceDefinition {
62 pub name: String,
63 pub methods: Vec<MethodDefinition>,
64}
65
66#[derive(Debug, Clone)]
68pub struct MethodDefinition {
69 pub name: String,
70 pub input_type: String,
71 pub output_type: String,
72}
73
74#[derive(Debug, Clone)]
76pub struct ServiceInfo {
77 pub name: String,
79 pub tags: Vec<String>,
80 pub fingerprint: String,
81 pub actr_type: ActrType,
82 pub published_at: Option<i64>,
83 pub description: Option<String>,
84 pub methods: Vec<MethodDefinition>,
85}
86
87#[derive(Debug, Clone)]
89pub struct ServiceDetails {
90 pub info: ServiceInfo,
91 pub proto_files: Vec<ProtoFile>,
92 pub dependencies: Vec<String>,
93}
94
95#[derive(Debug, Clone, PartialEq)]
97pub struct Fingerprint {
98 pub algorithm: String,
99 pub value: String,
100}
101
102#[derive(Debug, Clone)]
104pub struct ValidationReport {
105 pub is_valid: bool,
106 pub config_validation: ConfigValidation,
107 pub dependency_validation: Vec<DependencyValidation>,
108 pub network_validation: Vec<NetworkValidation>,
109 pub fingerprint_validation: Vec<FingerprintValidation>,
110 pub conflicts: Vec<ConflictReport>,
111}
112
113#[derive(Debug, Clone)]
114pub struct ConfigValidation {
115 pub is_valid: bool,
116 pub errors: Vec<String>,
117 pub warnings: Vec<String>,
118}
119
120#[derive(Debug, Clone)]
121pub struct DependencyValidation {
122 pub dependency: String,
123 pub is_available: bool,
124 pub error: Option<String>,
125}
126
127#[derive(Debug, Clone)]
128pub struct NetworkValidation {
129 pub is_reachable: bool,
130 pub health: HealthStatus,
131 pub latency_ms: Option<u64>,
132 pub error: Option<String>,
133}
134
135#[derive(Debug, Clone)]
136pub struct FingerprintValidation {
137 pub dependency: String,
138 pub expected: Fingerprint,
139 pub actual: Option<Fingerprint>,
140 pub is_valid: bool,
141 pub error: Option<String>,
142}
143
144#[derive(Debug, Clone)]
145pub struct ConflictReport {
146 pub dependency_a: String,
147 pub dependency_b: String,
148 pub conflict_type: ConflictType,
149 pub description: String,
150}
151
152#[derive(Debug, Clone)]
153pub enum ConflictType {
154 VersionConflict,
155 FingerprintMismatch,
156 CircularDependency,
157}
158
159impl ValidationReport {
160 pub fn is_success(&self) -> bool {
161 self.is_valid
162 && self.config_validation.is_valid
163 && self.dependency_validation.iter().all(|d| d.is_available)
164 && self.network_validation.iter().all(|n| n.is_reachable)
165 && self.fingerprint_validation.iter().all(|f| f.is_valid)
166 && self.conflicts.is_empty()
167 }
168}
169
170#[async_trait]
176pub trait ConfigManager: Send + Sync {
177 async fn load_config(&self, path: &Path) -> Result<Config>;
179
180 async fn save_config(&self, config: &Config, path: &Path) -> Result<()>;
182
183 async fn update_dependency(&self, spec: &DependencySpec) -> Result<()>;
185
186 async fn validate_config(&self) -> Result<ConfigValidation>;
188
189 fn get_project_root(&self) -> &Path;
191
192 async fn backup_config(&self) -> Result<ConfigBackup>;
194
195 async fn restore_backup(&self, backup: ConfigBackup) -> Result<()>;
197
198 async fn remove_backup(&self, backup: ConfigBackup) -> Result<()>;
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct PackageConfig {
204 pub name: String,
205 pub version: String,
206 #[serde(rename = "type")]
207 pub package_type: Option<String>,
208}
209
210#[derive(Debug, Clone)]
212pub struct ConfigBackup {
213 pub original_path: PathBuf,
214 pub backup_path: PathBuf,
215 pub timestamp: std::time::SystemTime,
216}
217
218#[async_trait]
224pub trait DependencyResolver: Send + Sync {
225 async fn resolve_spec(&self, config: &Config) -> Result<Vec<DependencySpec>>;
227
228 async fn resolve_dependencies(
230 &self,
231 specs: &[DependencySpec],
232 service_details: &[ServiceDetails],
233 ) -> Result<Vec<ResolvedDependency>>;
234
235 async fn check_conflicts(&self, deps: &[ResolvedDependency]) -> Result<Vec<ConflictReport>>;
237
238 async fn build_dependency_graph(&self, deps: &[ResolvedDependency]) -> Result<DependencyGraph>;
240}
241
242#[derive(Debug, Clone)]
243pub struct DependencyGraph {
244 pub nodes: Vec<String>,
245 pub edges: Vec<(String, String)>,
246 pub has_cycles: bool,
247}
248
249#[async_trait]
255pub trait ServiceDiscovery: Send + Sync {
256 async fn discover_services(&self, filter: Option<&ServiceFilter>) -> Result<Vec<ServiceInfo>>;
258
259 async fn get_service_details(&self, name: &str) -> Result<ServiceDetails>;
261
262 async fn check_service_availability(&self, name: &str) -> Result<AvailabilityStatus>;
264
265 async fn get_service_proto(&self, name: &str) -> Result<Vec<ProtoFile>>;
267}
268
269#[derive(Debug, Clone)]
270pub struct ServiceFilter {
271 pub name_pattern: Option<String>,
272 pub version_range: Option<String>,
273 pub tags: Option<Vec<String>>,
274}
275
276#[derive(Debug, Clone)]
277pub struct AvailabilityStatus {
278 pub is_available: bool,
279 pub last_seen: Option<std::time::SystemTime>,
280 pub health: HealthStatus,
281}
282
283#[derive(Debug, Clone)]
284pub enum HealthStatus {
285 Healthy,
286 Degraded,
287 Unhealthy,
288 Unknown,
289}
290
291#[async_trait]
297pub trait NetworkValidator: Send + Sync {
298 async fn check_connectivity(&self, service_name: &str) -> Result<ConnectivityStatus>;
300
301 async fn verify_service_health(&self, service_name: &str) -> Result<HealthStatus>;
303
304 async fn test_latency(&self, service_name: &str) -> Result<LatencyInfo>;
306
307 async fn batch_check(&self, service_names: &[String]) -> Result<Vec<NetworkCheckResult>>;
309}
310
311#[derive(Debug, Clone)]
312pub struct ConnectivityStatus {
313 pub is_reachable: bool,
314 pub response_time_ms: Option<u64>,
315 pub error: Option<String>,
316}
317
318#[derive(Debug, Clone)]
319pub struct LatencyInfo {
320 pub min_ms: u64,
321 pub max_ms: u64,
322 pub avg_ms: u64,
323 pub samples: u32,
324}
325
326#[derive(Debug, Clone)]
327pub struct NetworkCheckResult {
328 pub connectivity: ConnectivityStatus,
329 pub health: HealthStatus,
330 pub latency: Option<LatencyInfo>,
331}
332
333#[async_trait]
339pub trait FingerprintValidator: Send + Sync {
340 async fn compute_service_fingerprint(&self, service: &ServiceInfo) -> Result<Fingerprint>;
342
343 async fn verify_fingerprint(
345 &self,
346 expected: &Fingerprint,
347 actual: &Fingerprint,
348 ) -> Result<bool>;
349
350 async fn compute_project_fingerprint(&self, project_path: &Path) -> Result<Fingerprint>;
352
353 async fn generate_lock_fingerprint(&self, deps: &[ResolvedDependency]) -> Result<Fingerprint>;
355}
356
357#[async_trait]
363pub trait ProtoProcessor: Send + Sync {
364 async fn discover_proto_files(&self, path: &Path) -> Result<Vec<ProtoFile>>;
366
367 async fn parse_proto_services(&self, files: &[ProtoFile]) -> Result<Vec<ServiceDefinition>>;
369
370 async fn generate_code(&self, input: &Path, output: &Path) -> Result<GenerationResult>;
372
373 async fn validate_proto_syntax(&self, files: &[ProtoFile]) -> Result<ValidationReport>;
375}
376
377#[derive(Debug, Clone)]
378pub struct GenerationResult {
379 pub generated_files: Vec<PathBuf>,
380 pub warnings: Vec<String>,
381 pub errors: Vec<String>,
382}
383
384#[async_trait]
390pub trait CacheManager: Send + Sync {
391 async fn get_cached_proto(&self, service_name: &str) -> Result<Option<CachedProto>>;
393
394 async fn cache_proto(&self, service_name: &str, proto: &[ProtoFile]) -> Result<()>;
396
397 async fn invalidate_cache(&self, service_name: &str) -> Result<()>;
399
400 async fn clear_cache(&self) -> Result<()>;
402
403 async fn get_cache_stats(&self) -> Result<CacheStats>;
405}
406
407#[derive(Debug, Clone)]
408pub struct CachedProto {
409 pub files: Vec<ProtoFile>,
410 pub fingerprint: Fingerprint,
411 pub cached_at: std::time::SystemTime,
412 pub expires_at: Option<std::time::SystemTime>,
413}
414
415#[derive(Debug, Clone)]
416pub struct CacheStats {
417 pub total_entries: usize,
418 pub total_size_bytes: u64,
419 pub hit_rate: f64,
420 pub miss_rate: f64,
421}
422
423#[async_trait]
429pub trait UserInterface: Send + Sync {
430 async fn prompt_input(&self, prompt: &str) -> Result<String>;
432
433 async fn confirm(&self, message: &str) -> Result<bool>;
435
436 async fn select_from_list(&self, items: &[String], prompt: &str) -> Result<usize>;
438
439 async fn display_service_table(
441 &self,
442 items: &[ServiceInfo],
443 headers: &[&str],
444 formatter: fn(&ServiceInfo) -> Vec<String>,
445 );
446
447 async fn show_progress(&self, message: &str) -> Result<Box<dyn ProgressBar>>;
449}
450
451pub trait ProgressBar: Send + Sync {
453 fn update(&self, progress: f64);
454 fn set_message(&self, message: &str);
455 fn finish(&self);
456}
457
458impl From<TypeEntry> for ServiceInfo {
459 fn from(entry: TypeEntry) -> Self {
460 let name = entry.name.clone();
461 let tags = entry.tags.clone();
462 let actr_type = entry.actr_type.clone();
463
464 Self {
465 name,
466 actr_type,
467 tags,
468 published_at: entry.published_at,
469 fingerprint: entry.service_fingerprint,
470 description: entry.description,
471 methods: Vec::new(),
472 }
473 }
474}