@@ -240,6 +240,149 @@ struct CheckResult {
240240 reloaded : bool ,
241241}
242242
243+ // ============ Gemini Provider Commands ============
244+
245+ #[ derive( serde:: Serialize ) ]
246+ struct GeminiCredentialStatus {
247+ loaded : bool ,
248+ has_access_token : bool ,
249+ has_refresh_token : bool ,
250+ expiry_date : Option < i64 > ,
251+ is_valid : bool ,
252+ creds_path : String ,
253+ }
254+
255+ #[ tauri:: command]
256+ async fn get_gemini_credentials ( state : tauri:: State < ' _ , AppState > ) -> Result < GeminiCredentialStatus , String > {
257+ let s = state. read ( ) . await ;
258+ let creds = & s. gemini_provider . credentials ;
259+ let path = providers:: gemini:: GeminiProvider :: default_creds_path ( ) ;
260+
261+ Ok ( GeminiCredentialStatus {
262+ loaded : creds. access_token . is_some ( ) || creds. refresh_token . is_some ( ) ,
263+ has_access_token : creds. access_token . is_some ( ) ,
264+ has_refresh_token : creds. refresh_token . is_some ( ) ,
265+ expiry_date : creds. expiry_date ,
266+ is_valid : s. gemini_provider . is_token_valid ( ) ,
267+ creds_path : path. to_string_lossy ( ) . to_string ( ) ,
268+ } )
269+ }
270+
271+ #[ tauri:: command]
272+ async fn reload_gemini_credentials ( state : tauri:: State < ' _ , AppState > , logs : tauri:: State < ' _ , LogState > ) -> Result < String , String > {
273+ let mut s = state. write ( ) . await ;
274+ logs. write ( ) . await . add ( "info" , "[Gemini] 正在加载凭证..." ) ;
275+ s. gemini_provider . load_credentials ( ) . map_err ( |e| e. to_string ( ) ) ?;
276+ logs. write ( ) . await . add ( "info" , "[Gemini] 凭证加载成功" ) ;
277+ Ok ( "Gemini credentials reloaded" . to_string ( ) )
278+ }
279+
280+ #[ tauri:: command]
281+ async fn refresh_gemini_token ( state : tauri:: State < ' _ , AppState > , logs : tauri:: State < ' _ , LogState > ) -> Result < String , String > {
282+ let mut s = state. write ( ) . await ;
283+ logs. write ( ) . await . add ( "info" , "[Gemini] 正在刷新 Token..." ) ;
284+ let result = s. gemini_provider . refresh_token ( ) . await . map_err ( |e| e. to_string ( ) ) ;
285+ match & result {
286+ Ok ( _) => logs. write ( ) . await . add ( "info" , "[Gemini] Token 刷新成功" ) ,
287+ Err ( e) => logs. write ( ) . await . add ( "error" , & format ! ( "[Gemini] Token 刷新失败: {}" , e) ) ,
288+ }
289+ result
290+ }
291+
292+ #[ tauri:: command]
293+ async fn get_gemini_env_variables ( state : tauri:: State < ' _ , AppState > ) -> Result < Vec < EnvVariable > , String > {
294+ let s = state. read ( ) . await ;
295+ let creds = & s. gemini_provider . credentials ;
296+ let mut vars = Vec :: new ( ) ;
297+
298+ if let Some ( token) = & creds. access_token {
299+ vars. push ( EnvVariable {
300+ key : "GEMINI_ACCESS_TOKEN" . to_string ( ) ,
301+ value : token. clone ( ) ,
302+ masked : mask_token ( token) ,
303+ } ) ;
304+ }
305+ if let Some ( token) = & creds. refresh_token {
306+ vars. push ( EnvVariable {
307+ key : "GEMINI_REFRESH_TOKEN" . to_string ( ) ,
308+ value : token. clone ( ) ,
309+ masked : mask_token ( token) ,
310+ } ) ;
311+ }
312+ if let Some ( expiry) = creds. expiry_date {
313+ let expiry_str = expiry. to_string ( ) ;
314+ vars. push ( EnvVariable {
315+ key : "GEMINI_EXPIRY_DATE" . to_string ( ) ,
316+ value : expiry_str. clone ( ) ,
317+ masked : expiry_str,
318+ } ) ;
319+ }
320+
321+ Ok ( vars)
322+ }
323+
324+ #[ tauri:: command]
325+ async fn get_gemini_token_file_hash ( ) -> Result < String , String > {
326+ let path = providers:: gemini:: GeminiProvider :: default_creds_path ( ) ;
327+ if !path. exists ( ) {
328+ return Ok ( "" . to_string ( ) ) ;
329+ }
330+
331+ let content = std:: fs:: read ( & path) . map_err ( |e| e. to_string ( ) ) ?;
332+ let hash = format ! ( "{:x}" , md5:: compute( & content) ) ;
333+ Ok ( hash)
334+ }
335+
336+ #[ tauri:: command]
337+ async fn check_and_reload_gemini_credentials (
338+ state : tauri:: State < ' _ , AppState > ,
339+ logs : tauri:: State < ' _ , LogState > ,
340+ last_hash : String ,
341+ ) -> Result < CheckResult , String > {
342+ let path = providers:: gemini:: GeminiProvider :: default_creds_path ( ) ;
343+
344+ if !path. exists ( ) {
345+ return Ok ( CheckResult {
346+ changed : false ,
347+ new_hash : "" . to_string ( ) ,
348+ reloaded : false ,
349+ } ) ;
350+ }
351+
352+ let content = std:: fs:: read ( & path) . map_err ( |e| e. to_string ( ) ) ?;
353+ let new_hash = format ! ( "{:x}" , md5:: compute( & content) ) ;
354+
355+ if !last_hash. is_empty ( ) && new_hash != last_hash {
356+ logs. write ( ) . await . add ( "info" , "[Gemini][自动检测] 凭证文件已变化,正在重新加载..." ) ;
357+
358+ let mut s = state. write ( ) . await ;
359+ match s. gemini_provider . load_credentials ( ) {
360+ Ok ( _) => {
361+ logs. write ( ) . await . add ( "info" , "[Gemini][自动检测] 凭证重新加载成功" ) ;
362+ Ok ( CheckResult {
363+ changed : true ,
364+ new_hash,
365+ reloaded : true ,
366+ } )
367+ }
368+ Err ( e) => {
369+ logs. write ( ) . await . add ( "error" , & format ! ( "[Gemini][自动检测] 凭证重新加载失败: {}" , e) ) ;
370+ Ok ( CheckResult {
371+ changed : true ,
372+ new_hash,
373+ reloaded : false ,
374+ } )
375+ }
376+ }
377+ } else {
378+ Ok ( CheckResult {
379+ changed : false ,
380+ new_hash,
381+ reloaded : false ,
382+ } )
383+ }
384+ }
385+
243386#[ tauri:: command]
244387async fn get_logs ( logs : tauri:: State < ' _ , LogState > ) -> Result < Vec < logger:: LogEntry > , String > {
245388 Ok ( logs. read ( ) . await . get_logs ( ) )
@@ -324,12 +467,21 @@ pub fn run() {
324467 get_server_status,
325468 get_config,
326469 save_config,
470+ // Kiro commands
327471 refresh_kiro_token,
328472 reload_credentials,
329473 get_kiro_credentials,
330474 get_env_variables,
331475 get_token_file_hash,
332476 check_and_reload_credentials,
477+ // Gemini commands
478+ get_gemini_credentials,
479+ reload_gemini_credentials,
480+ refresh_gemini_token,
481+ get_gemini_env_variables,
482+ get_gemini_token_file_hash,
483+ check_and_reload_gemini_credentials,
484+ // Common
333485 get_logs,
334486 clear_logs,
335487 test_api,
0 commit comments