feat(settings): add proxy setting
This commit is contained in:
parent
f434fe1231
commit
973d24271b
@ -1,6 +1,6 @@
|
|||||||
import { electronApp, is, optimizer } from '@electron-toolkit/utils'
|
import { electronApp, is, optimizer } from '@electron-toolkit/utils'
|
||||||
import * as Sentry from '@sentry/electron/main'
|
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 installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer'
|
||||||
import windowStateKeeper from 'electron-window-state'
|
import windowStateKeeper from 'electron-window-state'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
@ -101,6 +101,10 @@ app.whenReady().then(() => {
|
|||||||
shell.openExternal(url)
|
shell.openExternal(url)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('set-proxy', (_, proxy: string) => {
|
||||||
|
session.defaultSession.setProxy({ proxyRules: proxy })
|
||||||
|
})
|
||||||
|
|
||||||
// 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法)
|
// 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法)
|
||||||
ipcMain.handle('check-for-update', async () => {
|
ipcMain.handle('check-for-update', async () => {
|
||||||
autoUpdater.logger?.info('触发检查更新')
|
autoUpdater.logger?.info('触发检查更新')
|
||||||
|
|||||||
1
src/preload/index.d.ts
vendored
1
src/preload/index.d.ts
vendored
@ -10,6 +10,7 @@ declare global {
|
|||||||
}>
|
}>
|
||||||
checkForUpdate: () => void
|
checkForUpdate: () => void
|
||||||
openWebsite: (url: string) => void
|
openWebsite: (url: string) => void
|
||||||
|
setProxy: (proxy: string) => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,8 @@ import { electronAPI } from '@electron-toolkit/preload'
|
|||||||
const api = {
|
const api = {
|
||||||
getAppInfo: () => ipcRenderer.invoke('get-app-info'),
|
getAppInfo: () => ipcRenderer.invoke('get-app-info'),
|
||||||
checkForUpdate: () => ipcRenderer.invoke('check-for-update'),
|
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
|
// Use `contextBridge` APIs to expose Electron APIs to
|
||||||
|
|||||||
@ -4,9 +4,11 @@ import { useAppDispatch } from '@renderer/store'
|
|||||||
import { setAvatar } from '@renderer/store/runtime'
|
import { setAvatar } from '@renderer/store/runtime'
|
||||||
import { runAsyncFunction } from '@renderer/utils'
|
import { runAsyncFunction } from '@renderer/utils'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
import { useSettings } from './useSettings'
|
||||||
|
|
||||||
export function useAppInit() {
|
export function useAppInit() {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
const { proxyUrl } = useSettings()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
runAsyncFunction(async () => {
|
runAsyncFunction(async () => {
|
||||||
@ -22,4 +24,8 @@ export function useAppInit() {
|
|||||||
isPackaged && setTimeout(window.api.checkForUpdate, 3000)
|
isPackaged && setTimeout(window.api.checkForUpdate, 3000)
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
proxyUrl && window.api.setProxy(proxyUrl)
|
||||||
|
}, [proxyUrl])
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,7 @@ const resources = {
|
|||||||
'error.enter.api.key': 'Please enter your API key first',
|
'error.enter.api.key': 'Please enter your API key first',
|
||||||
'error.enter.api.host': 'Please enter your API host first',
|
'error.enter.api.host': 'Please enter your API host first',
|
||||||
'error.enter.model': 'Please select a model first',
|
'error.enter.model': 'Please select a model first',
|
||||||
|
'error.invalid.proxy.url': 'Invalid proxy URL',
|
||||||
'api.connection.failed': 'Connection failed',
|
'api.connection.failed': 'Connection failed',
|
||||||
'api.connection.success': 'Connection successful',
|
'api.connection.success': 'Connection successful',
|
||||||
'chat.completion.paused': 'Chat completion paused',
|
'chat.completion.paused': 'Chat completion paused',
|
||||||
@ -142,7 +143,8 @@ const resources = {
|
|||||||
'about.feedback.title': '📝 Feedback',
|
'about.feedback.title': '📝 Feedback',
|
||||||
'about.feedback.button': 'Feedback',
|
'about.feedback.button': 'Feedback',
|
||||||
'about.contact.title': '📧 Contact',
|
'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.key': '请输入您的 API 密钥',
|
||||||
'error.enter.api.host': '请输入您的 API 地址',
|
'error.enter.api.host': '请输入您的 API 地址',
|
||||||
'error.enter.model': '请选择一个模型',
|
'error.enter.model': '请选择一个模型',
|
||||||
|
'error.invalid.proxy.url': '无效的代理地址',
|
||||||
'api.connection.failed': '连接失败',
|
'api.connection.failed': '连接失败',
|
||||||
'api.connection.success': '连接成功',
|
'api.connection.success': '连接成功',
|
||||||
'chat.completion.paused': '会话已停止',
|
'chat.completion.paused': '会话已停止',
|
||||||
@ -286,7 +289,8 @@ const resources = {
|
|||||||
'about.feedback.title': '📝 意见反馈',
|
'about.feedback.title': '📝 意见反馈',
|
||||||
'about.feedback.button': '反馈',
|
'about.feedback.button': '反馈',
|
||||||
'about.contact.title': '📧 邮件联系',
|
'about.contact.title': '📧 邮件联系',
|
||||||
'about.contact.button': '邮件'
|
'about.contact.button': '邮件',
|
||||||
|
'proxy.title': '代理地址'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,22 @@
|
|||||||
import { FC } from 'react'
|
import { FC, useState } from 'react'
|
||||||
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components'
|
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 styled from 'styled-components'
|
||||||
import LocalStorage from '@renderer/services/storage'
|
import LocalStorage from '@renderer/services/storage'
|
||||||
import { compressImage } from '@renderer/utils'
|
import { compressImage, isValidProxyUrl } from '@renderer/utils'
|
||||||
import useAvatar from '@renderer/hooks/useAvatar'
|
import useAvatar from '@renderer/hooks/useAvatar'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { setAvatar } from '@renderer/store/runtime'
|
import { setAvatar } from '@renderer/store/runtime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { setLanguage } from '@renderer/store/settings'
|
import { setLanguage } from '@renderer/store/settings'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings'
|
||||||
import i18n from '@renderer/i18n'
|
import i18n from '@renderer/i18n'
|
||||||
|
|
||||||
const GeneralSettings: FC = () => {
|
const GeneralSettings: FC = () => {
|
||||||
const avatar = useAvatar()
|
const avatar = useAvatar()
|
||||||
const { language } = useSettings()
|
const { language, proxyUrl: storeProxyUrl } = useSettings()
|
||||||
|
const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
@ -24,6 +26,16 @@ const GeneralSettings: FC = () => {
|
|||||||
localStorage.setItem('language', value)
|
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 (
|
return (
|
||||||
<SettingContainer>
|
<SettingContainer>
|
||||||
<SettingTitle>{t('settings.general.title')}</SettingTitle>
|
<SettingTitle>{t('settings.general.title')}</SettingTitle>
|
||||||
@ -62,6 +74,18 @@ const GeneralSettings: FC = () => {
|
|||||||
</Upload>
|
</Upload>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
|
<SettingRow>
|
||||||
|
<SettingRowTitle>{t('settings.proxy.title')}</SettingRowTitle>
|
||||||
|
<Input
|
||||||
|
placeholder="socks5://127.0.0.1:6153"
|
||||||
|
value={proxyUrl}
|
||||||
|
onChange={(e) => setProxyUrl(e.target.value)}
|
||||||
|
style={{ width: 300 }}
|
||||||
|
onBlur={() => onSetProxyUrl()}
|
||||||
|
type="url"
|
||||||
|
/>
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
</SettingContainer>
|
</SettingContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -250,7 +250,8 @@ const migrate = createMigrate({
|
|||||||
...state,
|
...state,
|
||||||
settings: {
|
settings: {
|
||||||
...state.settings,
|
...state.settings,
|
||||||
showAssistants: true
|
showAssistants: true,
|
||||||
|
proxyUrl: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,13 +7,15 @@ export interface SettingsState {
|
|||||||
showAssistants: boolean
|
showAssistants: boolean
|
||||||
sendMessageShortcut: SendMessageShortcut
|
sendMessageShortcut: SendMessageShortcut
|
||||||
language: string
|
language: string
|
||||||
|
proxyUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: SettingsState = {
|
const initialState: SettingsState = {
|
||||||
showRightSidebar: true,
|
showRightSidebar: true,
|
||||||
showAssistants: true,
|
showAssistants: true,
|
||||||
sendMessageShortcut: 'Enter',
|
sendMessageShortcut: 'Enter',
|
||||||
language: navigator.language
|
language: navigator.language,
|
||||||
|
proxyUrl: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingsSlice = createSlice({
|
const settingsSlice = createSlice({
|
||||||
@ -31,10 +33,14 @@ const settingsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
setLanguage: (state, action: PayloadAction<string>) => {
|
setLanguage: (state, action: PayloadAction<string>) => {
|
||||||
state.language = action.payload
|
state.language = action.payload
|
||||||
|
},
|
||||||
|
setProxyUrl: (state, action: PayloadAction<string | undefined>) => {
|
||||||
|
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
|
export default settingsSlice.reducer
|
||||||
|
|||||||
@ -203,3 +203,13 @@ export function estimateHistoryTokenCount(assistant: Assistant, msgs: Message[])
|
|||||||
export const capitalizeFirstLetter = (str: string) => {
|
export const capitalizeFirstLetter = (str: string) => {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user