跳到正文
灵动桌面框架
Esc
本栏目菜单

三层架构

灵动桌面框架的 Rust 后端(src-tauri/src/)以「Command → Service → Database」三层为主干,models、state、error 作为各层共用的支撑模块,托盘、远程网关等能力独立成模块,确保代码职责清晰、易于维护。

架构图

┌─────────────────────────────────────────┐
│  前端 invoke('set_config', {...})       │
└──────────────────┬──────────────────────┘
                   ↓
┌──────────────────────────────────────────┐
│  Layer 1: Commands(命令层)              │
│  ● 接收 IPC 请求、注入 State             │
│  ● 调用 Service 层、转换错误类型         │
└──────────────────┬───────────────────────┘
                   ↓
┌──────────────────────────────────────────┐
│  Layer 2: Services(业务层)              │
│  ● 参数校验、业务规则(如“不存在”判定)  │
│  ● 调用 Database 层                      │
└──────────────────┬───────────────────────┘
                   ↓
┌──────────────────────────────────────────┐
│  Layer 3: Database(数据层)              │
│  ● SQL 操作、Schema 迁移                 │
└──────────────────────────────────────────┘

目录与职责

层级 / 模块位置职责错误类型
Commandsrc-tauri/src/commands/IPC 入口(system.rs、config.rs),从 tauri::State 取出数据库后转发给 ServiceCommandError
Servicesrc-tauri/src/services/业务逻辑(config.rs);另含主窗口显示器记忆 main_window_placement.rsAppError
Databasesrc-tauri/src/database/mod.rs 封装 Database(Mutex<Connection>)与配置 DAO,schema.rs 负责版本迁移AppError
Modelssrc-tauri/src/models/mod.rs前后端共用的数据结构:AppConfig、SystemInfo-
Statesrc-tauri/src/state.rs全局状态 AppState { db },在 setup 中 app.manage(...) 注册-
Errorsrc-tauri/src/error.rsAppError(内部)与 CommandError(前端可见)及其转换-
入口src-tauri/src/lib.rs注册插件、初始化数据库 / 托盘 / 窗口、注册 Command、处理窗口事件-

不属于三层主干、但同样在 lib.rs 中声明的模块:

模块位置说明
系统托盘src-tauri/src/tray.rs托盘图标与「显示窗口 / 退出」菜单
通用工具src-tauri/src/shared/与业务无关的工具函数(如 time_utils)
远程网关src-tauri/src/remote/面向移动端伴侣的 HTTP 网关骨架,默认不启动

调用流程示例

前端: configApi.set('theme', 'dark')           // src/lib/api/config.ts
  → invoke('set_config', { key, value })
    → Command 层: commands::config::set_config  // 取 state.db,转发
      → Service 层: ConfigService::set          // 校验 key 非空
        → Database 层: Database::set_config     // INSERT ... ON CONFLICT(key) DO UPDATE

启动流程

lib.rs 的 run() 按以下顺序组装应用:

  1. 注册插件:single-instance(必须第一个,禁止多开,二次启动时唤回已有窗口)、opener、store、log、updater、process
  2. setup:在 app_data_dir 下打开数据库(开发环境 dev-app.db,生产环境 app.db)并执行迁移 → app.manage(AppState::new(db)) → 初始化托盘 → 把主窗口摆回上次所在的显示器后再显示 → 开发模式给窗口标题加 [DEV] 后缀
  3. invoke_handler 注册 Command
  4. on_window_event:主窗口事件交给 main_window_placement 记录位置;点击关闭按钮时隐藏到托盘而不是退出

开发规范

  • Command 层不写业务逻辑,只做 State 注入、转发与错误转换
  • 参数校验与业务规则放在 Service 层(如 ConfigService::set 拒绝空键)
  • Service 层不写 SQL,只调用 Database 方法
  • Database 层不写业务逻辑,只做数据访问
  • 禁止跨层调用(Command 直接调 Database)