refactor: 白板从画笔画板改为文本记事本
原实现是 Canvas 画笔画板,与「文字白板/记事本」需求不符。重做为纯文本实时协作: - model:strokes JSON -> content TEXT + version INT(乐观锁)+ edit_count; schema/dao/service 同步重构,append_stroke/replace_strokes -> update_content。 - WS 协议:stroke -> edit(发完整文本,debounce 400ms);init 下发 content/version。 update 帧广播给他人,cleared 广播给所有人。 - 前端:canvas -> textarea;收到远端 update 用最长公共前后缀算变更区间, 仅替换该区间并保留光标(区间前不动/后平移/内移末尾);清空/复制文本按钮。 - schema.sql 更新 whiteboard 表 DDL;DB 旧表 DROP 重建(开发环境)。 - 测试脚本与 README 同步更新。
This commit is contained in:
20
README.md
20
README.md
@@ -15,9 +15,9 @@
|
||||
- **文件浏览页** `GET /files`(Basic Auth,同 docs):列出/下载/**硬删除**已上传文件;删除后不再显示。
|
||||
管理 API:`GET /api/admin/files`、`GET /api/admin/files/{id}`、`GET /api/admin/files/{id}/download`、
|
||||
`DELETE /api/admin/files/{id}`(均 Basic Auth)。
|
||||
- **共享白板** `GET /wb/{id}`(公开,不存在则新建):Canvas 实时协作 + **清空 / 复制链接**,兼容移动端。
|
||||
- **共享记事本(白板)** `GET /wb/{id}`(公开,不存在则新建):纯文本实时协作 + **清空 / 复制文本**,兼容移动端。
|
||||
实时同步走 `WS /ws/wb/{id}`(**心跳 3s,连续 5 次丢失判失活并移除**)。
|
||||
- **白板管理页** `GET /wb-admin`(Basic Auth,同 docs):查看创建时间/修改次数/上次修改时间/删除。
|
||||
- **白板管理页** `GET /wb-admin`(Basic Auth,同 docs):查看创建时间/编辑次数/上次修改时间/删除。
|
||||
管理 API:`GET /api/admin/wb`、`DELETE /api/admin/wb/{id}`(均 Basic Auth)。
|
||||
- **反向隧道反代**:`ALL /api/userPort/{userName}` -- 把请求经 SSH 反向隧道转发到该 user 的本机服务。
|
||||
- **内置 SFTP/SSH 服务器**(asyncssh),支持 **密码 + 公钥** 鉴权,同时承载 SFTP 文件暂存与反向隧道。
|
||||
@@ -168,20 +168,24 @@ SSH 服务器(2022)同时承载 SFTP 文件暂存与反向隧道。隧道 us
|
||||
- **删除后不再显示**:列表每次进入或删除后重新 fetch,前端不缓存;DB 行已删,列表自然不含。
|
||||
- 公开 `/api/files` 系列(user.py 依赖的查重/查询/下载)保留不变。
|
||||
|
||||
## 共享白板
|
||||
## 共享记事本(白板)
|
||||
|
||||
白板无鉴权,任何人凭 `/wb/{id}` 即可访问并实时协作;`{id}` 须匹配
|
||||
`[a-zA-Z0-9_-]{1,64}`,非法返回 400。访问不存在的 id 自动新建空板。白板长期留存
|
||||
(存 MySQL `whiteboard` 表),进程重启后内容仍在。
|
||||
(存 MySQL `whiteboard` 表,`content` TEXT 列),进程重启后内容仍在。
|
||||
|
||||
### 实时同步与心跳
|
||||
|
||||
- 连接:`WS /ws/wb/{id}`(公开)。JSON 文本帧协议:
|
||||
- client -> server:`{"type":"hello","client_id":"..."}`(首帧,可选)、
|
||||
`{"type":"ping"}`(心跳)、`{"type":"stroke","stroke":{points,color,width}}`、`{"type":"clear"}`
|
||||
- server -> client:`{"type":"init","strokes":[...],"stroke_count":n}`、`{"type":"pong"}`、
|
||||
`{"type":"stroke","stroke":{...},"client_id":"..."}`(广播给他人,不含发送者)、
|
||||
`{"type":"ping"}`(心跳)、`{"type":"edit","content":"..."}`(debounce 后发完整文本)、
|
||||
`{"type":"clear"}`
|
||||
- server -> client:`{"type":"init","content":"...","version":n,"edit_count":m}`、
|
||||
`{"type":"pong"}`、`{"type":"update","content":"...","version":n,"client_id":"..."}`(广播给他人,不含发送者)、
|
||||
`{"type":"cleared","client_id":"..."}`(广播给所有人)、`{"type":"error","msg":"..."}`
|
||||
- **同步策略**:客户端本地编辑后 debounce 400ms 发完整文本,服务端存为新版本(version+1)
|
||||
并广播给同 board 的其他在线连接。其他端用最长公共前后缀算出变更区间,仅替换该区间并
|
||||
保留本地光标位置(在变更区间前不动,在后平移,在区间内移到末尾)。
|
||||
- **心跳**:客户端每 `whiteboard.heartbeat_interval_seconds`(默认 3s)发一次 `ping`,服务端回 `pong`
|
||||
并刷新计时。后台 reaper 每秒扫描,连续 `heartbeat_miss_threshold`(默认 5)次未收到心跳
|
||||
(即 15s)判失活,**关闭该连接并从 hub 移除**。
|
||||
@@ -197,7 +201,7 @@ SSH 服务器(2022)同时承载 SFTP 文件暂存与反向隧道。隧道 us
|
||||
|
||||
- `GET /wb-admin`(Basic Auth,同 docs)渲染 `static/whiteboard_admin.html`。
|
||||
- 管理 API(均 Basic Auth):
|
||||
- `GET /api/admin/wb?limit=&offset=` -> `{total, items:[{board_id, stroke_count, created_at, updated_at}]}`
|
||||
- `GET /api/admin/wb?limit=&offset=` -> `{total, items:[{board_id, edit_count, created_at, updated_at}]}`
|
||||
- `DELETE /api/admin/wb/{id}` -> 删 DB 行 + 关闭该 board 所有在线 WS 连接。
|
||||
|
||||
## 临时文件清理
|
||||
|
||||
Reference in New Issue
Block a user