hank9999 commited on
Commit
ae610e9
·
1 Parent(s): 7cd244e

feat: 支持多凭据格式回写功能

Browse files
src/kiro/model/credentials.rs CHANGED
@@ -102,6 +102,11 @@ impl CredentialsConfig {
102
  CredentialsConfig::Multiple(creds) => creds.is_empty(),
103
  }
104
  }
 
 
 
 
 
105
  }
106
 
107
  impl KiroCredentials {
 
102
  CredentialsConfig::Multiple(creds) => creds.is_empty(),
103
  }
104
  }
105
+
106
+ /// 判断是否为多凭据格式(数组格式)
107
+ pub fn is_multiple(&self) -> bool {
108
+ matches!(self, CredentialsConfig::Multiple(_))
109
+ }
110
  }
111
 
112
  impl KiroCredentials {
src/kiro/provider.rs CHANGED
@@ -268,7 +268,7 @@ mod tests {
268
  use crate::model::config::Config;
269
 
270
  fn create_test_provider(config: Config, credentials: KiroCredentials) -> KiroProvider {
271
- let tm = MultiTokenManager::new(config, vec![credentials], None).unwrap();
272
  KiroProvider::new(Arc::new(tm))
273
  }
274
 
 
268
  use crate::model::config::Config;
269
 
270
  fn create_test_provider(config: Config, credentials: KiroCredentials) -> KiroProvider {
271
+ let tm = MultiTokenManager::new(config, vec![credentials], None, None, false).unwrap();
272
  KiroProvider::new(Arc::new(tm))
273
  }
274
 
src/kiro/token_manager.rs CHANGED
@@ -8,6 +8,8 @@ use chrono::{DateTime, Duration, Utc};
8
  use parking_lot::Mutex;
9
  use tokio::sync::Mutex as TokioMutex;
10
 
 
 
11
  use crate::http_client::{build_client, ProxyConfig};
12
  use crate::kiro::machine_id;
13
  use crate::kiro::model::credentials::KiroCredentials;
@@ -385,6 +387,10 @@ pub struct MultiTokenManager {
385
  current_index: Mutex<usize>,
386
  /// Token 刷新锁,确保同一时间只有一个刷新操作
387
  refresh_lock: TokioMutex<()>,
 
 
 
 
388
  }
389
 
390
  /// 每个凭据最大 API 调用失败次数
@@ -411,10 +417,14 @@ impl MultiTokenManager {
411
  /// * `config` - 应用配置
412
  /// * `credentials` - 按优先级排序的凭据列表
413
  /// * `proxy` - 可选的代理配置
 
 
414
  pub fn new(
415
  config: Config,
416
  credentials: Vec<KiroCredentials>,
417
  proxy: Option<ProxyConfig>,
 
 
418
  ) -> anyhow::Result<Self> {
419
  if credentials.is_empty() {
420
  anyhow::bail!("至少需要一个凭据");
@@ -435,6 +445,8 @@ impl MultiTokenManager {
435
  entries: Mutex::new(entries),
436
  current_index: Mutex::new(0),
437
  refresh_lock: TokioMutex::new(()),
 
 
438
  })
439
  }
440
 
@@ -559,8 +571,14 @@ impl MultiTokenManager {
559
  }
560
 
561
  // 更新凭据
562
- let mut entries = self.entries.lock();
563
- entries[index].credentials = new_creds.clone();
 
 
 
 
 
 
564
  new_creds
565
  } else {
566
  // 其他请求已经完成刷新,直接使用新凭据
@@ -583,6 +601,45 @@ impl MultiTokenManager {
583
  })
584
  }
585
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586
  /// 报告指定凭据 API 调用成功
587
  ///
588
  /// 重置该凭据的失败计数
@@ -771,7 +828,7 @@ mod tests {
771
  let mut cred2 = KiroCredentials::default();
772
  cred2.priority = 1;
773
 
774
- let manager = MultiTokenManager::new(config, vec![cred1, cred2], None).unwrap();
775
  assert_eq!(manager.total_count(), 2);
776
  assert_eq!(manager.available_count(), 2);
777
  }
@@ -779,7 +836,7 @@ mod tests {
779
  #[test]
780
  fn test_multi_token_manager_empty_credentials() {
781
  let config = Config::default();
782
- let result = MultiTokenManager::new(config, vec![], None);
783
  assert!(result.is_err());
784
  }
785
 
@@ -789,7 +846,7 @@ mod tests {
789
  let cred1 = KiroCredentials::default();
790
  let cred2 = KiroCredentials::default();
791
 
792
- let manager = MultiTokenManager::new(config, vec![cred1, cred2], None).unwrap();
793
 
794
  // 前两次失败不会禁用(使用 index 0)
795
  assert!(manager.report_failure(0));
@@ -812,7 +869,7 @@ mod tests {
812
  let config = Config::default();
813
  let cred = KiroCredentials::default();
814
 
815
- let manager = MultiTokenManager::new(config, vec![cred], None).unwrap();
816
 
817
  // 失败两次(使用 index 0)
818
  manager.report_failure(0);
@@ -835,7 +892,7 @@ mod tests {
835
  let mut cred2 = KiroCredentials::default();
836
  cred2.refresh_token = Some("token2".to_string());
837
 
838
- let manager = MultiTokenManager::new(config, vec![cred1, cred2], None).unwrap();
839
 
840
  // 初始是第一个凭据
841
  assert_eq!(
 
8
  use parking_lot::Mutex;
9
  use tokio::sync::Mutex as TokioMutex;
10
 
11
+ use std::path::PathBuf;
12
+
13
  use crate::http_client::{build_client, ProxyConfig};
14
  use crate::kiro::machine_id;
15
  use crate::kiro::model::credentials::KiroCredentials;
 
387
  current_index: Mutex<usize>,
388
  /// Token 刷新锁,确保同一时间只有一个刷新操作
389
  refresh_lock: TokioMutex<()>,
390
+ /// 凭据文件路径(用于回写)
391
+ credentials_path: Option<PathBuf>,
392
+ /// 是否为多凭据格式(数组格式才回写)
393
+ is_multiple_format: bool,
394
  }
395
 
396
  /// 每个凭据最大 API 调用失败次数
 
417
  /// * `config` - 应用配置
418
  /// * `credentials` - 按优先级排序的凭据列表
419
  /// * `proxy` - 可选的代理配置
420
+ /// * `credentials_path` - 凭据文件路径(用于回写)
421
+ /// * `is_multiple_format` - 是否为多凭据格式(数组格式才回写)
422
  pub fn new(
423
  config: Config,
424
  credentials: Vec<KiroCredentials>,
425
  proxy: Option<ProxyConfig>,
426
+ credentials_path: Option<PathBuf>,
427
+ is_multiple_format: bool,
428
  ) -> anyhow::Result<Self> {
429
  if credentials.is_empty() {
430
  anyhow::bail!("至少需要一个凭据");
 
445
  entries: Mutex::new(entries),
446
  current_index: Mutex::new(0),
447
  refresh_lock: TokioMutex::new(()),
448
+ credentials_path,
449
+ is_multiple_format,
450
  })
451
  }
452
 
 
571
  }
572
 
573
  // 更新凭据
574
+ {
575
+ let mut entries = self.entries.lock();
576
+ entries[index].credentials = new_creds.clone();
577
+ }
578
+
579
+ // 回写凭据到文件(仅多凭据格式)
580
+ self.persist_credentials();
581
+
582
  new_creds
583
  } else {
584
  // 其他请求已经完成刷新,直接使用新凭据
 
601
  })
602
  }
603
 
604
+ /// 将凭据列表回写到源文件
605
+ ///
606
+ /// 仅在以下条件满足时回写:
607
+ /// - 源文件是多凭据格式(数组)
608
+ /// - credentials_path 已设置
609
+ fn persist_credentials(&self) {
610
+ // 仅多凭据格式才回写
611
+ if !self.is_multiple_format {
612
+ return;
613
+ }
614
+
615
+ let path = match &self.credentials_path {
616
+ Some(p) => p,
617
+ None => return,
618
+ };
619
+
620
+ // 收集所有凭据
621
+ let credentials: Vec<KiroCredentials> = {
622
+ let entries = self.entries.lock();
623
+ entries.iter().map(|e| e.credentials.clone()).collect()
624
+ };
625
+
626
+ // 序列化为 pretty JSON
627
+ let json = match serde_json::to_string_pretty(&credentials) {
628
+ Ok(j) => j,
629
+ Err(e) => {
630
+ tracing::error!("序列化凭据失败: {}", e);
631
+ return;
632
+ }
633
+ };
634
+
635
+ // 写入文件
636
+ if let Err(e) = std::fs::write(path, json) {
637
+ tracing::error!("回写凭据文件失败: {}", e);
638
+ } else {
639
+ tracing::debug!("已回写凭据到文件: {:?}", path);
640
+ }
641
+ }
642
+
643
  /// 报告指定凭据 API 调用成功
644
  ///
645
  /// 重置该凭据的失败计数
 
828
  let mut cred2 = KiroCredentials::default();
829
  cred2.priority = 1;
830
 
831
+ let manager = MultiTokenManager::new(config, vec![cred1, cred2], None, None, false).unwrap();
832
  assert_eq!(manager.total_count(), 2);
833
  assert_eq!(manager.available_count(), 2);
834
  }
 
836
  #[test]
837
  fn test_multi_token_manager_empty_credentials() {
838
  let config = Config::default();
839
+ let result = MultiTokenManager::new(config, vec![], None, None, false);
840
  assert!(result.is_err());
841
  }
842
 
 
846
  let cred1 = KiroCredentials::default();
847
  let cred2 = KiroCredentials::default();
848
 
849
+ let manager = MultiTokenManager::new(config, vec![cred1, cred2], None, None, false).unwrap();
850
 
851
  // 前两次失败不会禁用(使用 index 0)
852
  assert!(manager.report_failure(0));
 
869
  let config = Config::default();
870
  let cred = KiroCredentials::default();
871
 
872
+ let manager = MultiTokenManager::new(config, vec![cred], None, None, false).unwrap();
873
 
874
  // 失败两次(使用 index 0)
875
  manager.report_failure(0);
 
892
  let mut cred2 = KiroCredentials::default();
893
  cred2.refresh_token = Some("token2".to_string());
894
 
895
+ let manager = MultiTokenManager::new(config, vec![cred1, cred2], None, None, false).unwrap();
896
 
897
  // 初始是第一个凭据
898
  assert_eq!(
src/main.rs CHANGED
@@ -40,6 +40,9 @@ async fn main() {
40
  std::process::exit(1);
41
  });
42
 
 
 
 
43
  // 转换为按优先级排序的凭据列表
44
  let credentials_list = credentials_config.into_sorted_credentials();
45
  tracing::info!("已加载 {} 个凭据配置", credentials_list.len());
@@ -68,11 +71,17 @@ async fn main() {
68
  }
69
 
70
  // 创建 MultiTokenManager 和 KiroProvider
71
- let token_manager = MultiTokenManager::new(config.clone(), credentials_list, proxy_config.clone())
72
- .unwrap_or_else(|e| {
73
- tracing::error!("创建 Token 管理器失败: {}", e);
74
- std::process::exit(1);
75
- });
 
 
 
 
 
 
76
  let token_manager = Arc::new(token_manager);
77
  let kiro_provider = KiroProvider::with_proxy(token_manager.clone(), proxy_config.clone());
78
 
 
40
  std::process::exit(1);
41
  });
42
 
43
+ // 判断是否为多凭据格式(用于刷新后回写)
44
+ let is_multiple_format = credentials_config.is_multiple();
45
+
46
  // 转换为按优先级排序的凭据列表
47
  let credentials_list = credentials_config.into_sorted_credentials();
48
  tracing::info!("已加载 {} 个凭据配置", credentials_list.len());
 
71
  }
72
 
73
  // 创建 MultiTokenManager 和 KiroProvider
74
+ let token_manager = MultiTokenManager::new(
75
+ config.clone(),
76
+ credentials_list,
77
+ proxy_config.clone(),
78
+ Some(credentials_path.into()),
79
+ is_multiple_format,
80
+ )
81
+ .unwrap_or_else(|e| {
82
+ tracing::error!("创建 Token 管理器失败: {}", e);
83
+ std::process::exit(1);
84
+ });
85
  let token_manager = Arc::new(token_manager);
86
  let kiro_provider = KiroProvider::with_proxy(token_manager.clone(), proxy_config.clone());
87