# MeiliSearch Deep Dive

> **模块类型**: 搜索引擎 (searchEngine)  
> **模块标识**: `meilisearch`  
> **分析日期**: 2026-04-12  
> **FlyEnv 版本**: 4.13.2

---

## Overview

MeiliSearch 是一个开源的、快速的、支持 typo-tolerant 的搜索引擎。FlyEnv 通过模块化架构集成 MeiliSearch，提供服务生命周期管理、版本控制、配置管理和可视化界面。

相关文档链接:
- [Elasticsearch](./elasticsearch.md) - 同类搜索引擎模块
- [Base 基类](./base.md) - 服务模块基类实现
- [AppModuleTypeEnum](./type.md) - 模块类型系统

---

## Architecture

### Component Hierarchy

```
Renderer Process (Vue 3)
├── Index.vue                 # 主面板组件
│   ├── Service               # 服务控制面板
│   ├── Manager               # 版本管理器
│   ├── Config.vue            # 配置文件编辑器
│   └── Logs.vue              # 日志查看器
├── aside.vue                 # 侧边栏控制组件
├── Module.ts                 # 模块注册定义
└── setup.ts                  # 模块状态管理

Fork Process (Node.js)
└── MeiliSearch/index.ts      # 服务核心实现
    ├── _startServer()        # 服务启动
    ├── _stopServer()         # 服务停止 (继承 Base)
    ├── initConfig()          # 配置初始化
    ├── fetchAllOnlineVersion() # 在线版本获取
    └── allInstalledVersions()  # 本地版本扫描

Static Resources
└── tmpl/{platform}/
    └── meilisearch.toml      # 默认配置模板
```

### Data Flow Sequence

```
1. User Action (Toggle Service)
   │
   ▼
2. aside.vue - AsideSetup('meilisearch')
   │ IPC: app-fork:meilisearch startService
   ▼
3. Main Process → ForkManager
   │
   ▼
4. Fork Process - BaseManager.exec()
   │
   ▼
5. MeiliSearch.startService()
   ├── _stopServer()          # 先停止现有实例
   └── _startServer()         # 启动新实例
       ├── initConfig()       # 确保配置存在
       └── serviceStartExec() # 执行启动命令
```

Sources: src/render/components/MeiliSearch/aside.vue29-76 src/fork/module/MeiliSearch/index.ts62-126 src/fork/module/Base/index.ts88-121

---

## Data Model

### Module Registration

| Field | Type | Value | Description |
|-------|------|-------|-------------|
| `moduleType` | `AllAppModuleType` | `'searchEngine'` | 模块分类 |
| `typeFlag` | `AllAppModule` | `'meilisearch'` | 模块唯一标识 |
| `label` | `string` | `'Meilisearch'` | 显示名称 |
| `asideIndex` | `number` | `13` | 侧边栏排序索引 |
| `isService` | `boolean` | `true` | 是否为可启动服务 |
| `isTray` | `boolean` | `true` | 是否在托盘显示 |

Sources: src/render/components/MeiliSearch/Module.ts4-14 src/render/core/type.ts68

### State Management (setup.ts)

```typescript
interface MeiliSearchSetup {
  dir: Record<string, string>  // 工作目录映射: { [binPath]: workingDir }
  init(): void                 // 从 localForage 恢复状态
  save(): void                 // 持久化到 localForage
}
```

工作目录按版本隔离存储，使用版本号前两位作为子目录名（如 `1.12`）。

Sources: src/render/components/MeiliSearch/setup.ts1-26

### Common Configuration Item

| Field | Type | Description |
|-------|------|-------------|
| `name` | `string` | 配置项名称 (如 `http_addr`) |
| `value` | `string` | 默认值 |
| `enable` | `boolean` | 是否启用 |
| `type` | `string` | 分类: General/Network/Security/Performance/Backup/Experimental |
| `isString` | `boolean` | 值是否使用字符串引号包裹 |
| `isDir` | `boolean` | 是否为目录选择器 |
| `isFile` | `boolean` | 是否为文件选择器 |
| `options` | `Array<{label, value}>` | 下拉选项（如有） |
| `tips` | `function` | 提示文本函数 |

Sources: src/render/components/MeiliSearch/Config.vue46-451

---

## Core Components

### MeiliSearch Class (Fork Process)

继承自 `Base` 类，实现 MeiliSearch 特定的服务逻辑。

| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `init()` | - | `void` | 初始化 PID 文件路径 |
| `initConfig()` | - | `ForkPromise<string>` | 初始化配置文件，从模板复制 |
| `_startServer()` | `version: SoftInstalled, WORKING_DIR?: string` | `ForkPromise<void>` | 启动服务实例 |
| `fetchAllOnlineVersion()` | - | `ForkPromise<OnlineVersionItem[]>` | 获取可下载版本列表 |
| `allInstalledVersions()` | `setup: any` | `ForkPromise<SoftInstalled[]>` | 扫描本地已安装版本 |
| `_installSoftHandle()` | `row: any` | `Promise<void>` | 版本安装后处理 |
| `brewinfo()` | - | `ForkPromise<any>` | 获取 Homebrew 信息 |

Sources: src/fork/module/MeiliSearch/index.ts30-241

### Service Startup Parameters

```typescript
// macOS/Linux
const execArgs = `--config-file-path "${iniFile}"`

// Windows
const execArgs = `--config-file-path \`${iniFile}\``
```

启动时使用 `--config-file-path` 参数指定 TOML 配置文件路径，工作目录默认为 `{BaseDir}/meilisearch/{version}`。

Sources: src/fork/module/MeiliSearch/index.ts82-124

---

## Lifecycle Management

### Service Start Flow

```
startService() [Base]
    │
    ├──► _linkVersion()          # Homebrew 版本链接 (仅 macOS/Linux)
    │
    ├──► _stopServer()           # 停止现有实例
    │       ├── 读取 pid 文件
    │       ├── 进程搜索匹配
    │       └── 发送终止信号
    │
    └──► _startServer()          # 启动新实例
            │
            ├──► initConfig()    # 确保配置文件存在
            │       ├── 创建目录 {BaseDir}/meilisearch
            │       ├── 复制模板到 meilisearch.toml
            │       └── 复制模板到 meilisearch.default.toml
            │
            ├── 计算工作目录 (版本前两位)
            │
            └──► serviceStartExec() / serviceStartExecWin()
                    ├── 启动子进程
                    ├── 等待 PID 文件
                    └── 返回启动结果
```

Sources: src/fork/module/Base/index.ts88-121 src/fork/module/MeiliSearch/index.ts40-126

### Service Stop Flow

继承自 `Base._stopServer()`，通过以下方式定位进程：

1. **PID 文件**: `{BaseDir}/pid/meilisearch.pid`
2. **版本对象**: `version.pid` (如果存在)
3. **进程名称搜索**: 在进程列表中搜索 `meilisearch`

终止信号：
- Windows: `-INT`
- macOS/Linux: `-INT` (默认)

Sources: src/fork/module/Base/index.ts123-250

---

## Configuration System

### Configuration File Structure

配置文件位于 `{BaseDir}/meilisearch/meilisearch.toml`，采用 TOML 格式。

### Configuration Categories

| Category | Options | Description |
|----------|---------|-------------|
| **General** | `db_path`, `env`, `no_analytics`, `log_level` | 基础运行配置 |
| **Network** | `http_addr`, `http_payload_size_limit` | 网络监听配置 |
| **Security** | `master_key`, `ssl_*` | 认证与 SSL 配置 |
| **Performance** | `max_indexing_memory`, `max_indexing_threads` | 索引性能配置 |
| **Backup** | `dump_dir`, `snapshot_dir`, `import_*` | 数据备份与恢复 |
| **Experimental** | `experimental_enable_metrics`, `experimental_reduce_indexing_memory_usage` | 实验性功能 |

### Configuration UI (Config.vue)

采用双模式编辑器：
- **Common Mode**: 表单化配置项，支持开关、输入、选择器
- **Text Mode**: 直接编辑 TOML 文本

配置项同步机制：
1. 文本变更触发 `onTypeChange()`
2. 解析当前配置，更新 `commonSetting` 数组
3. 表单变更通过 `debounce(onSettingUpdate, 500)` 同步回文本

Sources: src/render/components/MeiliSearch/Config.vue1-534 static/tmpl/macOS/meilisearch.toml

---

## API/IPC Interface

### Command List

| Command | Parameters | Action | Returns |
|---------|-----------|--------|---------|
| `startService` | `version: SoftInstalled, WORKING_DIR?: string` | 启动服务 | `ForkPromise<void>` |
| `stopService` | `version: SoftInstalled` | 停止服务 | `ForkPromise<void>` |
| `initConfig` | - | 初始化配置文件 | `ForkPromise<string>` (配置文件路径) |
| `fetchAllOnlineVersion` | - | 获取在线版本 | `ForkPromise<OnlineVersionItem[]>` |
| `allInstalledVersions` | `setup: any` | 扫描本地版本 | `ForkPromise<SoftInstalled[]>` |
| `installSoft` | `row: any` | 安装版本 | `ForkPromise<boolean>` |
| `brewinfo` | - | Homebrew 信息 | `ForkPromise<any>` |

### IPC Communication Pattern

```typescript
// Renderer → Main → Fork
IPC.send('app-fork:meilisearch', 'startService', version, workingDir)
  .then((key: string) => {
    IPC.on(key, (msg: any) => {
      // 处理进度回调
    })
  })
```

进度事件类型：
- `APP-On-Log`: 日志消息
- `APP-Service-Start-PID`: 服务启动成功，返回 PID
- `APP-Service-Stop-Success`: 服务停止成功

Sources: src/fork/module/Base/index.ts34-43

---

## UI Components

### Index.vue Tab Structure

| Tab Index | Component | Description |
|-----------|-----------|-------------|
| 0 | `Service` | 服务控制面板，显示启动/停止按钮、工作目录选择 |
| 1 | `Manager` | 版本管理器，安装/切换版本 |
| 2 | `Config` | 配置文件编辑器 |
| 3 | `LogVM` | 启动错误日志查看 |

### aside.vue Sidebar Integration

```typescript
// 扩展启动参数，传递工作目录
module.startExtParam = (version: ModuleInstalledItem) => {
  const v = version.version?.split('.')?.slice(0, 2)?.join('.') ?? ''
  const dir = join(window.Server.BaseDir!, `meilisearch`, v)
  const p = MeiliSearchSetup.dir?.[version.bin] ?? dir
  return Promise.resolve([p])
}
```

Sources: src/render/components/MeiliSearch/Index.vue1-120 src/render/components/MeiliSearch/aside.vue51-66

---

## Platform Differences

| Feature | macOS/Linux | Windows | Notes |
|---------|-------------|---------|-------|
| **Binary Name** | `meilisearch` | `meilisearch.exe` | Windows 带 .exe 后缀 |
| **启动方式** | `serviceStartExec()` | `serviceStartExecWin()` | Windows 使用不同实现 |
| **参数引号** | `"${iniFile}"` | `\`${iniFile}\`` | Windows 使用反引号转义 |
| **版本目录** | `meilisearch-{version}/` | `meilisearch/{version}/` | 目录结构不同 |
| **安装方式** | 解压 tar/zip | 复制 .exe | Windows 直接复制可执行文件 |

### Version Directory Mapping

```typescript
// macOS/Linux
const dir = join(global.Server.AppDir!, `meilisearch-${a.version}`, 'meilisearch')

// Windows
const dir = join(global.Server.AppDir!, `meilisearch`, a.version, 'meilisearch.exe')
```

Sources: src/fork/module/MeiliSearch/index.ts136-156

---

## Version Management

### Online Version Fetching

通过 `api.one-env.com` 获取可用版本：

```typescript
const data = {
  app: 'meilisearch',
  os: 'mac' | 'win' | 'linux',
  arch: 'x86' | 'arm'
}
```

### Local Version Detection

```typescript
// 版本检测命令
const command = `"${item.bin}" --version`

// 版本解析正则
const reg = /(meilisearch )(\d+(\.\d+){1,4})(.*?)/g
```

版本号取前两位用于工作目录隔离（如 `1.12`）。

Sources: src/fork/module/MeiliSearch/index.ts158-197

---

## Troubleshooting

### Common Issues

| Issue | Cause | Solution |
|-------|-------|----------|
| 服务启动失败 | 配置文件中 `http_addr` 被占用 | 修改端口配置 |
| 工作目录权限不足 | 目录创建失败 | 检查 `{BaseDir}/meilisearch` 权限 |
| 版本检测失败 | 二进制文件损坏 | 重新安装版本 |

### Log Location

启动错误日志: `{BaseDir}/meilisearch/meilisearch-{version}-start-error.log`

Sources: src/render/components/MeiliSearch/Logs.vue26-34

---

*本文档遵循 DeepWiki 技术分析标准*
