mirror of
https://github.com/ValueCell-ai/ClawX.git
synced 2026-08-14 08:53:09 +00:00
134 lines
4.3 KiB
TypeScript
134 lines
4.3 KiB
TypeScript
import type { CompleteHostServiceRegistry } from '../main/ipc/host-contract';
|
|
import type { GatewayManager } from '../gateway/manager';
|
|
import { syncLaunchAtStartupSettingFromStore } from '../main/launch-at-startup';
|
|
import { createMenu } from '../main/menu';
|
|
import { applyProxySettings } from '../main/proxy';
|
|
import { syncProxyConfigToOpenClaw } from '../utils/openclaw-proxy';
|
|
import {
|
|
type AppSettings,
|
|
getAllSettings,
|
|
getSetting,
|
|
resetSettings,
|
|
setSetting,
|
|
} from '../utils/store';
|
|
import { isRecord } from './payload-utils';
|
|
|
|
type KeyPayload = {
|
|
key?: unknown;
|
|
};
|
|
|
|
type SetPayload = KeyPayload & {
|
|
value?: unknown;
|
|
};
|
|
|
|
type SetManyPayload = {
|
|
patch?: unknown;
|
|
};
|
|
|
|
const PROXY_SETTING_KEYS = new Set<keyof AppSettings>([
|
|
'proxyEnabled',
|
|
'proxyServer',
|
|
'proxyHttpServer',
|
|
'proxyHttpsServer',
|
|
'proxyAllServer',
|
|
'proxyBypassRules',
|
|
]);
|
|
|
|
async function validateSettingKey(key: unknown): Promise<boolean> {
|
|
if (typeof key !== 'string' || key.length === 0) return false;
|
|
const settings = await getAllSettings();
|
|
return Object.prototype.hasOwnProperty.call(settings, key);
|
|
}
|
|
|
|
async function requireSettingKey(payload: unknown): Promise<keyof AppSettings> {
|
|
const key = (payload as KeyPayload | undefined)?.key;
|
|
if (!await validateSettingKey(key)) {
|
|
throw new Error('Invalid settings key');
|
|
}
|
|
return key as keyof AppSettings;
|
|
}
|
|
|
|
async function requireSettingsPatch(payload: unknown): Promise<Partial<AppSettings>> {
|
|
const patch = (payload as SetManyPayload | undefined)?.patch;
|
|
if (!isRecord(patch)) {
|
|
throw new Error('Invalid settings patch');
|
|
}
|
|
const entries = Object.entries(patch);
|
|
for (const [key] of entries) {
|
|
if (!await validateSettingKey(key)) {
|
|
throw new Error('Invalid settings key');
|
|
}
|
|
}
|
|
return Object.fromEntries(entries) as Partial<AppSettings>;
|
|
}
|
|
|
|
function patchTouchesProxy(patch: Partial<AppSettings>): boolean {
|
|
return Object.keys(patch).some((key) => PROXY_SETTING_KEYS.has(key as keyof AppSettings));
|
|
}
|
|
|
|
function patchTouchesLaunchAtStartup(patch: Partial<AppSettings>): boolean {
|
|
return Object.prototype.hasOwnProperty.call(patch, 'launchAtStartup');
|
|
}
|
|
|
|
function patchTouchesLanguage(patch: Partial<AppSettings>): boolean {
|
|
return Object.prototype.hasOwnProperty.call(patch, 'language');
|
|
}
|
|
|
|
async function handleProxySettingsChange(gatewayManager: GatewayManager): Promise<void> {
|
|
const settings = await getAllSettings();
|
|
await syncProxyConfigToOpenClaw(settings, { preserveExistingWhenDisabled: false });
|
|
await applyProxySettings(settings);
|
|
if (gatewayManager.getStatus().state === 'running') {
|
|
await gatewayManager.restart();
|
|
}
|
|
}
|
|
|
|
async function runSettingsSideEffects(
|
|
gatewayManager: GatewayManager,
|
|
patch: Partial<AppSettings>,
|
|
): Promise<void> {
|
|
if (patchTouchesProxy(patch)) {
|
|
await handleProxySettingsChange(gatewayManager);
|
|
}
|
|
if (patchTouchesLaunchAtStartup(patch)) {
|
|
await syncLaunchAtStartupSettingFromStore();
|
|
}
|
|
if (patchTouchesLanguage(patch)) {
|
|
await createMenu(typeof patch.language === 'string' ? patch.language : undefined);
|
|
}
|
|
}
|
|
|
|
export function createSettingsApi(gatewayManager: GatewayManager): CompleteHostServiceRegistry['settings'] {
|
|
return {
|
|
getAll: () => getAllSettings(),
|
|
get: async (payload) => {
|
|
const key = await requireSettingKey(payload);
|
|
return getSetting(key as never);
|
|
},
|
|
set: async (payload) => {
|
|
const body = payload as SetPayload | undefined;
|
|
const key = await requireSettingKey(body);
|
|
await setSetting(key as never, body?.value as never);
|
|
await runSettingsSideEffects(gatewayManager, { [key]: body?.value } as Partial<AppSettings>);
|
|
return { success: true };
|
|
},
|
|
setMany: async (payload) => {
|
|
const patch = await requireSettingsPatch(payload);
|
|
const entries = Object.entries(patch) as Array<[keyof AppSettings, AppSettings[keyof AppSettings]]>;
|
|
for (const [key, value] of entries) {
|
|
await setSetting(key, value as never);
|
|
}
|
|
await runSettingsSideEffects(gatewayManager, patch);
|
|
return { success: true };
|
|
},
|
|
reset: async () => {
|
|
await resetSettings();
|
|
await handleProxySettingsChange(gatewayManager);
|
|
await syncLaunchAtStartupSettingFromStore();
|
|
const settings = await getAllSettings();
|
|
await createMenu(settings.language);
|
|
return { success: true, settings };
|
|
},
|
|
};
|
|
}
|