zhixi-document-runtime/docs/event-protocol.md

108 lines
2.4 KiB
Markdown
Raw Permalink 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.

# Reading Event Protocol
## 概述
Rust Core 生成阅读事件App 负责收集和上传。这是一个单向数据流Rust → App → Backend。
## 事件类型
```rust
enum ReadingEvent {
MaterialOpened { material_id, timestamp_ms },
MaterialClosed { material_id, timestamp_ms, active_seconds },
PositionChanged { material_id, position, timestamp_ms },
Heartbeat { material_id, active_seconds, position?, timestamp_ms },
MarkedAsRead { material_id, timestamp_ms },
}
```
## 事件说明
### MaterialOpened
用户打开一份资料时触发。
```json
{
"type": "material_opened",
"material_id": "abc123",
"timestamp_ms": 1717100000000
}
```
### MaterialClosed
用户关闭资料时触发,`active_seconds` 为本次打开的累计活跃秒数。
```json
{
"type": "material_closed",
"material_id": "abc123",
"timestamp_ms": 1717100300000,
"active_seconds": 285
}
```
### PositionChanged
用户滚动/翻页/缩放导致阅读位置变化。频率由 App 控制(建议每 5 秒或停止交互后触发)。
```json
{
"type": "position_changed",
"material_id": "abc123",
"timestamp_ms": 1717100100000,
"position": {
"type": "markdown",
"block_id": "heading-3",
"scroll_progress": 0.45
}
}
```
### Heartbeat
定时心跳,用于计算阅读时长。即使位置未变化也应周期性触发(建议 10-15 秒)。
```json
{
"type": "heartbeat",
"material_id": "abc123",
"timestamp_ms": 1717100150000,
"active_seconds": 15,
"position": null
}
```
### MarkedAsRead
用户手动标记已读。
```json
{
"type": "marked_as_read",
"material_id": "abc123",
"timestamp_ms": 1717100400000
}
```
## 事件收集流程
```text
1. App 打开资料 → Rust 生成 MaterialOpened
2. App 启动定时器(~15s
3. 每次定时器触发 → Rust 生成 Heartbeat
4. 用户交互(滚动/翻页)→ App 调用 update_position → Rust 生成 PositionChanged
5. App 关闭资料 → Rust 生成 MaterialClosed含 active_seconds
6. App 定期调用 export_pending_events() 获取所有未导出事件
7. App POST 事件到后端 /reading/events
8. App 调用 clear_exported_events() 清空缓冲区
```
## App 侧实现要点
- 事件应在本地缓存(内存队列),不要一次传一个
- 批量上传(每次 5-20 条)或定时上传(每 30s
- 网络失败时保留队列,下次重试
- 离线时事件不丢失,恢复网络后继续上传