fix: 代码审查修复 + 精简重写 README
后端修复: - 白板删除踢人失效:delete_whiteboard 改 async def,删除后直接 await hub.close_board()。原实现用 asyncio.get_running_loop() 在同步 REST handler (threadpool)里调用必抛 RuntimeError 被 except 吞掉,close_board 从不执行。 同时移除 service 的 hub 依赖(close_board 改由 controller 调用,service 只管 DB)。 - delete_file 去重复查询:原先 get_out_with_disk_path + get_by_id 查两次, 合并为一次;磁盘 unlink 失败加 logger.warning(原静默吞掉致磁盘泄漏无记录)。 - get_hub 单例加 threading.Lock 双重检查(防 REST threadpool 与 WS 事件循环 并发首访各建一个 hub)。 - file_controller 公开 /api/files list 加 Query(ge=1, le=10000) 约束(原无上限可 DoS)。 前端修复: - applyRemoteUpdate 有未发送编辑时重发:合并远端更新后若本地有 pending 编辑 (editor.value !== lastSentText)重新 scheduleSend,避免被 lastSentText 短路丢弃。 - init 不覆盖未发送编辑:断线重连后若本地有未发送内容,作为新版本发上去而非被 init 覆盖。 - applyRemoteUpdate 仅在编辑器已有焦点时恢复焦点,避免抢按钮焦点。 - api() 401 时 location.reload() 触发浏览器 Basic Auth 弹窗(原只 toast 卡死)。 README: - 精简重写,补全 Ubuntu 从 0 安装、Apache 反代(含 WS)、配置项表格、防火墙说明。
This commit is contained in:
@@ -88,6 +88,8 @@
|
||||
|
||||
// ---------- 应用远端更新(保留光标) ----------
|
||||
// 策略:用最长公共前后缀算出变更区间,仅替换该区间,光标按相对位置调整。
|
||||
// 若本地有未发送的编辑(editor.value !== lastSentText),合并后重新 scheduleSend,
|
||||
// 避免本地编辑被远端覆盖后因 lastSentText 短路而丢弃。
|
||||
function applyRemoteUpdate(newText) {
|
||||
const oldText = editor.value;
|
||||
if (newText === oldText) return;
|
||||
@@ -108,6 +110,7 @@
|
||||
suffixNew--;
|
||||
}
|
||||
|
||||
const hadPending = editor.value !== lastSentText;
|
||||
suppressInput = true;
|
||||
// 用 setRangeText 替换 [prefix, suffixOld) 为 newText[prefix, suffixNew)
|
||||
editor.setRangeText(newText.slice(prefix, suffixNew), prefix, suffixOld, "end");
|
||||
@@ -130,7 +133,11 @@
|
||||
try {
|
||||
editor.setSelectionRange(newStart, newEnd);
|
||||
} catch {}
|
||||
editor.focus();
|
||||
// 仅当编辑器当前有焦点时恢复焦点,避免抢其它控件焦点
|
||||
if (document.activeElement === editor) editor.focus();
|
||||
|
||||
// 本地有未发送编辑被合并了,重新安排发送,避免被丢弃
|
||||
if (hadPending) scheduleSend();
|
||||
}
|
||||
|
||||
// ---------- WebSocket ----------
|
||||
@@ -164,11 +171,19 @@
|
||||
try { msg = JSON.parse(raw); } catch { return; }
|
||||
switch (msg.type) {
|
||||
case "init":
|
||||
suppressInput = true;
|
||||
editor.value = msg.content || "";
|
||||
lastSentText = editor.value;
|
||||
suppressInput = false;
|
||||
editor.focus();
|
||||
// 连接建立时服务端下发当前文本。若本地有未发送编辑(断线期间输入的),
|
||||
// 不直接覆盖,而是把本地编辑作为最新版本发上去(last-writer-wins),
|
||||
// 避免断线期间的编辑被静默丢弃。
|
||||
if (editor.value && editor.value !== lastSentText) {
|
||||
lastSentText = editor.value;
|
||||
send({ type: "edit", content: editor.value });
|
||||
} else {
|
||||
suppressInput = true;
|
||||
editor.value = msg.content || "";
|
||||
lastSentText = editor.value;
|
||||
suppressInput = false;
|
||||
editor.focus();
|
||||
}
|
||||
setStatus("已同步", false);
|
||||
break;
|
||||
case "pong":
|
||||
|
||||
Reference in New Issue
Block a user