1use anyhow::Result;
6use std::sync::Arc;
7
8use super::components::*;
9
10#[derive(Debug, Clone)]
16pub struct InstallResult {
17 pub installed_dependencies: Vec<ResolvedDependency>,
18 pub updated_config: bool,
19 pub updated_lock_file: bool,
20 pub cache_updates: usize,
21 pub warnings: Vec<String>,
22}
23
24impl InstallResult {
25 pub fn success() -> Self {
26 Self {
27 installed_dependencies: Vec::new(),
28 updated_config: false,
29 updated_lock_file: false,
30 cache_updates: 0,
31 warnings: Vec::new(),
32 }
33 }
34
35 pub fn summary(&self) -> String {
36 format!(
37 "安装了 {} 个依赖,更新了 {} 个缓存项",
38 self.installed_dependencies.len(),
39 self.cache_updates
40 )
41 }
42}
43
44#[derive(Debug, Clone)]
46pub struct InstallPlan {
47 pub dependencies_to_install: Vec<DependencySpec>,
48 pub resolved_dependencies: Vec<ResolvedDependency>,
49 pub estimated_cache_size: u64,
50 pub required_permissions: Vec<String>,
51}
52
53#[derive(Debug, Clone)]
55pub struct GenerationOptions {
56 pub input_path: std::path::PathBuf,
57 pub output_path: std::path::PathBuf,
58 pub clean_before_generate: bool,
59 pub generate_scaffold: bool,
60 pub format_code: bool,
61 pub run_checks: bool,
62}
63
64#[derive(Clone)]
70pub struct ValidationPipeline {
71 config_manager: Arc<dyn ConfigManager>,
72 dependency_resolver: Arc<dyn DependencyResolver>,
73 service_discovery: Arc<dyn ServiceDiscovery>,
74 network_validator: Arc<dyn NetworkValidator>,
75 fingerprint_validator: Arc<dyn FingerprintValidator>,
76}
77
78impl ValidationPipeline {
79 pub fn new(
80 config_manager: Arc<dyn ConfigManager>,
81 dependency_resolver: Arc<dyn DependencyResolver>,
82 service_discovery: Arc<dyn ServiceDiscovery>,
83 network_validator: Arc<dyn NetworkValidator>,
84 fingerprint_validator: Arc<dyn FingerprintValidator>,
85 ) -> Self {
86 Self {
87 config_manager,
88 dependency_resolver,
89 service_discovery,
90 network_validator,
91 fingerprint_validator,
92 }
93 }
94
95 pub async fn validate_project(&self) -> Result<ValidationReport> {
97 let config_validation = self.config_manager.validate_config().await?;
99
100 if !config_validation.is_valid {
102 return Ok(ValidationReport {
103 is_valid: false,
104 config_validation,
105 dependency_validation: vec![],
106 network_validation: vec![],
107 fingerprint_validation: vec![],
108 conflicts: vec![],
109 });
110 }
111
112 let config = self
114 .config_manager
115 .load_config(
116 self.config_manager
117 .get_project_root()
118 .join("Actr.toml")
119 .as_path(),
120 )
121 .await?;
122 let dependency_specs = self.extract_dependency_specs(&config)?;
123 let resolved_dependencies = self
124 .dependency_resolver
125 .resolve_dependencies(&dependency_specs)
126 .await?;
127
128 let conflicts = self
130 .dependency_resolver
131 .check_conflicts(&resolved_dependencies)
132 .await?;
133
134 let dependency_validation = self.validate_dependencies(&dependency_specs).await?;
136 let network_validation = self
137 .validate_network_connectivity(&resolved_dependencies)
138 .await?;
139 let fingerprint_validation = self.validate_fingerprints(&resolved_dependencies).await?;
140
141 let is_valid = config_validation.is_valid
142 && dependency_validation.iter().all(|d| d.is_available)
143 && network_validation.iter().all(|n| n.is_reachable)
144 && fingerprint_validation.iter().all(|f| f.is_valid)
145 && conflicts.is_empty();
146
147 Ok(ValidationReport {
148 is_valid,
149 config_validation,
150 dependency_validation,
151 network_validation,
152 fingerprint_validation,
153 conflicts,
154 })
155 }
156
157 pub async fn validate_dependencies(
159 &self,
160 specs: &[DependencySpec],
161 ) -> Result<Vec<DependencyValidation>> {
162 let mut results = Vec::new();
163
164 for spec in specs {
165 let validation = match self
166 .service_discovery
167 .check_service_availability(&spec.uri)
168 .await
169 {
170 Ok(status) => DependencyValidation {
171 dependency: spec.name.clone(),
172 is_available: status.is_available,
173 resolved_uri: Some(spec.uri.clone()),
174 error: None,
175 },
176 Err(e) => DependencyValidation {
177 dependency: spec.name.clone(),
178 is_available: false,
179 resolved_uri: None,
180 error: Some(e.to_string()),
181 },
182 };
183 results.push(validation);
184 }
185
186 Ok(results)
187 }
188
189 async fn validate_network_connectivity(
191 &self,
192 deps: &[ResolvedDependency],
193 ) -> Result<Vec<NetworkValidation>> {
194 let uris: Vec<String> = deps.iter().map(|d| d.uri.clone()).collect();
195 let network_results = self.network_validator.batch_check(&uris).await?;
196
197 Ok(network_results
198 .into_iter()
199 .map(|result| NetworkValidation {
200 uri: result.uri,
201 is_reachable: result.connectivity.is_reachable,
202 latency_ms: result.connectivity.response_time_ms,
203 error: result.connectivity.error,
204 })
205 .collect())
206 }
207
208 async fn validate_fingerprints(
210 &self,
211 deps: &[ResolvedDependency],
212 ) -> Result<Vec<FingerprintValidation>> {
213 let mut results = Vec::new();
214
215 for dep in deps {
216 let expected = Fingerprint {
217 algorithm: "sha256".to_string(),
218 value: dep.fingerprint.clone(),
219 };
220
221 let service_info = match self.service_discovery.get_service_details(&dep.uri).await {
223 Ok(details) => details.info,
224 Err(e) => {
225 results.push(FingerprintValidation {
226 dependency: dep.spec.name.clone(),
227 expected,
228 actual: None,
229 is_valid: false,
230 error: Some(e.to_string()),
231 });
232 continue;
233 }
234 };
235
236 match self
237 .fingerprint_validator
238 .compute_service_fingerprint(&service_info)
239 .await
240 {
241 Ok(actual) => {
242 let is_valid = self
243 .fingerprint_validator
244 .verify_fingerprint(&expected, &actual)
245 .await
246 .unwrap_or(false);
247 results.push(FingerprintValidation {
248 dependency: dep.spec.name.clone(),
249 expected,
250 actual: Some(actual),
251 is_valid,
252 error: None,
253 });
254 }
255 Err(e) => {
256 results.push(FingerprintValidation {
257 dependency: dep.spec.name.clone(),
258 expected,
259 actual: None,
260 is_valid: false,
261 error: Some(e.to_string()),
262 });
263 }
264 }
265 }
266
267 Ok(results)
268 }
269
270 fn extract_dependency_specs(&self, config: &ActrConfig) -> Result<Vec<DependencySpec>> {
272 let mut specs = Vec::new();
273
274 if let Some(dependencies) = &config.dependencies {
275 for (name, dep_config) in dependencies {
276 let spec = match dep_config {
277 DependencyConfig::Simple(uri) => DependencySpec {
278 name: name.clone(),
279 uri: uri.clone(),
280 version: None,
281 fingerprint: None,
282 },
283 DependencyConfig::Complex {
284 uri,
285 version,
286 fingerprint,
287 } => DependencySpec {
288 name: name.clone(),
289 uri: uri.clone(),
290 version: version.clone(),
291 fingerprint: fingerprint.clone(),
292 },
293 };
294 specs.push(spec);
295 }
296 }
297
298 Ok(specs)
299 }
300}
301
302pub struct InstallPipeline {
308 validation_pipeline: ValidationPipeline,
309 config_manager: Arc<dyn ConfigManager>,
310 cache_manager: Arc<dyn CacheManager>,
311 #[allow(dead_code)]
312 proto_processor: Arc<dyn ProtoProcessor>,
313}
314
315impl InstallPipeline {
316 pub fn new(
317 validation_pipeline: ValidationPipeline,
318 config_manager: Arc<dyn ConfigManager>,
319 cache_manager: Arc<dyn CacheManager>,
320 proto_processor: Arc<dyn ProtoProcessor>,
321 ) -> Self {
322 Self {
323 validation_pipeline,
324 config_manager,
325 cache_manager,
326 proto_processor,
327 }
328 }
329
330 pub async fn install_dependencies(&self, specs: &[DependencySpec]) -> Result<InstallResult> {
332 let validation_report = self
334 .validation_pipeline
335 .validate_dependencies(specs)
336 .await?;
337
338 let failed_validations: Vec<_> = validation_report
340 .iter()
341 .filter(|v| !v.is_available)
342 .collect();
343
344 if !failed_validations.is_empty() {
345 return Err(anyhow::anyhow!(
346 "依赖验证失败: {}",
347 failed_validations
348 .iter()
349 .map(|v| format!(
350 "{}: {}",
351 v.dependency,
352 v.error.as_deref().unwrap_or("unknown error")
353 ))
354 .collect::<Vec<_>>()
355 .join(", ")
356 ));
357 }
358
359 let backup = self.config_manager.backup_config().await?;
361
362 match self.execute_atomic_install(specs).await {
363 Ok(result) => {
364 self.config_manager.remove_backup(backup).await?;
366 Ok(result)
367 }
368 Err(e) => {
369 self.config_manager.restore_backup(backup).await?;
371 Err(e)
372 }
373 }
374 }
375
376 async fn execute_atomic_install(&self, specs: &[DependencySpec]) -> Result<InstallResult> {
378 let mut result = InstallResult::success();
379
380 for spec in specs {
381 self.config_manager.update_dependency(spec).await?;
383 result.updated_config = true;
384
385 let service_details = self
387 .validation_pipeline
388 .service_discovery
389 .get_service_details(&spec.uri)
390 .await?;
391
392 self.cache_manager
393 .cache_proto(&spec.uri, &service_details.proto_files)
394 .await?;
395 result.cache_updates += 1;
396
397 let resolved_dep = ResolvedDependency {
399 spec: spec.clone(),
400 uri: spec.uri.clone(),
401 resolved_version: service_details.info.version,
402 fingerprint: service_details.info.fingerprint,
403 proto_files: service_details.proto_files,
404 };
405 result.installed_dependencies.push(resolved_dep);
406 }
407
408 self.update_lock_file(&result.installed_dependencies)
410 .await?;
411 result.updated_lock_file = true;
412
413 Ok(result)
414 }
415
416 async fn update_lock_file(&self, dependencies: &[ResolvedDependency]) -> Result<()> {
418 println!("更新锁文件: {} 个依赖", dependencies.len());
421 Ok(())
422 }
423}
424
425pub struct GenerationPipeline {
431 #[allow(dead_code)]
432 config_manager: Arc<dyn ConfigManager>,
433 proto_processor: Arc<dyn ProtoProcessor>,
434 #[allow(dead_code)]
435 cache_manager: Arc<dyn CacheManager>,
436}
437
438impl GenerationPipeline {
439 pub fn new(
440 config_manager: Arc<dyn ConfigManager>,
441 proto_processor: Arc<dyn ProtoProcessor>,
442 cache_manager: Arc<dyn CacheManager>,
443 ) -> Self {
444 Self {
445 config_manager,
446 proto_processor,
447 cache_manager,
448 }
449 }
450
451 pub async fn generate_code(&self, options: &GenerationOptions) -> Result<GenerationResult> {
453 if options.clean_before_generate {
455 self.clean_output_directory(&options.output_path).await?;
456 }
457
458 let local_protos = self
460 .proto_processor
461 .discover_proto_files(&options.input_path)
462 .await?;
463
464 let dependency_protos = self.load_dependency_protos().await?;
466
467 let all_protos = [local_protos, dependency_protos].concat();
469 let validation = self
470 .proto_processor
471 .validate_proto_syntax(&all_protos)
472 .await?;
473
474 if !validation.is_valid {
475 return Err(anyhow::anyhow!("Proto文件语法验证失败"));
476 }
477
478 let mut generation_result = self
480 .proto_processor
481 .generate_code(&options.input_path, &options.output_path)
482 .await?;
483
484 if options.format_code {
486 self.format_generated_code(&generation_result.generated_files)
487 .await?;
488 }
489
490 if options.run_checks {
491 let check_result = self
492 .run_code_checks(&generation_result.generated_files)
493 .await?;
494 generation_result.warnings.extend(check_result.warnings);
495 generation_result.errors.extend(check_result.errors);
496 }
497
498 Ok(generation_result)
499 }
500
501 async fn clean_output_directory(&self, output_path: &std::path::Path) -> Result<()> {
503 if output_path.exists() {
504 std::fs::remove_dir_all(output_path)?;
505 }
506 std::fs::create_dir_all(output_path)?;
507 Ok(())
508 }
509
510 async fn load_dependency_protos(&self) -> Result<Vec<ProtoFile>> {
512 Ok(Vec::new())
514 }
515
516 async fn format_generated_code(&self, files: &[std::path::PathBuf]) -> Result<()> {
518 for file in files {
519 if file.extension().and_then(|s| s.to_str()) == Some("rs") {
520 let output = std::process::Command::new("rustfmt").arg(file).output()?;
522
523 if !output.status.success() {
524 eprintln!("rustfmt 警告: {}", String::from_utf8_lossy(&output.stderr));
525 }
526 }
527 }
528 Ok(())
529 }
530
531 async fn run_code_checks(&self, files: &[std::path::PathBuf]) -> Result<GenerationResult> {
533 Ok(GenerationResult {
535 generated_files: files.to_vec(),
536 warnings: vec![],
537 errors: vec![],
538 })
539 }
540}