import { IpcChannel } from '@shared/IpcChannel' import { ipcMain } from 'electron' import { EventEmitter } from 'events' import { windowService } from './WindowService' type StoreValue = any type Unsubscribe = () => void export class ReduxService extends EventEmitter { private stateCache: any = {} private isReady = false private readonly STATUS_CHANGE_EVENT = 'statusChange' constructor() { super() this.setupIpcHandlers() } private setupIpcHandlers() { // 监听 store 就绪事件 ipcMain.handle(IpcChannel.ReduxStoreReady, () => { this.isReady = true this.emit('ready') }) // 监听 store 状态变化 ipcMain.on(IpcChannel.ReduxStateChange, (_, newState) => { this.stateCache = newState this.emit(this.STATUS_CHANGE_EVENT, newState) }) } private async waitForStoreReady(webContents: Electron.WebContents, timeout = 10000): Promise { if (this.isReady) return const startTime = Date.now() while (Date.now() - startTime < timeout) { try { const isReady = await webContents.executeJavaScript(` !!window.store && typeof window.store.getState === 'function' `) if (isReady) { this.isReady = true return } } catch (error) { // 忽略错误,继续等待 } await new Promise((resolve) => setTimeout(resolve, 100)) } throw new Error('Timeout waiting for Redux store to be ready') } // 添加同步获取状态的方法 getStateSync() { return this.stateCache } // 添加同步选择器方法 selectSync(selector: string): T | undefined { try { // 使用 Function 构造器来安全地执行选择器 const selectorFn = new Function('state', `return ${selector}`) return selectorFn(this.stateCache) } catch (error) { console.error('Failed to select from cache:', error) return undefined } } // 修改 select 方法,优先使用缓存 async select(selector: string): Promise { try { // 如果已经准备就绪,先尝试从缓存中获取 if (this.isReady) { const cachedValue = this.selectSync(selector) if (cachedValue !== undefined) { return cachedValue } } // 如果缓存中没有,再从渲染进程获取 const mainWindow = windowService.getMainWindow() if (!mainWindow) { throw new Error('Main window is not available') } await this.waitForStoreReady(mainWindow.webContents) return await mainWindow.webContents.executeJavaScript(` (() => { const state = window.store.getState(); return ${selector}; })() `) } catch (error) { console.error('Failed to select store value:', error) throw error } } // 派发 action async dispatch(action: any): Promise { const mainWindow = windowService.getMainWindow() if (!mainWindow) { throw new Error('Main window is not available') } await this.waitForStoreReady(mainWindow.webContents) try { await mainWindow.webContents.executeJavaScript(` window.store.dispatch(${JSON.stringify(action)}) `) } catch (error) { console.error('Failed to dispatch action:', error) throw error } } // 订阅状态变化 async subscribe(selector: string, callback: (newValue: any) => void): Promise { const mainWindow = windowService.getMainWindow() if (!mainWindow) { throw new Error('Main window is not available') } await this.waitForStoreReady(mainWindow.webContents) // 在渲染进程中设置监听 await mainWindow.webContents.executeJavaScript( ` if (!window._storeSubscriptions) { window._storeSubscriptions = new Set(); // 设置全局状态变化监听 const unsubscribe = window.store.subscribe(() => { const state = window.store.getState(); window.electron.ipcRenderer.send('` + IpcChannel.ReduxStateChange + `', state); }); window._storeSubscriptions.add(unsubscribe); } ` ) // 在主进程中处理回调 const handler = async () => { try { const newValue = await this.select(selector) callback(newValue) } catch (error) { console.error('Error in subscription handler:', error) } } this.on(this.STATUS_CHANGE_EVENT, handler) return () => { this.off(this.STATUS_CHANGE_EVENT, handler) } } // 获取整个状态树 async getState(): Promise { const mainWindow = windowService.getMainWindow() if (!mainWindow) { throw new Error('Main window is not available') } await this.waitForStoreReady(mainWindow.webContents) try { return await mainWindow.webContents.executeJavaScript(` window.store.getState() `) } catch (error) { console.error('Failed to get state:', error) throw error } } // 批量执行 actions async batch(actions: any[]): Promise { for (const action of actions) { await this.dispatch(action) } } } export const reduxService = new ReduxService() /** example async function example() { try { // 读取状态 const settings = await reduxService.select('state.settings') console.log('settings', settings) // 派发 action await reduxService.dispatch({ type: 'settings/updateApiKey', payload: 'new-api-key' }) // 订阅状态变化 const unsubscribe = await reduxService.subscribe('state.settings.apiKey', (newValue) => { console.log('API key changed:', newValue) }) // 批量执行 actions await reduxService.batch([ { type: 'action1', payload: 'data1' }, { type: 'action2', payload: 'data2' } ]) // 同步方法虽然可能不是最新的数据,但响应更快 const apiKey = reduxService.selectSync('state.settings.apiKey') console.log('apiKey', apiKey) // 处理保证是最新的数据 const apiKey1 = await reduxService.select('state.settings.apiKey') console.log('apiKey1', apiKey1) // 取消订阅 unsubscribe() } catch (error) { console.error('Error:', error) } } */