From 973d24271b08588c8ce975cb0126dd73606629e9 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Tue, 23 Jul 2024 00:28:41 +0800 Subject: [PATCH] feat(settings): add proxy setting --- src/main/index.ts | 6 +++- src/preload/index.d.ts | 1 + src/preload/index.ts | 3 +- src/renderer/src/hooks/useAppInit.ts | 6 ++++ src/renderer/src/i18n/index.ts | 8 +++-- .../src/pages/settings/GeneralSettings.tsx | 32 ++++++++++++++++--- src/renderer/src/store/migrate.ts | 3 +- src/renderer/src/store/settings.ts | 10 ++++-- src/renderer/src/utils/index.ts | 10 ++++++ 9 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index 4af33c61..493d3e0c 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,6 +1,6 @@ import { electronApp, is, optimizer } from '@electron-toolkit/utils' import * as Sentry from '@sentry/electron/main' -import { app, BrowserWindow, ipcMain, Menu, MenuItem, shell } from 'electron' +import { app, BrowserWindow, ipcMain, Menu, MenuItem, session, shell } from 'electron' import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer' import windowStateKeeper from 'electron-window-state' import { join } from 'path' @@ -101,6 +101,10 @@ app.whenReady().then(() => { shell.openExternal(url) }) + ipcMain.handle('set-proxy', (_, proxy: string) => { + session.defaultSession.setProxy({ proxyRules: proxy }) + }) + // 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法) ipcMain.handle('check-for-update', async () => { autoUpdater.logger?.info('触发检查更新') diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index 01c52c8a..979e601b 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -10,6 +10,7 @@ declare global { }> checkForUpdate: () => void openWebsite: (url: string) => void + setProxy: (proxy: string) => void } } } diff --git a/src/preload/index.ts b/src/preload/index.ts index 4523d7fd..0bfaa489 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -5,7 +5,8 @@ import { electronAPI } from '@electron-toolkit/preload' const api = { getAppInfo: () => ipcRenderer.invoke('get-app-info'), checkForUpdate: () => ipcRenderer.invoke('check-for-update'), - openWebsite: (url: string) => ipcRenderer.invoke('open-website', url) + openWebsite: (url: string) => ipcRenderer.invoke('open-website', url), + setProxy: (proxy: string) => ipcRenderer.invoke('set-proxy', proxy) } // Use `contextBridge` APIs to expose Electron APIs to diff --git a/src/renderer/src/hooks/useAppInit.ts b/src/renderer/src/hooks/useAppInit.ts index efdd7efb..d77aaac8 100644 --- a/src/renderer/src/hooks/useAppInit.ts +++ b/src/renderer/src/hooks/useAppInit.ts @@ -4,9 +4,11 @@ import { useAppDispatch } from '@renderer/store' import { setAvatar } from '@renderer/store/runtime' import { runAsyncFunction } from '@renderer/utils' import { useEffect } from 'react' +import { useSettings } from './useSettings' export function useAppInit() { const dispatch = useAppDispatch() + const { proxyUrl } = useSettings() useEffect(() => { runAsyncFunction(async () => { @@ -22,4 +24,8 @@ export function useAppInit() { isPackaged && setTimeout(window.api.checkForUpdate, 3000) }) }, []) + + useEffect(() => { + proxyUrl && window.api.setProxy(proxyUrl) + }, [proxyUrl]) } diff --git a/src/renderer/src/i18n/index.ts b/src/renderer/src/i18n/index.ts index e837e9c4..74d02857 100644 --- a/src/renderer/src/i18n/index.ts +++ b/src/renderer/src/i18n/index.ts @@ -39,6 +39,7 @@ const resources = { 'error.enter.api.key': 'Please enter your API key first', 'error.enter.api.host': 'Please enter your API host first', 'error.enter.model': 'Please select a model first', + 'error.invalid.proxy.url': 'Invalid proxy URL', 'api.connection.failed': 'Connection failed', 'api.connection.success': 'Connection successful', 'chat.completion.paused': 'Chat completion paused', @@ -142,7 +143,8 @@ const resources = { 'about.feedback.title': '📝 Feedback', 'about.feedback.button': 'Feedback', 'about.contact.title': '📧 Contact', - 'about.contact.button': 'Email' + 'about.contact.button': 'Email', + 'proxy.title': 'Proxy Address' } } }, @@ -182,6 +184,7 @@ const resources = { 'error.enter.api.key': '请输入您的 API 密钥', 'error.enter.api.host': '请输入您的 API 地址', 'error.enter.model': '请选择一个模型', + 'error.invalid.proxy.url': '无效的代理地址', 'api.connection.failed': '连接失败', 'api.connection.success': '连接成功', 'chat.completion.paused': '会话已停止', @@ -286,7 +289,8 @@ const resources = { 'about.feedback.title': '📝 意见反馈', 'about.feedback.button': '反馈', 'about.contact.title': '📧 邮件联系', - 'about.contact.button': '邮件' + 'about.contact.button': '邮件', + 'proxy.title': '代理地址' } } } diff --git a/src/renderer/src/pages/settings/GeneralSettings.tsx b/src/renderer/src/pages/settings/GeneralSettings.tsx index 26d988db..7b96191f 100644 --- a/src/renderer/src/pages/settings/GeneralSettings.tsx +++ b/src/renderer/src/pages/settings/GeneralSettings.tsx @@ -1,20 +1,22 @@ -import { FC } from 'react' +import { FC, useState } from 'react' import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components' -import { Avatar, Select, Upload } from 'antd' +import { Avatar, Input, Select, Upload } from 'antd' import styled from 'styled-components' import LocalStorage from '@renderer/services/storage' -import { compressImage } from '@renderer/utils' +import { compressImage, isValidProxyUrl } from '@renderer/utils' import useAvatar from '@renderer/hooks/useAvatar' import { useAppDispatch } from '@renderer/store' import { setAvatar } from '@renderer/store/runtime' import { useSettings } from '@renderer/hooks/useSettings' import { setLanguage } from '@renderer/store/settings' import { useTranslation } from 'react-i18next' +import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings' import i18n from '@renderer/i18n' const GeneralSettings: FC = () => { const avatar = useAvatar() - const { language } = useSettings() + const { language, proxyUrl: storeProxyUrl } = useSettings() + const [proxyUrl, setProxyUrl] = useState(storeProxyUrl) const dispatch = useAppDispatch() const { t } = useTranslation() @@ -24,6 +26,16 @@ const GeneralSettings: FC = () => { localStorage.setItem('language', value) } + const onSetProxyUrl = () => { + if (!proxyUrl || !isValidProxyUrl(proxyUrl)) { + window.message.error({ content: t('message.error.invalid.proxy.url'), key: 'proxy-error' }) + return + } + + dispatch(_setProxyUrl(proxyUrl)) + window.api.setProxy(proxyUrl) + } + return ( {t('settings.general.title')} @@ -62,6 +74,18 @@ const GeneralSettings: FC = () => { + + {t('settings.proxy.title')} + setProxyUrl(e.target.value)} + style={{ width: 300 }} + onBlur={() => onSetProxyUrl()} + type="url" + /> + + ) } diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts index ec9ab36b..b4db3d45 100644 --- a/src/renderer/src/store/migrate.ts +++ b/src/renderer/src/store/migrate.ts @@ -250,7 +250,8 @@ const migrate = createMigrate({ ...state, settings: { ...state.settings, - showAssistants: true + showAssistants: true, + proxyUrl: undefined } } } diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts index 24654825..027c5c53 100644 --- a/src/renderer/src/store/settings.ts +++ b/src/renderer/src/store/settings.ts @@ -7,13 +7,15 @@ export interface SettingsState { showAssistants: boolean sendMessageShortcut: SendMessageShortcut language: string + proxyUrl?: string } const initialState: SettingsState = { showRightSidebar: true, showAssistants: true, sendMessageShortcut: 'Enter', - language: navigator.language + language: navigator.language, + proxyUrl: undefined } const settingsSlice = createSlice({ @@ -31,10 +33,14 @@ const settingsSlice = createSlice({ }, setLanguage: (state, action: PayloadAction) => { state.language = action.payload + }, + setProxyUrl: (state, action: PayloadAction) => { + state.proxyUrl = action.payload } } }) -export const { toggleRightSidebar, toggleShowAssistants, setSendMessageShortcut, setLanguage } = settingsSlice.actions +export const { toggleRightSidebar, toggleShowAssistants, setSendMessageShortcut, setLanguage, setProxyUrl } = + settingsSlice.actions export default settingsSlice.reducer diff --git a/src/renderer/src/utils/index.ts b/src/renderer/src/utils/index.ts index 43f67b5c..fb409da0 100644 --- a/src/renderer/src/utils/index.ts +++ b/src/renderer/src/utils/index.ts @@ -203,3 +203,13 @@ export function estimateHistoryTokenCount(assistant: Assistant, msgs: Message[]) export const capitalizeFirstLetter = (str: string) => { return str.charAt(0).toUpperCase() + str.slice(1) } + +// is valid proxy url +export const isValidProxyUrl = (url: string) => { + try { + new URL(url) + return true + } catch (error) { + return false + } +}