From f2da7ee59dbb76bcff98367b0b046cccec4e61a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Dec 2025 08:54:47 +0000 Subject: [PATCH 1/3] Initial plan From 4c29fb741284dfa90af3cd2e522fec9f3bfd1b35 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Dec 2025 09:03:34 +0000 Subject: [PATCH 2/3] Add proxy network settings support for outbound HTTP requests Co-authored-by: lwaay2025 <218015601+lwaay2025@users.noreply.github.com> --- main.go | 17 +- services/appsettings.go | 38 +++-- services/connectivitytestservice.go | 10 +- services/healthcheckservice.go | 11 +- services/httpclient.go | 243 ++++++++++++++++++++++++++++ services/providerrelay.go | 1 + services/skillservice.go | 2 +- services/speedtestservice.go | 18 +-- services/updateservice.go | 12 +- 9 files changed, 304 insertions(+), 48 deletions(-) create mode 100644 services/httpclient.go diff --git a/main.go b/main.go index c47711a..411001a 100644 --- a/main.go +++ b/main.go @@ -91,7 +91,22 @@ func main() { } log.Println("✅ 数据库写入队列已启动") - // 【修复】第三步:创建服务(现在可以安全使用数据库了) + // 【新增】第三步:初始化全局 HTTP 客户端(支持代理配置) + proxyConfig, err := services.GetProxyConfig() + if err != nil { + log.Printf("⚠️ 读取代理配置失败,使用默认配置: %v", err) + proxyConfig = services.ProxyConfig{UseProxy: false} + } + if err := services.InitHTTPClient(proxyConfig); err != nil { + log.Fatalf("初始化 HTTP 客户端失败: %v", err) + } + if proxyConfig.UseProxy { + log.Printf("✅ HTTP 客户端已初始化(代理: %s %s)", proxyConfig.ProxyType, proxyConfig.ProxyAddress) + } else { + log.Println("✅ HTTP 客户端已初始化(直连模式)") + } + + // 【修复】第四步:创建服务(现在可以安全使用数据库了) suiService, errt := services.NewSuiStore() if errt != nil { log.Fatalf("SuiStore 初始化失败: %v", errt) diff --git a/services/appsettings.go b/services/appsettings.go index 583d93a..784bffc 100644 --- a/services/appsettings.go +++ b/services/appsettings.go @@ -13,17 +13,20 @@ import ( const ( appSettingsDir = ".code-switch" // 【修复】修正拼写错误(原为 .codex-swtich) appSettingsFile = "app.json" - oldSettingsDir = ".codex-swtich" // 旧的错误拼写 + oldSettingsDir = ".codex-swtich" // 旧的错误拼写 migrationMarkerFile = ".migrated-from-codex-swtich" // 迁移标记文件 ) type AppSettings struct { - ShowHeatmap bool `json:"show_heatmap"` - ShowHomeTitle bool `json:"show_home_title"` - AutoStart bool `json:"auto_start"` - AutoUpdate bool `json:"auto_update"` - AutoConnectivityTest bool `json:"auto_connectivity_test"` - EnableSwitchNotify bool `json:"enable_switch_notify"` // 供应商切换通知开关 + ShowHeatmap bool `json:"show_heatmap"` + ShowHomeTitle bool `json:"show_home_title"` + AutoStart bool `json:"auto_start"` + AutoUpdate bool `json:"auto_update"` + AutoConnectivityTest bool `json:"auto_connectivity_test"` + EnableSwitchNotify bool `json:"enable_switch_notify"` // 供应商切换通知开关 + UseProxy bool `json:"use_proxy"` // 是否启用代理服务器 + ProxyAddress string `json:"proxy_address"` // 代理地址(如 http://127.0.0.1:1080) + ProxyType string `json:"proxy_type"` // 代理类型:http/https/socks5 } type AppSettingsService struct { @@ -139,9 +142,12 @@ func (as *AppSettingsService) defaultSettings() AppSettings { ShowHeatmap: true, ShowHomeTitle: true, AutoStart: autoStartEnabled, - AutoUpdate: true, // 默认开启自动更新 - AutoConnectivityTest: true, // 默认开启自动可用性监控(开箱即用) - EnableSwitchNotify: true, // 默认开启切换通知 + AutoUpdate: true, // 默认开启自动更新 + AutoConnectivityTest: true, // 默认开启自动可用性监控(开箱即用) + EnableSwitchNotify: true, // 默认开启切换通知 + UseProxy: false, // 默认不使用代理 + ProxyAddress: "", // 默认代理地址为空 + ProxyType: "http", // 默认代理类型为 HTTP } } @@ -173,6 +179,18 @@ func (as *AppSettingsService) SaveAppSettings(settings AppSettings) (AppSettings if err := as.saveLocked(settings); err != nil { return settings, err } + + // 【新增】同步代理配置到全局 HTTP 客户端 + proxyConfig := ProxyConfig{ + UseProxy: settings.UseProxy, + ProxyAddress: settings.ProxyAddress, + ProxyType: settings.ProxyType, + } + if err := UpdateHTTPClient(proxyConfig); err != nil { + // 代理配置更新失败不应阻止设置保存,只记录错误 + fmt.Printf("⚠️ 更新 HTTP 客户端代理配置失败: %v\n", err) + } + return settings, nil } diff --git a/services/connectivitytestservice.go b/services/connectivitytestservice.go index 75149e5..5870de3 100644 --- a/services/connectivitytestservice.go +++ b/services/connectivitytestservice.go @@ -81,15 +81,7 @@ func NewConnectivityTestService( "gemini": {}, }, autoTestEnabled: false, - client: &http.Client{ - Timeout: 10 * time.Second, - Transport: &http.Transport{ - MaxIdleConns: 10, - IdleConnTimeout: 30 * time.Second, - DisableCompression: true, - MaxIdleConnsPerHost: 5, - }, - }, + client: GetHTTPClientWithTimeout(10 * time.Second), } } diff --git a/services/healthcheckservice.go b/services/healthcheckservice.go index fb3d625..394a9e3 100644 --- a/services/healthcheckservice.go +++ b/services/healthcheckservice.go @@ -122,16 +122,7 @@ func NewHealthCheckService( "gemini": {}, }, pollInterval: time.Duration(DefaultPollIntervalSeconds) * time.Second, - client: &http.Client{ - // 由每次请求的 context 控制超时,避免固定值截断自定义配置 - Timeout: 0, - Transport: &http.Transport{ - MaxIdleConns: 20, - IdleConnTimeout: 30 * time.Second, - DisableCompression: true, - MaxIdleConnsPerHost: 5, - }, - }, + client: GetHTTPClient(), // 使用全局客户端,超时由每次请求的 context 控制 } } diff --git a/services/httpclient.go b/services/httpclient.go new file mode 100644 index 0000000..84a34ff --- /dev/null +++ b/services/httpclient.go @@ -0,0 +1,243 @@ +package services + +import ( + "crypto/tls" + "fmt" + "net" + "net/http" + "net/url" + "sync" + "time" + + "golang.org/x/net/proxy" +) + +var ( + // globalHTTPClient 全局 HTTP 客户端实例 + globalHTTPClient *http.Client + // clientMutex 保护全局客户端的并发访问 + clientMutex sync.RWMutex + // currentProxyConfig 当前代理配置(用于检测配置变化) + currentProxyConfig ProxyConfig +) + +// ProxyConfig 代理配置 +type ProxyConfig struct { + UseProxy bool + ProxyAddress string + ProxyType string +} + +// InitHTTPClient 初始化全局 HTTP 客户端 +// 应该在应用启动时调用一次,后续通过 UpdateHTTPClient 更新配置 +func InitHTTPClient(config ProxyConfig) error { + clientMutex.Lock() + defer clientMutex.Unlock() + + client, err := createHTTPClient(config) + if err != nil { + return err + } + + globalHTTPClient = client + currentProxyConfig = config + return nil +} + +// UpdateHTTPClient 更新全局 HTTP 客户端的代理配置 +// 当用户修改代理设置时调用 +func UpdateHTTPClient(config ProxyConfig) error { + clientMutex.Lock() + defer clientMutex.Unlock() + + // 如果配置没有变化,不需要重建客户端 + if config == currentProxyConfig { + return nil + } + + client, err := createHTTPClient(config) + if err != nil { + return err + } + + globalHTTPClient = client + currentProxyConfig = config + return nil +} + +// GetHTTPClient 获取全局 HTTP 客户端 +// 所有需要发送 HTTP 请求的地方都应该使用此函数获取客户端 +func GetHTTPClient() *http.Client { + clientMutex.RLock() + defer clientMutex.RUnlock() + + if globalHTTPClient == nil { + // 如果全局客户端未初始化,返回一个默认客户端 + return createDefaultHTTPClient() + } + + return globalHTTPClient +} + +// GetHTTPClientWithTimeout 获取带指定超时的 HTTP 客户端 +// 这会复制全局客户端的配置但使用新的超时时间 +func GetHTTPClientWithTimeout(timeout time.Duration) *http.Client { + baseClient := GetHTTPClient() + + // 创建一个新的客户端,复用传输层但设置新的超时 + client := &http.Client{ + Transport: baseClient.Transport, + Timeout: timeout, + } + + return client +} + +// createHTTPClient 根据配置创建 HTTP 客户端 +func createHTTPClient(config ProxyConfig) (*http.Client, error) { + if !config.UseProxy || config.ProxyAddress == "" { + // 不使用代理,返回默认客户端 + return createDefaultHTTPClient(), nil + } + + // 根据代理类型创建相应的传输层 + transport, err := createTransport(config) + if err != nil { + return nil, fmt.Errorf("创建代理传输层失败: %w", err) + } + + return &http.Client{ + Transport: transport, + Timeout: 32 * time.Hour, // 与现有配置保持一致:32小时超时 + }, nil +} + +// createDefaultHTTPClient 创建默认的 HTTP 客户端(不使用代理) +func createDefaultHTTPClient() *http.Client { + return &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, + }, + }, + Timeout: 32 * time.Hour, + } +} + +// createTransport 根据代理类型创建传输层 +func createTransport(config ProxyConfig) (http.RoundTripper, error) { + proxyType := config.ProxyType + proxyAddr := config.ProxyAddress + + switch proxyType { + case "http", "https": + return createHTTPProxyTransport(proxyAddr) + case "socks5": + return createSOCKS5ProxyTransport(proxyAddr) + default: + return nil, fmt.Errorf("不支持的代理类型: %s", proxyType) + } +} + +// createHTTPProxyTransport 创建 HTTP/HTTPS 代理传输层 +func createHTTPProxyTransport(proxyAddr string) (*http.Transport, error) { + proxyURL, err := url.Parse(proxyAddr) + if err != nil { + return nil, fmt.Errorf("解析代理地址失败: %w", err) + } + + transport := &http.Transport{ + Proxy: http.ProxyURL(proxyURL), + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, + }, + } + + return transport, nil +} + +// createSOCKS5ProxyTransport 创建 SOCKS5 代理传输层 +func createSOCKS5ProxyTransport(proxyAddr string) (*http.Transport, error) { + // 解析代理地址 + proxyURL, err := url.Parse(proxyAddr) + if err != nil { + // 如果不是完整 URL,尝试作为 host:port 处理 + proxyURL = &url.URL{ + Scheme: "socks5", + Host: proxyAddr, + } + } + + // 移除 URL scheme,因为 SOCKS5 拨号器只需要 host:port + socksAddr := proxyURL.Host + if socksAddr == "" { + socksAddr = proxyAddr + } + + // 创建 SOCKS5 拨号器 + dialer, err := proxy.SOCKS5("tcp", socksAddr, nil, proxy.Direct) + if err != nil { + return nil, fmt.Errorf("创建 SOCKS5 拨号器失败: %w", err) + } + + // 创建使用 SOCKS5 代理的传输层 + transport := &http.Transport{ + Dial: dialer.Dial, + DialContext: func(ctx interface{}, network, addr string) (net.Conn, error) { + return dialer.Dial(network, addr) + }, + ForceAttemptHTTP2: false, // SOCKS5 通常不支持 HTTP/2 + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, + }, + } + + return transport, nil +} + +// GetProxyConfig 从应用设置中获取代理配置 +func GetProxyConfig() (ProxyConfig, error) { + // 创建一个临时的 AppSettingsService 来读取配置 + home, err := getUserHomeDir() + if err != nil { + return ProxyConfig{}, fmt.Errorf("获取用户目录失败: %w", err) + } + + service := &AppSettingsService{ + path: home + "/" + appSettingsDir + "/" + appSettingsFile, + } + + settings, err := service.GetAppSettings() + if err != nil { + return ProxyConfig{}, fmt.Errorf("读取应用设置失败: %w", err) + } + + return ProxyConfig{ + UseProxy: settings.UseProxy, + ProxyAddress: settings.ProxyAddress, + ProxyType: settings.ProxyType, + }, nil +} diff --git a/services/providerrelay.go b/services/providerrelay.go index 13caa3d..78ca308 100644 --- a/services/providerrelay.go +++ b/services/providerrelay.go @@ -637,6 +637,7 @@ func (prs *ProviderRelayService) forwardRequest( }() req := xrequest.New(). + SetClient(GetHTTPClient()). SetHeaders(headers). SetQueryParams(query). SetRetry(1, 500*time.Millisecond). diff --git a/services/skillservice.go b/services/skillservice.go index 6f3a5c7..81a54ba 100644 --- a/services/skillservice.go +++ b/services/skillservice.go @@ -86,7 +86,7 @@ func NewSkillService() *SkillService { home = "." } return &SkillService{ - httpClient: &http.Client{Timeout: 60 * time.Second}, + httpClient: GetHTTPClientWithTimeout(60 * time.Second), storePath: filepath.Join(home, skillStoreDir, skillStoreFile), installDir: filepath.Join(home, ".claude", "skills"), } diff --git a/services/speedtestservice.go b/services/speedtestservice.go index 843f3cb..4e4c9bd 100644 --- a/services/speedtestservice.go +++ b/services/speedtestservice.go @@ -145,16 +145,16 @@ func (s *SpeedTestService) formatError(err error) string { // buildClient 构建 HTTP 客户端 func (s *SpeedTestService) buildClient(timeoutSecs int) *http.Client { - return &http.Client{ - Timeout: time.Duration(timeoutSecs) * time.Second, - CheckRedirect: func(req *http.Request, via []*http.Request) error { - // 限制重定向次数为 5 - if len(via) >= 5 { - return fmt.Errorf("重定向次数过多") - } - return nil - }, + client := GetHTTPClientWithTimeout(time.Duration(timeoutSecs) * time.Second) + // 配置重定向策略 + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + // 限制重定向次数为 5 + if len(via) >= 5 { + return fmt.Errorf("重定向次数过多") + } + return nil } + return client } // sanitizeTimeout 规范化超时参数 diff --git a/services/updateservice.go b/services/updateservice.go index faae795..1ab83f3 100644 --- a/services/updateservice.go +++ b/services/updateservice.go @@ -148,9 +148,7 @@ func detectPortableMode() bool { func (us *UpdateService) CheckUpdate() (*UpdateInfo, error) { log.Printf("[UpdateService] 开始检查更新,当前版本: %s", us.currentVersion) - client := &http.Client{ - Timeout: 15 * time.Second, // 增加超时时间从10秒到15秒 - } + client := GetHTTPClientWithTimeout(15 * time.Second) releaseURL := "https://api.github.com/repos/Rogers-F/code-switch-R/releases/latest" @@ -312,7 +310,7 @@ func (us *UpdateService) findSHA256ForAsset(assets []struct { } // 下载并解析 SHA256 文件 - client := &http.Client{Timeout: 10 * time.Second} + client := GetHTTPClientWithTimeout(10 * time.Second) resp, err := client.Get(sha256URL) if err != nil { log.Printf("[UpdateService] 下载 SHA256 文件失败: %v", err) @@ -431,7 +429,7 @@ func (us *UpdateService) DownloadUpdate(progressCallback func(float64)) error { // downloadWithResume 支持断点续传的下载 func (us *UpdateService) downloadWithResume(url, dest string, progressCallback func(float64)) error { - client := &http.Client{Timeout: 5 * time.Minute} + client := GetHTTPClientWithTimeout(5 * time.Minute) var start int64 var total int64 @@ -1962,9 +1960,7 @@ func (us *UpdateService) downloadAndVerify(assetName string) (string, error) { // downloadFile 下载单个文件 func (us *UpdateService) downloadFile(url, destPath string) error { - client := &http.Client{ - Timeout: 5 * time.Minute, // 大文件下载超时 - } + client := GetHTTPClientWithTimeout(5 * time.Minute) resp, err := client.Get(url) if err != nil { From 45c634426f0e8d9cdd3bb4ffb3518174423623f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Dec 2025 09:08:12 +0000 Subject: [PATCH 3/3] Add proxy settings UI in frontend general settings Co-authored-by: lwaay2025 <218015601+lwaay2025@users.noreply.github.com> --- frontend/src/components/General/Index.vue | 68 +++++++++++++++++++++++ frontend/src/locales/en.json | 10 +++- frontend/src/locales/zh.json | 10 +++- frontend/src/services/appSettings.ts | 6 ++ 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/General/Index.vue b/frontend/src/components/General/Index.vue index 467e75b..d8d8e9a 100644 --- a/frontend/src/components/General/Index.vue +++ b/frontend/src/components/General/Index.vue @@ -28,6 +28,12 @@ const autoStartEnabled = ref(getCachedValue('autoStart', false)) const autoUpdateEnabled = ref(getCachedValue('autoUpdate', true)) const autoConnectivityTestEnabled = ref(getCachedValue('autoConnectivityTest', false)) const switchNotifyEnabled = ref(getCachedValue('switchNotify', true)) // 切换通知开关 + +// 代理配置相关状态 +const useProxy = ref(getCachedValue('useProxy', false)) +const proxyAddress = ref(localStorage.getItem('app-settings-proxyAddress') || '') +const proxyType = ref(localStorage.getItem('app-settings-proxyType') || 'http') + const settingsLoading = ref(true) const saveBusy = ref(false) @@ -65,6 +71,9 @@ const loadAppSettings = async () => { autoUpdateEnabled.value = data?.auto_update ?? true autoConnectivityTestEnabled.value = data?.auto_connectivity_test ?? false switchNotifyEnabled.value = data?.enable_switch_notify ?? true + useProxy.value = data?.use_proxy ?? false + proxyAddress.value = data?.proxy_address ?? '' + proxyType.value = data?.proxy_type ?? 'http' // 缓存到 localStorage,下次打开时直接显示正确状态 localStorage.setItem('app-settings-heatmap', String(heatmapEnabled.value)) @@ -73,6 +82,9 @@ const loadAppSettings = async () => { localStorage.setItem('app-settings-autoUpdate', String(autoUpdateEnabled.value)) localStorage.setItem('app-settings-autoConnectivityTest', String(autoConnectivityTestEnabled.value)) localStorage.setItem('app-settings-switchNotify', String(switchNotifyEnabled.value)) + localStorage.setItem('app-settings-useProxy', String(useProxy.value)) + localStorage.setItem('app-settings-proxyAddress', proxyAddress.value) + localStorage.setItem('app-settings-proxyType', proxyType.value) } catch (error) { console.error('failed to load app settings', error) heatmapEnabled.value = true @@ -81,6 +93,9 @@ const loadAppSettings = async () => { autoUpdateEnabled.value = true autoConnectivityTestEnabled.value = false switchNotifyEnabled.value = true + useProxy.value = false + proxyAddress.value = '' + proxyType.value = 'http' } finally { settingsLoading.value = false } @@ -97,6 +112,9 @@ const persistAppSettings = async () => { auto_update: autoUpdateEnabled.value, auto_connectivity_test: autoConnectivityTestEnabled.value, enable_switch_notify: switchNotifyEnabled.value, + use_proxy: useProxy.value, + proxy_address: proxyAddress.value, + proxy_type: proxyType.value, } await saveAppSettings(payload) @@ -458,6 +476,51 @@ onMounted(async () => { + + + {{ $t('components.general.title.proxy') }} + + + + + + + + {{ $t('components.general.label.useProxyHint') }} + + + + + + + HTTP/HTTPS + SOCKS5 + + + + + + + + + + @@ -663,6 +726,11 @@ onMounted(async () => { font-size: 12px; } +.proxy-address-input { + width: 320px; + font-size: 12px; +} + .info-text.warning { color: var(--mac-text-warning, #e67e22); } diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 0f4dc6a..17a9561 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -515,7 +515,8 @@ "update": "Application update", "blacklist": "Blacklist Settings", "dataImport": "Data Import", - "connectivity": "Connectivity Test" + "connectivity": "Connectivity Test", + "proxy": "Proxy Network Settings" }, "label": { "assistant_access": "Accessibility permissions", @@ -548,7 +549,12 @@ "times": "times", "minutes": "minutes", "save": "Save", - "saving": "Saving..." + "saving": "Saving...", + "useProxy": "Use proxy server", + "useProxyHint": "When enabled, all requests to vendor APIs will be forwarded through the proxy", + "proxyType": "Proxy type", + "proxyAddress": "Proxy address", + "proxyAddressPlaceholder": "e.g., http://127.0.0.1:1080 or socks5://127.0.0.1:1080" }, "subLabel": { "sb_assistant_access": "Accessibility permission is required to operate clipboard contents", diff --git a/frontend/src/locales/zh.json b/frontend/src/locales/zh.json index 8b4254d..385e48e 100644 --- a/frontend/src/locales/zh.json +++ b/frontend/src/locales/zh.json @@ -516,7 +516,8 @@ "update": "应用更新", "blacklist": "拉黑配置", "dataImport": "数据导入", - "connectivity": "连通性检测" + "connectivity": "连通性检测", + "proxy": "代理网络设置" }, "label": { "assistant_access": "辅助功能访问权限", @@ -549,7 +550,12 @@ "times": "次", "minutes": "分钟", "save": "保存", - "saving": "保存中..." + "saving": "保存中...", + "useProxy": "使用代理服务器", + "useProxyHint": "启用后所有发往供应商 API 的请求将通过代理转发", + "proxyType": "代理类型", + "proxyAddress": "代理地址", + "proxyAddressPlaceholder": "例如:http://127.0.0.1:1080 或 socks5://127.0.0.1:1080" }, "subLabel": { "sb_assistant_access": "需要无障碍访问权限来操作剪切板内容", diff --git a/frontend/src/services/appSettings.ts b/frontend/src/services/appSettings.ts index 18f2212..255a41d 100644 --- a/frontend/src/services/appSettings.ts +++ b/frontend/src/services/appSettings.ts @@ -7,6 +7,9 @@ export type AppSettings = { auto_update: boolean auto_connectivity_test: boolean enable_switch_notify: boolean // 供应商切换通知开关 + use_proxy: boolean // 是否启用代理服务器 + proxy_address: string // 代理地址 + proxy_type: string // 代理类型:http/https/socks5 } const DEFAULT_SETTINGS: AppSettings = { @@ -16,6 +19,9 @@ const DEFAULT_SETTINGS: AppSettings = { auto_update: true, auto_connectivity_test: false, enable_switch_notify: true, // 默认开启 + use_proxy: false, // 默认不使用代理 + proxy_address: '', // 默认代理地址为空 + proxy_type: 'http', // 默认代理类型为 HTTP } export const fetchAppSettings = async (): Promise => {