Files
zn-ai/electron/service/config-service.ts
DEV_DSW 416399e7a8 feat: implement menu service for context menu management
feat: add provider API service for managing provider accounts and keys
feat: create provider runtime sync service for agent runtime management
feat: introduce script execution service for running automation scripts
feat: develop script store service for managing script metadata and storage
feat: implement theme service for managing application theme settings
feat: add updater service for handling application updates
feat: create window service for managing application windows and their states
2026-04-22 09:26:39 +08:00

134 lines
4.0 KiB
TypeScript

import { BrowserWindow, ipcMain } from 'electron'
import { CONFIG_KEYS, IPC_EVENTS } from '@runtime/lib/constants'
import logManager from '@electron/service/logger'
import type { ConfigKeys, IConfig } from '@electron/types/runtime'
import { getUserDataDir } from '@electron/utils/paths'
import { debounce } from '@electron/utils/shared'
type AppConfig = IConfig & {
[CONFIG_KEYS.GATEWAY_AUTO_START]: boolean;
};
const DEFAULT_CONFIG: AppConfig = {
[CONFIG_KEYS.THEME_MODE]: 'system',
[CONFIG_KEYS.PRIMARY_COLOR]: '#BB5BE7',
[CONFIG_KEYS.LANGUAGE]: 'zh',
[CONFIG_KEYS.FONT_SIZE]: 14,
[CONFIG_KEYS.MINIMIZE_TO_TRAY]: false,
[CONFIG_KEYS.LAUNCH_AT_STARTUP]: false,
[CONFIG_KEYS.PROVIDER]: '',
[CONFIG_KEYS.DEFAULT_MODEL]: null,
[CONFIG_KEYS.SELECTED_CHANNELS]: [],
[CONFIG_KEYS.IMAGE_CACHE]: [],
[CONFIG_KEYS.TASK_LIST]: [],
[CONFIG_KEYS.GATEWAY_AUTO_START]: true,
}
export class ConfigService {
private static _instance: ConfigService;
private _store: any;
private _defaultConfig: AppConfig = DEFAULT_CONFIG;
private _listeners: Array<(config: AppConfig) => void> = [];
private constructor() {
// store 通过 init() 异步初始化,避免 ESM 模块在 CJS 打包环境中同步导入的问题
}
public async init() {
if (this._store) return;
const { default: Store } = await import('electron-store');
this._store = new Store<AppConfig>({
name: 'config',
cwd: getUserDataDir(),
defaults: DEFAULT_CONFIG,
});
this._setupIpcEvents();
logManager.info('ConfigService initialized successfully.')
}
private _ensureStore() {
if (!this._store) {
throw new Error('ConfigService has not been initialized. Call init() first.');
}
}
private _setupIpcEvents() {
const duration = 200;
const handelUpdate = debounce((val) => this.update(val), duration);
ipcMain.handle(IPC_EVENTS.GET_CONFIG, (_, key) => this.get(key));
ipcMain.handle(IPC_EVENTS.SET_CONFIG, (_, key, val) => {
this.set(key, val);
return { success: true };
});
ipcMain.on(IPC_EVENTS.UPDATE_CONFIG, (_, updates) => handelUpdate(updates));
}
public static getInstance(): ConfigService {
if (!this._instance) {
this._instance = new ConfigService();
}
return this._instance;
}
private _notifyListeners(): void {
this._ensureStore();
BrowserWindow.getAllWindows().forEach(win => win.webContents.send(IPC_EVENTS.CONFIG_UPDATED, this._store.store));
this._listeners.forEach(listener => listener({ ...this._store.store }));
}
public getConfig(): AppConfig {
if (!this._store) {
return { ...this._defaultConfig };
}
return this._store.store;
}
public get<T = any>(key: ConfigKeys): T {
if (!this._store) {
return this._defaultConfig[key] as T;
}
return this._store.get(key) as T
}
public set(key: ConfigKeys, value: unknown, autoSave: boolean = true): void {
this._ensureStore();
const oldValue = this._store.get(key);
if (oldValue === value) return;
this._store.set(key, value);
logManager.info(`Config set: ${key} = ${JSON.stringify(value)}`);
logManager.info(`Config file path: ${this._store.path}`);
autoSave && this._notifyListeners();
}
public update(updates: Partial<AppConfig>, autoSave: boolean = true): void {
this._ensureStore();
(Object.keys(updates) as ConfigKeys[]).forEach((key) => {
this._store.set(key, updates[key]);
});
autoSave && this._notifyListeners();
}
public resetToDefault(): void {
this._ensureStore();
(Object.keys(this._defaultConfig) as ConfigKeys[]).forEach((key) => {
this._store.set(key, this._defaultConfig[key]);
});
logManager.info('Config reset to default.');
this._notifyListeners();
}
public onConfigChange(listener: ((config: AppConfig) => void)): () => void {
this._listeners.push(listener);
return () => this._listeners = this._listeners.filter(l => l !== listener);
}
}
export const configManager = ConfigService.getInstance();
export default configManager;