claude_code_toolkit/providers/
registry.rs

1//! Provider registry following Service Locator Pattern
2
3use super::ProviderFactory;
4use crate::error::Result;
5use crate::traits::{
6  Credentials,
7  SecretManager,
8  SecretMapping,
9  SecretProvider,
10  SyncResult,
11  Target,
12};
13use async_trait::async_trait;
14use std::collections::HashMap;
15use tracing::{ error, info, warn };
16
17/// Service locator for secret providers
18pub struct ProviderRegistry {
19  factory: ProviderFactory,
20  providers: HashMap<String, Box<dyn SecretProvider>>,
21}
22
23impl ProviderRegistry {
24  pub fn new() -> Self {
25    Self {
26      factory: ProviderFactory::new(),
27      providers: HashMap::new(),
28    }
29  }
30
31  /// Initialize provider from configuration
32  pub async fn initialize_provider(
33    &mut self,
34    name: &str,
35    config: HashMap<String, String>
36  ) -> Result<()> {
37    let provider = self.factory.create(name, &config)?;
38
39    // Validate provider configuration
40    if !provider.is_configured().await? {
41      warn!("Provider {} is not properly configured", name);
42      return Err(
43        crate::error::ClaudeCodeError::Generic(format!("Provider {} is not configured", name))
44      );
45    }
46
47    info!("Initialized provider: {}", name);
48    self.providers.insert(name.to_string(), provider);
49    Ok(())
50  }
51
52  /// Get targets for all providers
53  pub async fn get_all_targets(&self) -> Result<HashMap<String, Vec<Target>>> {
54    let mut all_targets = HashMap::new();
55
56    for (provider_name, provider) in &self.providers {
57      let mut provider_targets = Vec::new();
58
59      // Get organizations
60      if let Ok(orgs) = provider.list_targets("organization").await {
61        for org in orgs {
62          provider_targets.push(Target {
63            provider: provider_name.clone(),
64            target_type: "organization".to_string(),
65            name: org,
66            config: HashMap::new(),
67          });
68        }
69      }
70
71      // Get repositories
72      if let Ok(repos) = provider.list_targets("repository").await {
73        for repo in repos {
74          provider_targets.push(Target {
75            provider: provider_name.clone(),
76            target_type: "repository".to_string(),
77            name: repo,
78            config: HashMap::new(),
79          });
80        }
81      }
82
83      all_targets.insert(provider_name.clone(), provider_targets);
84    }
85
86    Ok(all_targets)
87  }
88}
89
90impl Default for ProviderRegistry {
91  fn default() -> Self {
92    Self::new()
93  }
94}
95
96#[async_trait]
97impl SecretManager for ProviderRegistry {
98  fn register_provider(&mut self, provider: Box<dyn SecretProvider>) {
99    let name = provider.provider_name().to_string();
100    info!("Registering provider: {}", name);
101    self.providers.insert(name, provider);
102  }
103
104  fn get_provider(&self, name: &str) -> Option<&dyn SecretProvider> {
105    self.providers.get(name).map(|p| p.as_ref())
106  }
107
108  async fn sync_credentials(
109    &self,
110    credentials: &Credentials,
111    mapping: &SecretMapping
112  ) -> Result<SyncResult> {
113    // Empty targets for backward compatibility
114    let targets = Vec::new();
115    self.sync_credentials_to_targets(credentials, mapping, &targets).await
116  }
117
118  async fn sync_credentials_to_targets(
119    &self,
120    credentials: &Credentials,
121    mapping: &SecretMapping,
122    targets: &[Target]
123  ) -> Result<SyncResult> {
124    let secrets = mapping.to_secrets(credentials);
125    let mut total_result = SyncResult {
126      succeeded: 0,
127      failed: 0,
128      errors: Vec::new(),
129    };
130
131    for (provider_name, provider) in &self.providers {
132      match provider.sync_secrets(&secrets, targets).await {
133        Ok(result) => {
134          total_result.succeeded += result.succeeded;
135          total_result.failed += result.failed;
136          total_result.errors.extend(result.errors);
137        }
138        Err(e) => {
139          error!("Provider {} sync failed: {}", provider_name, e);
140          total_result.failed += 1;
141          total_result.errors.push(format!("Provider {}: {}", provider_name, e));
142        }
143      }
144    }
145
146    info!("Sync completed: {} succeeded, {} failed", total_result.succeeded, total_result.failed);
147
148    Ok(total_result)
149  }
150
151  async fn validate_targets(&self) -> Result<HashMap<String, bool>> {
152    let mut all_results = HashMap::new();
153
154    for (provider_name, provider) in &self.providers {
155      // TODO: Get targets from configuration
156      let targets = Vec::new();
157
158      match provider.validate_access(&targets).await {
159        Ok(results) => {
160          for (target, valid) in results {
161            all_results.insert(format!("{}:{}", provider_name, target), valid);
162          }
163        }
164        Err(e) => {
165          warn!("Failed to validate targets for provider {}: {}", provider_name, e);
166        }
167      }
168    }
169
170    Ok(all_results)
171  }
172
173  fn list_providers(&self) -> Vec<&str> {
174    self.providers
175      .keys()
176      .map(|s| s.as_str())
177      .collect()
178  }
179}