Skip to content

IPC 系统

IPC 通道是主进程对外暴露能力的标准方式。模板把它做成了一个可测试、可扩展的微框架

三个核心抽象

抽象文件作用
Containercore/container.js极简 DI,注册键值或工厂
IpcRoutercore/ipc-router.js把 channel 字符串映射到 handler
Middlewarecore/middlewares/*.js洋葱模型,每个 handler 共享

装配流程

入口在 electron/main/ipc/index.js

js
export function setupIpc({ pythonService }) {
  const logger = Logger.getInstance()
  const container = getContainer()

  container.register('python', pythonService)
  container.register('bridge', () => getBridgeManager())
  container.register('logger', logger)

  const router = new IpcRouter({ container, logger })

  router
    .use(errorBoundary())
    .use(logging())
    .use(timing())
    .use(metrics())
    .use(validate())

  router.registerAll(allModules)

  logger.info(
    `[ipc] all modules ready, modules=${allModules.length} channels=${router.listChannels().length}`
  )
  return router
}

容器里常用的键:

key类型说明
pythonPythonService进程状态、URL、重启
bridge工厂 → BridgeManager反向通道管理
loggerLogger单例日志
mainWindowBrowserWindow在 createWindow 时写入

中间件管道

注册顺序即执行顺序,洋葱模型从外向内:

errorBoundary → logging → timing → metrics → validate → handler
中间件责任
errorBoundary把 handler 抛的异常转成统一响应 { ok: false, error: { code, message } }
logging进入与离开记一行日志,含 channel 与耗时
timing注入 ctx.startedAt,timing.end() 反向写回结果 meta
metrics收集 channel 调用次数、平均耗时(可 expose 给运维)
validate若模块声明了 schema,按 zod 校验入参

handler 拿到的上下文 ctx

js
async (ctx) => {
  ctx.deps          // 注入的依赖对象(按 deps: [...] 声明)
  ctx.payload       // 入参(已校验)
  ctx.event         // 原始 IpcMainInvokeEvent
  ctx.logger        // 子 logger(带 channel 前缀)
  return data       // 返回值会被包装成 { ok: true, data }
}

模块自动发现

electron/main/ipc/modules/index.js

js
const modules = import.meta.glob('./**/*.module.js', { eager: true })

export default Object.values(modules)
  .map((m) => m.default)
  .filter(Boolean)

新增能力只需新建 modules/<域>/<feature>.module.js,导出 default:

js
// electron/main/ipc/modules/python/python.module.js
export default {
  name: 'python',
  handlers: [
    {
      channel: 'python:get-backend-url',
      deps: ['python'],
      handler: (_ctx, { python }) => python.getBackendBaseUrl()
    },
    {
      channel: 'python:get-status',
      deps: ['python'],
      handler: (_ctx, { python }) => python.getStatus()
    }
  ]
}

Vite 编译期就把 glob 解析成静态 import 数组,运行时零开销。

现有四个业务域

文件提供的 channel
modules/python/python.module.jspython:get-backend-urlpython:get-statuspython:health-checkpython:restartpython:is-daemon-mode
modules/bridge/bridge.module.jsbridge:ensure-connectionbridge:get-statusbridge:disconnectbridge:get-stats
modules/dialog/dialog.module.jsdialog:select-directory
modules/system/system.module.jssystem:get-app-info

渲染端调用

web/src/api/ipc/python.js 提供薄封装:

js
const ipc = window.electron.ipcRenderer

export const getBackendUrl = () => ipc.invoke('python:get-backend-url')
export const getStatus = () => ipc.invoke('python:get-status')

约定:所有 IPC 都通过 invoke 走,返回 { ok, data }{ ok: false, error: { code, message } }

基于 MIT 协议发布