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:
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -43,8 +43,8 @@ async def upload_file(
|
||||
|
||||
@router.get("", response_model=FileListResponse, summary="列出已上传的文件")
|
||||
def list_files(
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
limit: int = Query(100, ge=1, le=10000),
|
||||
offset: int = Query(0, ge=0),
|
||||
service: UploadService = Depends(_service),
|
||||
) -> FileListResponse:
|
||||
total, items = service.list_files(limit=limit, offset=offset)
|
||||
|
||||
@@ -32,8 +32,8 @@ router = APIRouter(tags=["whiteboard"])
|
||||
|
||||
|
||||
def _service(db: Session = Depends(get_db)) -> WhiteboardService:
|
||||
"""REST 路径的 service:注入 hub 以便删除时踢出连接。"""
|
||||
return WhiteboardService(WhiteboardDAO(db), hub=get_hub())
|
||||
"""REST 路径的 service(纯 DB 操作)。"""
|
||||
return WhiteboardService(WhiteboardDAO(db))
|
||||
|
||||
|
||||
# ---------------- 公开 REST ----------------
|
||||
@@ -71,7 +71,7 @@ def list_whiteboards(
|
||||
summary="删除记事本(需鉴权)",
|
||||
description="删 DB 行,并关闭该 board 的所有在线 WebSocket 连接。",
|
||||
)
|
||||
def delete_whiteboard(
|
||||
async def delete_whiteboard(
|
||||
board_id: str,
|
||||
service: WhiteboardService = Depends(_service),
|
||||
_: str = Depends(require_docs_auth),
|
||||
@@ -79,6 +79,8 @@ def delete_whiteboard(
|
||||
ok = service.delete(board_id)
|
||||
if not ok:
|
||||
raise HTTPException(404, "白板不存在")
|
||||
# 删除成功后踢出该 board 的所有在线连接(close_board 是 async,须在事件循环中调用)
|
||||
await get_hub().close_board(board_id)
|
||||
return {"deleted": True}
|
||||
|
||||
|
||||
@@ -116,7 +118,7 @@ async def whiteboard_ws(websocket: WebSocket, board_id: str) -> None:
|
||||
|
||||
# 校验 board_id 并加载白板(不存在则新建)
|
||||
try:
|
||||
board = _with_db(lambda db: WhiteboardService(WhiteboardDAO(db), hub=hub).get_or_create(board_id))
|
||||
board = _with_db(lambda db: WhiteboardService(WhiteboardDAO(db)).get_or_create(board_id))
|
||||
except HTTPException as exc:
|
||||
await _safe_send(websocket, {"type": "error", "msg": exc.detail})
|
||||
await _safe_close(websocket)
|
||||
@@ -162,7 +164,7 @@ async def whiteboard_ws(websocket: WebSocket, board_id: str) -> None:
|
||||
continue
|
||||
try:
|
||||
out = _with_db(
|
||||
lambda db: WhiteboardService(WhiteboardDAO(db), hub=hub).update_content(board_id, content)
|
||||
lambda db: WhiteboardService(WhiteboardDAO(db)).update_content(board_id, content)
|
||||
)
|
||||
except HTTPException as exc:
|
||||
await _safe_send(websocket, {"type": "error", "msg": exc.detail})
|
||||
@@ -175,7 +177,7 @@ async def whiteboard_ws(websocket: WebSocket, board_id: str) -> None:
|
||||
)
|
||||
elif mtype == "clear":
|
||||
try:
|
||||
_with_db(lambda db: WhiteboardService(WhiteboardDAO(db), hub=hub).clear(board_id))
|
||||
_with_db(lambda db: WhiteboardService(WhiteboardDAO(db)).clear(board_id))
|
||||
except HTTPException as exc:
|
||||
await _safe_send(websocket, {"type": "error", "msg": exc.detail})
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user