zhixi-document-runtime/docs/app-rust-bridge.md

207 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# App ↔ Rust 调用协议
## 概述
本文档定义宿主 AppiOS/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 保护