File size: 6,277 Bytes
a21c316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use crate::modules::{process, db, device};
use crate::models::Account;
use std::fs;

pub trait SystemIntegration: Send + Sync {
    /// 当切换账号时执行的系统层操作(如杀进程、写入文件、注入数据库)
    async fn on_account_switch(&self, account: &crate::models::Account) -> Result<(), String>;
    
    /// 更新系统托盘(如果适用)
    fn update_tray(&self);
    
    /// 发送系统通知
    fn show_notification(&self, title: &str, body: &str);
}

/// 桌面版实现:包含完整的进程控制和 UI 同步
pub struct DesktopIntegration {
    pub app_handle: tauri::AppHandle,
}

impl SystemIntegration for DesktopIntegration {
    async fn on_account_switch(&self, account: &crate::models::Account) -> Result<(), String> {
        crate::modules::logger::log_info(&format!("[Desktop] Executing system switch for: {}", account.email));
        
        // 1. 获取存储路径
        let storage_path = device::get_storage_path()?;

        // 2. 关闭外部进程
        if process::is_antigravity_running() {
            process::close_antigravity(20)?;
        }

        // 3. 写入设备 Profile
        if let Some(ref profile) = account.device_profile {
            device::write_profile(&storage_path, profile)?;
        }

        // 4. 数据库处理与 Token 注入
        let db_path = db::get_db_path()?;
        if db_path.exists() {
            let backup_path = db_path.with_extension("vscdb.backup");
            let _ = fs::copy(&db_path, &backup_path);
        }
        
        db::inject_token(
            &db_path,
            &account.token.access_token,
            &account.token.refresh_token,
            account.token.expiry_timestamp,
            &account.email,
            account.token.is_gcp_tos,
            account.token.project_id.as_deref(),
        )?;
        
        // 4.1 同步 Service Machine ID 到数据库 (关键修复点)
        if let Some(ref profile) = account.device_profile {
            let _ = db::write_service_machine_id(&db_path, &profile.mac_machine_id);
        }

        // 5. 重启外部进程
        process::start_antigravity()?;
        
        // 6. 更新托盘
        let _ = crate::modules::tray::update_tray_menus(&self.app_handle);
        
        Ok(())
    }

    fn update_tray(&self) {
        let _ = crate::modules::tray::update_tray_menus(&self.app_handle);
    }

    fn show_notification(&self, title: &str, body: &str) {
        // 使用 tauri-plugin-dialog 或原生通知(此处简化)
        crate::modules::logger::log_info(&format!("[Notification] {}: {}", title, body));
    }
}

/// Headless/Docker 实现:仅执行数据层操作,忽略 UI 和进程控制
pub struct HeadlessIntegration;

impl SystemIntegration for HeadlessIntegration {
    async fn on_account_switch(&self, account: &crate::models::Account) -> Result<(), String> {
        crate::modules::logger::log_info(&format!("[Headless] Account switched in memory: {}", account.email));
        // Docker 模式下通常不直接控制宿主机的 VS Code 进程
        // 如果需要同步配置到某个 volume,可以在此处添加逻辑
        Ok(())
    }

    fn update_tray(&self) {
        // No-op
    }

    fn show_notification(&self, title: &str, body: &str) {
        crate::modules::logger::log_info(&format!("[Log Notification] {}: {}", title, body));
    }
}
/// 系统集成管理器:替代 Arc<dyn SystemIntegration> 以解决 async trait 的 dyn 兼容性问题
#[derive(Clone)]
pub enum SystemManager {
    Desktop(tauri::AppHandle),
    Headless,
}

impl SystemManager {
    pub async fn on_account_switch(&self, account: &Account) -> Result<(), String> {
        match self {
            SystemManager::Desktop(handle) => {
                let integration = DesktopIntegration { app_handle: handle.clone() };
                integration.on_account_switch(account).await
            },
            SystemManager::Headless => {
                let integration = HeadlessIntegration;
                integration.on_account_switch(account).await
            }
        }
    }

    pub fn update_tray(&self) {
        if let SystemManager::Desktop(handle) = self {
            let integration = DesktopIntegration { app_handle: handle.clone() };
            integration.update_tray();
        }
    }

    pub fn show_notification(&self, title: &str, body: &str) {
        match self {
            SystemManager::Desktop(handle) => {
                let integration = DesktopIntegration { app_handle: handle.clone() };
                integration.show_notification(title, body);
            },
            SystemManager::Headless => {
                let integration = HeadlessIntegration;
                integration.show_notification(title, body);
            }
        }
    }
}

impl SystemIntegration for SystemManager {
    async fn on_account_switch(&self, account: &crate::models::Account) -> Result<(), String> {
        match self {
            SystemManager::Desktop(handle) => {
                let integration = DesktopIntegration { app_handle: handle.clone() };
                integration.on_account_switch(account).await
            },
            SystemManager::Headless => {
                let integration = HeadlessIntegration;
                integration.on_account_switch(account).await
            }
        }
    }

    fn update_tray(&self) {
        match self {
            SystemManager::Desktop(handle) => {
                let integration = DesktopIntegration { app_handle: handle.clone() };
                integration.update_tray();
            },
            SystemManager::Headless => {
                let integration = HeadlessIntegration;
                integration.update_tray();
            }
        }
    }

    fn show_notification(&self, title: &str, body: &str) {
        match self {
            SystemManager::Desktop(handle) => {
                let integration = DesktopIntegration { app_handle: handle.clone() };
                integration.show_notification(title, body);
            },
            SystemManager::Headless => {
                let integration = HeadlessIntegration;
                integration.show_notification(title, body);
            }
        }
    }
}