docs: app-rust-bridge - complete FFI call protocol
This commit is contained in:
parent
8042a9d92e
commit
a0aaf9b713
206
docs/app-rust-bridge.md
Normal file
206
docs/app-rust-bridge.md
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
# App ↔ Rust 调用协议
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本文档定义宿主 App(iOS/Android)与 Rust Core 之间的全部调用边界。
|
||||||
|
|
||||||
|
核心原则:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Rust Core 是纯计算层。
|
||||||
|
不做网络请求、不保存 Token、不访问后端 API。
|
||||||
|
文件由 App 下载到本地后,把路径交给 Rust。
|
||||||
|
阅读事件由 Rust 生成,App 负责上传。
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 调用方向
|
||||||
|
|
||||||
|
```text
|
||||||
|
App ──调用──→ Rust Core
|
||||||
|
App ←──返回── Rust Core
|
||||||
|
App ──上传──→ Backend API
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rust 暴露给 App 的函数
|
||||||
|
|
||||||
|
### 1. 文件类型识别
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn detect_material_type(file_path: &str) -> Result<MaterialType, DocumentError>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输入**:本地文件路径
|
||||||
|
**输出**:MaterialType 枚举值
|
||||||
|
**用途**:App 据此决定使用哪种 PreviewMode
|
||||||
|
|
||||||
|
### 2. 打开文档
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn open_document(file_path: &str, material_id: &str) -> Result<DocumentHandle, DocumentError>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输入**:本地文件路径 + 资料 ID
|
||||||
|
**输出**:DocumentHandle(不透明句柄,App 传递给后续函数)
|
||||||
|
**用途**:初始化文档解析,建立阅读会话
|
||||||
|
|
||||||
|
### 3. 获取文档信息
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn get_document_info(handle: &DocumentHandle) -> Result<DocumentInfo, DocumentError>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:DocumentInfo(标题、类型、大小、页数、字数)
|
||||||
|
**用途**:App 展示资料详情
|
||||||
|
|
||||||
|
### 4. 获取 Markdown Blocks
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn get_markdown_blocks(handle: &DocumentHandle) -> Result<Vec<DocumentBlock>, DocumentError>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:DocumentBlock 列表
|
||||||
|
**用途**:App 原生渲染 Markdown
|
||||||
|
**前置**:MaterialType 必须为 Markdown
|
||||||
|
|
||||||
|
### 5. 获取文本内容
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn get_text_content(handle: &DocumentHandle) -> Result<String, DocumentError>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:完整文本内容
|
||||||
|
**用途**:App 原生渲染纯文本
|
||||||
|
**前置**:MaterialType 必须为 Text
|
||||||
|
|
||||||
|
### 6. 获取图片 Metadata
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn get_image_meta(file_path: &str) -> Result<ImageMeta, DocumentError>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:width, height, format, file_size
|
||||||
|
**用途**:App 展示图片信息
|
||||||
|
**前置**:MaterialType 必须为 Image
|
||||||
|
|
||||||
|
### 7. 搜索文档
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn search_document(handle: &DocumentHandle, query: &str) -> Result<Vec<SearchResult>, DocumentError>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输入**:搜索关键词
|
||||||
|
**输出**:SearchResult 列表(block_id, snippet, match range)
|
||||||
|
**用途**:App 展示搜索结果
|
||||||
|
**支持**:Markdown、TXT
|
||||||
|
|
||||||
|
### 8. 更新阅读位置
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn update_reading_position(material_id: &str, position: ReadingPosition)
|
||||||
|
```
|
||||||
|
|
||||||
|
**输入**:资料 ID + 阅读位置
|
||||||
|
**用途**:记录用户当前读到的位置,用于继续阅读
|
||||||
|
|
||||||
|
### 9. 导出阅读事件
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn export_pending_events() -> Vec<ReadingEvent>
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:所有未导出的阅读事件列表
|
||||||
|
**用途**:App 定期拉取事件并上传到后端
|
||||||
|
|
||||||
|
### 10. 清空已导出事件
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn clear_exported_events(count: usize)
|
||||||
|
```
|
||||||
|
|
||||||
|
**用途**:确认前 count 条事件已成功上传,从缓冲区移除
|
||||||
|
|
||||||
|
### 11. 创建笔记锚点
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn create_note_anchor(material_id: &str, position: Option<ReadingPosition>) -> NoteAnchor
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:NoteAnchor
|
||||||
|
**用途**:关联笔记到资料的具体位置
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rust 不提供的函数(由 App 负责)
|
||||||
|
|
||||||
|
以下函数**不存在于 Rust Core**,完全由宿主 App 实现:
|
||||||
|
|
||||||
|
| App 职责 | 说明 |
|
||||||
|
|---------|------|
|
||||||
|
| `download_file(url)` | COS 下载 → 本地沙盒 |
|
||||||
|
| `upload_reading_events(events)` | POST 到 /reading/events |
|
||||||
|
| `save_note_to_backend(note)` | POST 到 /notes |
|
||||||
|
| `call_ai_chat(prompt)` | 调 AI API |
|
||||||
|
| `share_file(material_id)` | 系统分享面板 |
|
||||||
|
| `delete_material(material_id)` | 调后端删除接口 |
|
||||||
|
| `get_user_token()` | Token 管理 |
|
||||||
|
| `open_system_preview(file_path)` | QuickLook / 系统预览 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 调用时序
|
||||||
|
|
||||||
|
### 打开并阅读 Markdown
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. App: download_file(cos_url) → /tmp/doc.md
|
||||||
|
2. App: detect_material_type("/tmp/doc.md") → Markdown
|
||||||
|
3. App: open_document("/tmp/doc.md", "abc123") → handle
|
||||||
|
4. App: get_document_info(handle) → DocumentInfo
|
||||||
|
5. App: get_markdown_blocks(handle) → [Block]
|
||||||
|
6. App: 渲染 blocks
|
||||||
|
7. 用户滚动 → App: update_reading_position("abc123", pos)
|
||||||
|
8. 定时器 → App: export_pending_events() → [events]
|
||||||
|
9. App: POST /reading/events
|
||||||
|
10. App: clear_exported_events(n)
|
||||||
|
11. 用户关闭 → App: export_pending_events() → last events
|
||||||
|
12. App: POST /reading/events
|
||||||
|
13. App: clear_exported_events(n)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 打开 PDF(平台预览)
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. App: download_file(cos_url) → /tmp/doc.pdf
|
||||||
|
2. App: detect_material_type("/tmp/doc.pdf") → Pdf
|
||||||
|
3. App: 判断 PreviewMode::PlatformPreview
|
||||||
|
4. App: open_system_preview("/tmp/doc.pdf") // QuickLook
|
||||||
|
5. App: 监听页码变化 → 转换为 PdfReadingPosition
|
||||||
|
6. App: update_reading_position("abc123", pos)
|
||||||
|
7. 同上导出事件流程
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 错误处理约定
|
||||||
|
|
||||||
|
所有函数返回 `Result<T, DocumentError>`:
|
||||||
|
|
||||||
|
| 错误 | 场景 | App 处理 |
|
||||||
|
|------|------|---------|
|
||||||
|
| FileNotFound | 文件路径不存在 | 提示用户重新下载 |
|
||||||
|
| UnsupportedFormat | 无法识别的格式 | 显示"暂不支持" |
|
||||||
|
| ParseError | 文件内容损坏 | 显示"文件异常" |
|
||||||
|
| InvalidEncoding | 非 UTF-8 | 尝试其他编码或提示 |
|
||||||
|
| IoError | 磁盘错误 | 重试或提示 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 线程安全
|
||||||
|
|
||||||
|
- Rust Core 的函数应在**后台线程**调用
|
||||||
|
- App 主线程只做 UI 渲染
|
||||||
|
- `export_pending_events` 和 `clear_exported_events` 内部需要 Mutex 保护
|
||||||
Loading…
x
Reference in New Issue
Block a user