mirror of
https://github.com/yaklang/yaklang-chrome-extension.git
synced 2026-09-22 03:10:43 +08:00
fix popup ui
This commit is contained in:
@@ -350,3 +350,27 @@ body {
|
||||
.ant-menu .ant-menu-item.ant-menu-item-selected.active-item::after {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.active-item {
|
||||
background-color: #F28B44 !important;
|
||||
color: white !important;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s ease-in-out !important;
|
||||
}
|
||||
|
||||
.active-item img {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.active-item .anticon {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.proxy-menu .ant-menu-item {
|
||||
transition: all 0.2s ease-in-out !important;
|
||||
}
|
||||
|
||||
/* 添加悬停效果 */
|
||||
.proxy-menu .ant-menu-item:hover {
|
||||
background-color: rgba(242, 139, 68, 0.1) !important;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import {browser,} from 'wxt/browser';
|
||||
import type {MenuProps} from 'antd';
|
||||
import type {ProxyConfig} from '@/types/proxy';
|
||||
import {ContentActionType, ProxyActionType} from '@/types/action';
|
||||
import { getAllProxyConfigs, getCurrentProxy } from '@/utils/storage';
|
||||
|
||||
import './index.css';
|
||||
|
||||
@@ -58,6 +59,7 @@ export const ProxySwitch: React.FC = () => {
|
||||
const handleMessage = (message: any) => {
|
||||
if (message.action === ContentActionType.PROXY_CONFIGS_UPDATED && message.source !== 'proxy_switch') {
|
||||
loadCustomProxies();
|
||||
loadProxyStatus();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -80,18 +82,23 @@ export const ProxySwitch: React.FC = () => {
|
||||
// 获取当前代理状态
|
||||
const loadProxyStatus = async () => {
|
||||
try {
|
||||
// 先尝试从后台脚本获取当前代理状态
|
||||
const response = await browser.runtime.sendMessage({
|
||||
action: ProxyActionType.GET_PROXY_STATUS
|
||||
});
|
||||
|
||||
if (!response) {
|
||||
console.log('No response from background script');
|
||||
if (response && response.success) {
|
||||
const activeMode = response.data.mode;
|
||||
setCurrentMode(activeMode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.success) {
|
||||
const activeMode = response.data.mode;
|
||||
setCurrentMode(activeMode);
|
||||
// 如果后台脚本没有返回,则从存储中获取当前代理
|
||||
const currentProxy = await getCurrentProxy();
|
||||
if (currentProxy) {
|
||||
setCurrentMode(currentProxy.id);
|
||||
} else {
|
||||
setCurrentMode('direct');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading proxy status:', error);
|
||||
@@ -102,33 +109,12 @@ export const ProxySwitch: React.FC = () => {
|
||||
// 加载自定义代理配置
|
||||
const loadCustomProxies = async () => {
|
||||
try {
|
||||
const DB_NAME = 'yaklang_extension';
|
||||
const STORE_NAME = 'proxy_configs';
|
||||
|
||||
// 打开数据库
|
||||
const db = await new Promise<IDBDatabase>((resolve, reject) => {
|
||||
const request = indexedDB.open(DB_NAME, 1);
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
});
|
||||
|
||||
// 从数据库读取代理配置
|
||||
const configs = await new Promise<ProxyConfig[]>((resolve, reject) => {
|
||||
try {
|
||||
const transaction = db.transaction([STORE_NAME], 'readonly');
|
||||
const store = transaction.objectStore(STORE_NAME);
|
||||
const request = store.getAll();
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(request.result || []);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
// 使用存储API获取所有代理配置
|
||||
const configs = await getAllProxyConfigs();
|
||||
|
||||
// 处理代理配置
|
||||
const proxies = configs
|
||||
.filter((proxy: ProxyConfig) => !FIXED_MODES.some(mode => mode.key === proxy.id))
|
||||
.filter((proxy: ProxyConfig) => !['direct', 'system'].includes(proxy.id))
|
||||
.map((proxy: ProxyConfig): CustomProxy => ({
|
||||
key: proxy.id,
|
||||
name: proxy.name,
|
||||
@@ -138,6 +124,7 @@ export const ProxySwitch: React.FC = () => {
|
||||
}));
|
||||
setCustomProxies(proxies);
|
||||
|
||||
// 查找并设置已启用的代理
|
||||
const enabledProxy = configs.find((proxy: ProxyConfig) => proxy.enabled);
|
||||
if (enabledProxy) {
|
||||
setCurrentMode(enabledProxy.id);
|
||||
@@ -182,6 +169,8 @@ export const ProxySwitch: React.FC = () => {
|
||||
}
|
||||
|
||||
try {
|
||||
// 先更新UI状态,避免闪烁
|
||||
setCurrentMode(mode);
|
||||
setIsLoading(true);
|
||||
|
||||
// 发送切换代理请求
|
||||
@@ -190,11 +179,17 @@ export const ProxySwitch: React.FC = () => {
|
||||
mode
|
||||
});
|
||||
|
||||
if (response && response.success) {
|
||||
setCurrentMode(mode);
|
||||
if (!response || !response.success) {
|
||||
// 如果失败,恢复原状态
|
||||
console.error('Failed to switch proxy mode');
|
||||
await loadProxyStatus(); // 重新加载正确的状态
|
||||
} else {
|
||||
// 成功时刷新代理列表状态
|
||||
await loadCustomProxies();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error switching to proxy mode ${mode}:`, error);
|
||||
await loadProxyStatus(); // 出错时重新加载正确的状态
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -218,7 +213,15 @@ export const ProxySwitch: React.FC = () => {
|
||||
...customProxies.map(proxy => ({
|
||||
key: proxy.key,
|
||||
label: proxy.name,
|
||||
icon: <img src={YAK_ICON_URL} alt="YAK" style={{width: 24, height: 24}}/>,
|
||||
icon: <img
|
||||
src={YAK_ICON_URL}
|
||||
alt="YAK"
|
||||
style={{
|
||||
width: 20,
|
||||
height: 20,
|
||||
filter: currentMode === proxy.key ? 'brightness(0) invert(1)' : 'none'
|
||||
}}
|
||||
/>,
|
||||
className: `${currentMode === proxy.key ? 'active-item' : ''} menu-id-${proxy.key}`,
|
||||
}))
|
||||
);
|
||||
|
||||
@@ -1,11 +1,32 @@
|
||||
import { browser, type Browser } from 'wxt/browser';
|
||||
import {ContentActionType, ProxyActionType} from '@/types/action';
|
||||
import { getCurrentProxyMode, switchProxyMode } from '@/utils/proxy';
|
||||
import { getProxyConfig, saveProxyConfig } from '@/utils/storage';
|
||||
import type { ProxyConfig } from '@/types/proxy';
|
||||
|
||||
// 固定的代理模式配置
|
||||
const FIXED_MODES = [
|
||||
{
|
||||
id: 'direct',
|
||||
name: '[直接连接]',
|
||||
proxyType: 'direct',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
id: 'system',
|
||||
name: '[系统代理]',
|
||||
proxyType: 'system',
|
||||
enabled: false
|
||||
}
|
||||
];
|
||||
|
||||
export default defineBackground({
|
||||
type: 'module',
|
||||
|
||||
main() {
|
||||
async main() {
|
||||
// 初始化固定模式的代理配置
|
||||
await initializeFixedModes();
|
||||
|
||||
// 初始化代理状态监听
|
||||
browser.runtime.onMessage.addListener((message: any, sender: Browser.runtime.MessageSender, sendResponse: (response?: any) => void) => {
|
||||
if (message.action === ProxyActionType.GET_PROXY_STATUS) {
|
||||
@@ -34,3 +55,19 @@ export default defineBackground({
|
||||
console.log('代理管理后台服务已启动');
|
||||
},
|
||||
});
|
||||
|
||||
// 初始化固定模式的代理配置
|
||||
async function initializeFixedModes() {
|
||||
try {
|
||||
// 确保固定模式的配置已保存到数据库
|
||||
for (const modeConfig of FIXED_MODES) {
|
||||
const existingConfig = await getProxyConfig(modeConfig.id);
|
||||
if (!existingConfig) {
|
||||
console.log(`初始化固定模式配置: ${modeConfig.id}`);
|
||||
await saveProxyConfig(modeConfig as ProxyConfig);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化固定模式配置失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,26 @@
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.add-proxy-card .ant-modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 10px 24px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.add-proxy-card .ant-modal-footer button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.required-label::before {
|
||||
content: '* ';
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.ant-form-item-label > label.ant-form-item-required:not(.ant-form-item-required-mark-optional)::before {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ant-space {
|
||||
width: 100%;
|
||||
}
|
||||
+147
-32
@@ -47,20 +47,68 @@ export default function App() {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const newProxy: ProxyConfig = {
|
||||
const newProxy: Partial<ProxyConfig> = {
|
||||
id: uuidv4(),
|
||||
name: values.name,
|
||||
proxyType: "fixed_servers",
|
||||
scheme: values.proxyType,
|
||||
host: values.host,
|
||||
port: Number(values.port),
|
||||
enabled: false
|
||||
};
|
||||
|
||||
if (values.proxyType === 'fixed_servers') {
|
||||
newProxy.proxyType = 'fixed_servers';
|
||||
newProxy.scheme = values.scheme;
|
||||
newProxy.host = values.host;
|
||||
newProxy.port = Number(values.port);
|
||||
|
||||
// 处理不经过代理的地址
|
||||
if (values.bypassList) {
|
||||
newProxy.bypassList = values.bypassList
|
||||
.split('\n')
|
||||
.map((line: string) => line.trim())
|
||||
.filter((line: string) => line.length > 0);
|
||||
} else {
|
||||
newProxy.bypassList = [];
|
||||
}
|
||||
} else if (values.proxyType === 'pac_script') {
|
||||
newProxy.proxyType = 'pac_script';
|
||||
newProxy.mode = 'pac_script';
|
||||
|
||||
// 处理PAC脚本匹配域名
|
||||
if (values.matchList) {
|
||||
newProxy.matchList = values.matchList
|
||||
.split('\n')
|
||||
.map((line: string) => line.trim())
|
||||
.filter((line: string) => line.length > 0);
|
||||
}
|
||||
|
||||
// 创建PAC脚本
|
||||
newProxy.pacScript = {
|
||||
data: `function FindProxyForURL(url, host) {
|
||||
// 匹配域名列表
|
||||
const domains = ${JSON.stringify(newProxy.matchList || [])};
|
||||
|
||||
// 检查是否匹配任何域名
|
||||
for (let i = 0; i < domains.length; i++) {
|
||||
const domain = domains[i];
|
||||
// 支持通配符
|
||||
if (domain.startsWith('*.') && host.endsWith(domain.substring(1))) {
|
||||
return 'PROXY ${values.host}:${values.port}';
|
||||
} else if (host === domain) {
|
||||
return 'PROXY ${values.host}:${values.port}';
|
||||
}
|
||||
}
|
||||
|
||||
// 默认直接连接
|
||||
return 'DIRECT';
|
||||
}`,
|
||||
mandatory: true
|
||||
};
|
||||
}
|
||||
|
||||
// 添加认证信息
|
||||
if (values.username) newProxy.username = values.username;
|
||||
if (values.password) newProxy.password = values.password;
|
||||
|
||||
await saveProxyConfig(newProxy);
|
||||
await saveProxyConfig(newProxy as ProxyConfig);
|
||||
|
||||
// 重新加载代理列表
|
||||
await loadProxies();
|
||||
@@ -111,6 +159,12 @@ export default function App() {
|
||||
|
||||
// 重新加载代理列表
|
||||
await loadProxies();
|
||||
|
||||
// 通知后台脚本
|
||||
browser.runtime.sendMessage({
|
||||
action: ContentActionType.PROXY_CONFIGS_UPDATED,
|
||||
source: 'options'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error activating proxy ${id}:`, error);
|
||||
}
|
||||
@@ -179,9 +233,14 @@ export default function App() {
|
||||
key={proxy.id}
|
||||
actions={[
|
||||
<Button
|
||||
type="primary"
|
||||
type={proxy.enabled ? "default" : "primary"}
|
||||
onClick={() => handleActivate(proxy.id)}
|
||||
disabled={proxy.enabled}
|
||||
style={proxy.enabled ? {
|
||||
backgroundColor: "#F28B44",
|
||||
color: "white",
|
||||
borderColor: "#F28B44"
|
||||
} : undefined}
|
||||
>
|
||||
{proxy.enabled ? '已启用' : '启用'}
|
||||
</Button>,
|
||||
@@ -207,7 +266,19 @@ export default function App() {
|
||||
open={isModalOpen}
|
||||
className='add-proxy-card'
|
||||
onCancel={handleCancel}
|
||||
footer={null}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={handleCancel}>
|
||||
Cancel
|
||||
</Button>,
|
||||
<Button
|
||||
key="submit"
|
||||
type="primary"
|
||||
onClick={() => form.submit()}
|
||||
loading={loading}
|
||||
>
|
||||
OK
|
||||
</Button>
|
||||
]}
|
||||
destroyOnClose
|
||||
>
|
||||
<Form
|
||||
@@ -217,17 +288,38 @@ export default function App() {
|
||||
>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="代理名称"
|
||||
label={<span className="required-label">名称</span>}
|
||||
rules={[{ required: true, message: '请输入代理名称' }]}
|
||||
>
|
||||
<Input placeholder="例如: 公司内网代理" />
|
||||
<Input placeholder="为此代理添加一个名称" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="proxyType"
|
||||
label="代理类型"
|
||||
initialValue="http"
|
||||
label={<span className="required-label">类型</span>}
|
||||
initialValue="fixed_servers"
|
||||
rules={[{ required: true, message: '请选择代理类型' }]}
|
||||
>
|
||||
<Select>
|
||||
<Option value="fixed_servers">代理服务器</Option>
|
||||
<Option value="pac_script">PAC 脚本</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
noStyle
|
||||
shouldUpdate={(prevValues, currentValues) => prevValues.proxyType !== currentValues.proxyType}
|
||||
>
|
||||
{({ getFieldValue }) => {
|
||||
const proxyType = getFieldValue('proxyType');
|
||||
if (proxyType === 'fixed_servers') {
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name="scheme"
|
||||
label={<span className="required-label">协议</span>}
|
||||
initialValue="http"
|
||||
rules={[{ required: true, message: '请选择代理协议' }]}
|
||||
>
|
||||
<Select>
|
||||
<Option value="http">HTTP</Option>
|
||||
@@ -237,25 +329,60 @@ export default function App() {
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Space style={{ display: 'flex' }}>
|
||||
<Form.Item
|
||||
name="host"
|
||||
label="主机地址"
|
||||
label={<span className="required-label">主机</span>}
|
||||
rules={[{ required: true, message: '请输入主机地址' }]}
|
||||
style={{ flex: 3 }}
|
||||
>
|
||||
<Input placeholder="例如: proxy.example.com 或 192.168.1.100" />
|
||||
<Input placeholder="127.0.0.1" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="port"
|
||||
label="端口"
|
||||
label={<span className="required-label">端口</span>}
|
||||
rules={[{ required: true, message: '请输入端口' }]}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<Input placeholder="例如: 8080" />
|
||||
<Input placeholder="8080" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="bypassList"
|
||||
label="不经过代理的地址"
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder={`例如:
|
||||
localhost
|
||||
127.0.0.1
|
||||
*.example.com`}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: '#999' }}>每行一个地址,支持通配符 *</div>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
} else if (proxyType === 'pac_script') {
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name="matchList"
|
||||
label={<span className="required-label">匹配域名</span>}
|
||||
rules={[{ required: true, message: '请输入至少一个匹配域名' }]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder={`例如:
|
||||
*.example.com
|
||||
google.com
|
||||
github.com`}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: '#999' }}>每行一个域名,支持通配符 *</div>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
</Form.Item>
|
||||
</Space>
|
||||
|
||||
<Space style={{ display: 'flex' }}>
|
||||
<Form.Item
|
||||
@@ -274,18 +401,6 @@ export default function App() {
|
||||
<Input.Password placeholder="认证密码" />
|
||||
</Form.Item>
|
||||
</Space>
|
||||
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
icon={<PlusOutlined />}
|
||||
loading={loading}
|
||||
block
|
||||
>
|
||||
添加代理
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</Content>
|
||||
|
||||
+28
-22
@@ -1,6 +1,6 @@
|
||||
import { browser } from 'wxt/browser';
|
||||
import type { ProxyConfig } from '../types/proxy';
|
||||
import { getAllProxyConfigs, getProxyConfig, enableProxyConfig, disableAllProxies } from './storage';
|
||||
import { getAllProxyConfigs, getProxyConfig, enableProxyConfig, disableAllProxies, getCurrentProxy, setCurrentProxy } from './storage';
|
||||
|
||||
/**
|
||||
* 获取当前激活的代理模式
|
||||
@@ -8,10 +8,19 @@ import { getAllProxyConfigs, getProxyConfig, enableProxyConfig, disableAllProxie
|
||||
*/
|
||||
export async function getCurrentProxyMode(): Promise<string> {
|
||||
try {
|
||||
// 首先尝试从当前代理存储中获取
|
||||
const currentProxyConfig = await getCurrentProxy();
|
||||
if (currentProxyConfig) {
|
||||
return currentProxyConfig.id;
|
||||
}
|
||||
|
||||
// 如果没有当前代理记录,则从配置列表查找已启用的代理
|
||||
const configs = await getAllProxyConfigs();
|
||||
const enabledProxy = configs.find(config => config.enabled);
|
||||
|
||||
if (enabledProxy) {
|
||||
// 如果找到已启用的代理,更新当前代理存储
|
||||
await setCurrentProxy(enabledProxy);
|
||||
return enabledProxy.id;
|
||||
}
|
||||
|
||||
@@ -30,23 +39,6 @@ export async function getCurrentProxyMode(): Promise<string> {
|
||||
*/
|
||||
export async function switchProxyMode(mode: string): Promise<boolean> {
|
||||
try {
|
||||
if (mode === 'direct') {
|
||||
// 清除所有代理设置
|
||||
await disableAllProxies();
|
||||
await browser.proxy.settings.clear({});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mode === 'system') {
|
||||
// 使用系统代理
|
||||
await disableAllProxies();
|
||||
await browser.proxy.settings.set({
|
||||
value: { mode: 'system' },
|
||||
scope: 'regular'
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// 使用自定义代理
|
||||
const config = await getProxyConfig(mode);
|
||||
if (!config) {
|
||||
@@ -59,14 +51,16 @@ export async function switchProxyMode(mode: string): Promise<boolean> {
|
||||
|
||||
// 设置代理
|
||||
if (config.proxyType === 'direct') {
|
||||
// 直接连接模式
|
||||
await browser.proxy.settings.clear({});
|
||||
} else if (config.proxyType === 'system') {
|
||||
// 系统代理模式
|
||||
await browser.proxy.settings.set({
|
||||
value: { mode: 'system' },
|
||||
scope: 'regular'
|
||||
});
|
||||
} else {
|
||||
// 构建代理配置
|
||||
} else if (config.proxyType === 'fixed_servers') {
|
||||
// 固定服务器代理
|
||||
const proxyConfig = {
|
||||
mode: 'fixed_servers',
|
||||
rules: {}
|
||||
@@ -74,7 +68,7 @@ export async function switchProxyMode(mode: string): Promise<boolean> {
|
||||
|
||||
// 添加代理规则
|
||||
const proxyRule = {
|
||||
scheme: config.proxyType,
|
||||
scheme: config.scheme,
|
||||
host: config.host || '',
|
||||
port: config.port || 80
|
||||
};
|
||||
@@ -88,7 +82,7 @@ export async function switchProxyMode(mode: string): Promise<boolean> {
|
||||
// 设置代理规则
|
||||
proxyConfig.rules = {
|
||||
singleProxy: proxyRule,
|
||||
bypassList: ['localhost', '127.0.0.1']
|
||||
bypassList: config.bypassList || ['localhost', '127.0.0.1']
|
||||
};
|
||||
|
||||
// 应用代理设置
|
||||
@@ -96,6 +90,18 @@ export async function switchProxyMode(mode: string): Promise<boolean> {
|
||||
value: proxyConfig,
|
||||
scope: 'regular'
|
||||
});
|
||||
} else if (config.proxyType === 'pac_script') {
|
||||
// PAC脚本代理
|
||||
const pacConfig = {
|
||||
mode: 'pac_script',
|
||||
pacScript: config.pacScript
|
||||
};
|
||||
|
||||
// 应用PAC脚本设置
|
||||
await browser.proxy.settings.set({
|
||||
value: pacConfig,
|
||||
scope: 'regular'
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+186
-23
@@ -2,21 +2,35 @@ import type { ProxyConfig } from '../types/proxy';
|
||||
|
||||
// 数据库名称和存储名称
|
||||
const DB_NAME = 'yaklang_extension';
|
||||
const PROXY_STORE_NAME = 'proxy_configs';
|
||||
const STORES = {
|
||||
PROXY_CONFIGS: 'proxy_configs', // 代理配置列表存储
|
||||
CURRENT_PROXY: 'current_proxy', // 当前代理配置存储
|
||||
PROXY_AUTH: 'proxy_auth' // 代理认证信息存储
|
||||
};
|
||||
|
||||
const DB_VERSION = 2; // 增加版本号以触发数据库升级
|
||||
|
||||
// 打开数据库
|
||||
async function openDB(): Promise<IDBDatabase> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(DB_NAME, 1);
|
||||
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
|
||||
request.onupgradeneeded = (event) => {
|
||||
const db = (event.target as IDBOpenDBRequest).result;
|
||||
|
||||
// 如果存储不存在,创建它
|
||||
if (!db.objectStoreNames.contains(PROXY_STORE_NAME)) {
|
||||
db.createObjectStore(PROXY_STORE_NAME, { keyPath: 'id' });
|
||||
// 检查并创建各个存储对象
|
||||
if (!db.objectStoreNames.contains(STORES.PROXY_CONFIGS)) {
|
||||
db.createObjectStore(STORES.PROXY_CONFIGS, { keyPath: 'id' });
|
||||
}
|
||||
|
||||
if (!db.objectStoreNames.contains(STORES.CURRENT_PROXY)) {
|
||||
db.createObjectStore(STORES.CURRENT_PROXY, { keyPath: 'id' });
|
||||
}
|
||||
|
||||
if (!db.objectStoreNames.contains(STORES.PROXY_AUTH)) {
|
||||
db.createObjectStore(STORES.PROXY_AUTH, { keyPath: 'id' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,8 +43,8 @@ export async function getAllProxyConfigs(): Promise<ProxyConfig[]> {
|
||||
try {
|
||||
const db = await openDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([PROXY_STORE_NAME], 'readonly');
|
||||
const store = transaction.objectStore(PROXY_STORE_NAME);
|
||||
const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readonly');
|
||||
const store = transaction.objectStore(STORES.PROXY_CONFIGS);
|
||||
const request = store.getAll();
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
@@ -47,8 +61,8 @@ export async function getProxyConfig(id: string): Promise<ProxyConfig | null> {
|
||||
try {
|
||||
const db = await openDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([PROXY_STORE_NAME], 'readonly');
|
||||
const store = transaction.objectStore(PROXY_STORE_NAME);
|
||||
const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readonly');
|
||||
const store = transaction.objectStore(STORES.PROXY_CONFIGS);
|
||||
const request = store.get(id);
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
@@ -65,12 +79,18 @@ export async function saveProxyConfig(config: ProxyConfig): Promise<boolean> {
|
||||
try {
|
||||
const db = await openDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([PROXY_STORE_NAME], 'readwrite');
|
||||
const store = transaction.objectStore(PROXY_STORE_NAME);
|
||||
const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readwrite');
|
||||
const store = transaction.objectStore(STORES.PROXY_CONFIGS);
|
||||
const request = store.put(config);
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(true);
|
||||
request.onsuccess = () => {
|
||||
// 如果代理被启用,更新当前代理
|
||||
if (config.enabled) {
|
||||
setCurrentProxy(config).catch(console.error);
|
||||
}
|
||||
resolve(true);
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error saving proxy config:', error);
|
||||
@@ -78,13 +98,70 @@ export async function saveProxyConfig(config: ProxyConfig): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
// 批量保存代理配置
|
||||
export async function saveProxyConfigs(configs: ProxyConfig[]): Promise<boolean> {
|
||||
try {
|
||||
const db = await openDB();
|
||||
const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readwrite');
|
||||
const store = transaction.objectStore(STORES.PROXY_CONFIGS);
|
||||
|
||||
// 获取所有现有配置
|
||||
const existingConfigs = await getAllProxyConfigs();
|
||||
|
||||
// 保留固定模式配置(direct和system)
|
||||
const fixedModeConfigs = existingConfigs.filter(config =>
|
||||
config.id === 'direct' || config.id === 'system'
|
||||
);
|
||||
|
||||
// 确保新保存的配置不会覆盖固定模式的enabled状态
|
||||
const nonFixedConfigs = configs.filter(config =>
|
||||
config.id !== 'direct' && config.id !== 'system'
|
||||
);
|
||||
|
||||
// 合并配置
|
||||
const allConfigs = [...fixedModeConfigs, ...nonFixedConfigs];
|
||||
|
||||
// 更新enabled状态
|
||||
const updatedConfigs = allConfigs.map(config => ({
|
||||
...config,
|
||||
enabled: configs.some(c => c.id === config.id && c.enabled)
|
||||
}));
|
||||
|
||||
// 清除所有配置
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const clearRequest = store.clear();
|
||||
clearRequest.onerror = () => reject(clearRequest.error);
|
||||
clearRequest.onsuccess = () => resolve();
|
||||
});
|
||||
|
||||
// 保存所有配置
|
||||
for (const config of updatedConfigs) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const putRequest = store.put(config);
|
||||
putRequest.onerror = () => reject(putRequest.error);
|
||||
putRequest.onsuccess = () => resolve();
|
||||
});
|
||||
|
||||
// 如果代理被启用,更新当前代理
|
||||
if (config.enabled) {
|
||||
await setCurrentProxy(config);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error saving proxy configs:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 删除代理配置
|
||||
export async function deleteProxyConfig(id: string): Promise<boolean> {
|
||||
try {
|
||||
const db = await openDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([PROXY_STORE_NAME], 'readwrite');
|
||||
const store = transaction.objectStore(PROXY_STORE_NAME);
|
||||
const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readwrite');
|
||||
const store = transaction.objectStore(STORES.PROXY_CONFIGS);
|
||||
const request = store.delete(id);
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
@@ -96,16 +173,99 @@ export async function deleteProxyConfig(id: string): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
// 设置当前代理
|
||||
export async function setCurrentProxy(proxy: ProxyConfig): Promise<boolean> {
|
||||
try {
|
||||
const db = await openDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORES.CURRENT_PROXY], 'readwrite');
|
||||
const store = transaction.objectStore(STORES.CURRENT_PROXY);
|
||||
const request = store.put({ ...proxy, id: 'current' });
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(true);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error setting current proxy:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前代理
|
||||
export async function getCurrentProxy(): Promise<ProxyConfig | null> {
|
||||
try {
|
||||
const db = await openDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORES.CURRENT_PROXY], 'readonly');
|
||||
const store = transaction.objectStore(STORES.CURRENT_PROXY);
|
||||
const request = store.get('current');
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(request.result || null);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error getting current proxy:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 清除当前代理
|
||||
export async function clearCurrentProxy(): Promise<boolean> {
|
||||
try {
|
||||
const db = await openDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORES.CURRENT_PROXY], 'readwrite');
|
||||
const store = transaction.objectStore(STORES.CURRENT_PROXY);
|
||||
const request = store.delete('current');
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(true);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error clearing current proxy:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 启用指定的代理,禁用其他
|
||||
export async function enableProxyConfig(id: string): Promise<boolean> {
|
||||
try {
|
||||
// 获取所有配置
|
||||
const configs = await getAllProxyConfigs();
|
||||
|
||||
for (const config of configs) {
|
||||
const updated = { ...config, enabled: config.id === id };
|
||||
await saveProxyConfig(updated);
|
||||
// 查找目标代理
|
||||
const targetProxy = configs.find(config => config.id === id);
|
||||
if (!targetProxy) {
|
||||
console.error(`找不到ID为 ${id} 的代理配置`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 创建更新后的代理配置
|
||||
const updatedConfigs = configs.map(config => ({
|
||||
...config,
|
||||
enabled: config.id === id
|
||||
}));
|
||||
|
||||
// 保存到数据库
|
||||
const db = await openDB();
|
||||
const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readwrite');
|
||||
const store = transaction.objectStore(STORES.PROXY_CONFIGS);
|
||||
|
||||
// 逐个更新配置
|
||||
for (const config of updatedConfigs) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const request = store.put(config);
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve();
|
||||
});
|
||||
}
|
||||
|
||||
// 设置当前代理
|
||||
await setCurrentProxy({
|
||||
...targetProxy,
|
||||
enabled: true
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`Error enabling proxy config ${id}:`, error);
|
||||
@@ -117,13 +277,16 @@ export async function enableProxyConfig(id: string): Promise<boolean> {
|
||||
export async function disableAllProxies(): Promise<boolean> {
|
||||
try {
|
||||
const configs = await getAllProxyConfigs();
|
||||
const updatedConfigs = configs.map(config => ({
|
||||
...config,
|
||||
enabled: false
|
||||
}));
|
||||
|
||||
for (const config of configs) {
|
||||
if (config.enabled) {
|
||||
const updated = { ...config, enabled: false };
|
||||
await saveProxyConfig(updated);
|
||||
}
|
||||
}
|
||||
// 保存更新后的配置列表
|
||||
await saveProxyConfigs(updatedConfigs);
|
||||
|
||||
// 清除当前代理
|
||||
await clearCurrentProxy();
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user