Files
yaklang-chrome-extension/src/app/background/handlers/proxy.ts
T

117 lines
4.9 KiB
TypeScript

import type { BackgroundRequestHandler } from '../router';
import { ok } from '../response';
import {
applyProxyRules,
clearCurrentSiteRoute,
compileCurrentProxyRules,
dirtyProxyState,
exportProxyConfiguration,
getProxyRuleSourcePage,
hasProxyAuthPassword,
importProxyConfiguration,
previewCurrentProxyRules,
refreshProxyRuleSource,
removeProxyProfile,
removeProxyRuleSource,
routeCurrentSite,
saveProxyProfile,
saveProxyRuleSource,
setProxyAuthPassword,
switchProxy,
} from '@/features/proxy/service';
import { updateState } from '@/platform/storage/state';
export const handleProxyRequest: BackgroundRequestHandler = async (request) => {
switch (request.action) {
case 'proxy.save': return ok(await saveProxyProfile(request.payload));
case 'proxy.delete': return ok(await removeProxyProfile(request.payload.id));
case 'proxy.switch': return ok(await switchProxy(request.payload.id));
case 'proxy.rule.save': {
const rule = request.payload;
return ok(await updateState((state) => {
if (!state.proxyProfiles.some((profile) => profile.id === rule.proxyProfileId
&& ['direct', 'fixed_servers'].includes(profile.kind))) {
throw new Error('规则 PAC 只能使用直接连接或固定代理出口');
}
return dirtyProxyState({
...state,
proxyRules: [...state.proxyRules.filter((item) => item.id !== rule.id), rule],
});
}));
}
case 'proxy.rule.delete': {
const { id } = request.payload;
return ok(await updateState((state) => dirtyProxyState({
...state,
proxyRules: state.proxyRules.filter((item) => item.id !== id),
})));
}
case 'proxy.auto.apply': return ok(await applyProxyRules());
case 'proxy.rules.preview': return ok(await previewCurrentProxyRules(request.payload.url));
case 'proxy.rules.compile': return ok(await compileCurrentProxyRules());
case 'proxy.rules.reorder': {
const ids = request.payload.ids;
return ok(await updateState((current) => {
if (ids.length !== current.proxyRules.length || new Set(ids).size !== ids.length
|| ids.some((id) => !current.proxyRules.some((rule) => rule.id === id))) {
throw new Error('规则排序必须包含当前全部规则且不能重复');
}
const byId = new Map(current.proxyRules.map((rule) => [rule.id, rule]));
return dirtyProxyState({
...current,
proxyRules: ids.map((id, order) => ({
...byId.get(id)!, order, updatedAt: Date.now(),
})),
});
}));
}
case 'proxy.rules.settings': {
const input = request.payload;
return ok(await updateState((current) => {
if (!current.proxyProfiles.some((profile) => profile.id === input.defaultProfileId
&& ['direct', 'fixed_servers'].includes(profile.kind))) {
throw new Error('默认出口必须是直接连接或固定代理');
}
return dirtyProxyState({ ...current, proxyRouting: input });
}));
}
case 'proxy.source.save': return ok(await saveProxyRuleSource(request.payload));
case 'proxy.source.refresh': return ok(await refreshProxyRuleSource(request.payload.id));
case 'proxy.source.delete': return ok(await removeProxyRuleSource(request.payload.id));
case 'proxy.sources.reorder': {
const ids = request.payload.ids;
return ok(await updateState((current) => {
if (ids.length !== current.proxyRuleSources.length || new Set(ids).size !== ids.length
|| ids.some((id) => !current.proxyRuleSources.some((source) => source.id === id))) {
throw new Error('规则源排序必须包含当前全部订阅且不能重复');
}
const byId = new Map(current.proxyRuleSources.map((source) => [source.id, source]));
return dirtyProxyState({
...current,
proxyRuleSources: ids.map((id, order) => ({ ...byId.get(id)!, order })),
});
}));
}
case 'proxy.source.rules': return ok(await getProxyRuleSourcePage(
request.payload.id,
request.payload.offset,
request.payload.limit,
request.payload.query,
));
case 'proxy.site.route': return ok(await routeCurrentSite(
request.payload.url,
request.payload.profileId,
));
case 'proxy.site.route.clear': return ok(await clearCurrentSiteRoute(request.payload.url));
case 'proxy.auth.set':
await setProxyAuthPassword(request.payload.profileId, request.payload.password);
return ok({ configured: hasProxyAuthPassword(request.payload.profileId) });
case 'proxy.auth.status': return ok({
configured: hasProxyAuthPassword(request.payload.profileId),
});
case 'proxy.config.export': return ok(await exportProxyConfiguration());
case 'proxy.config.import': return ok(await importProxyConfiguration(request.payload.configuration));
default: return undefined;
}
};