feat(api): 新增 /ws/collab 通道与课堂求助控制面

学生发起/撤销求助,在线教师收到全量列表。求助只在内存,不落库。
二进制帧的限流单独一档,避免协作输入把连接踢掉。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1d8B3f4SXJwDvUY625eQd
This commit is contained in:
2026-08-28 02:24:44 -06:00
co-authored by Claude Opus 5
parent c04570b4ad
commit 1db2c49b87
4 changed files with 318 additions and 8 deletions
+13 -2
View File
@@ -100,19 +100,30 @@ const server = Bun.serve<SubmissionSocketData>({
new Response("Not found", { status: 404 })
)
}
if (url.pathname === "/ws/submissions" || url.pathname === "/ws/config") {
if (
url.pathname === "/ws/submissions" ||
url.pathname === "/ws/config" ||
url.pathname === "/ws/collab"
) {
if (!isAllowedWebSocketOrigin(request.headers.get("origin"), url)) {
return new Response("Forbidden", { status: 403 })
}
const user = await getRequestSessionUser(request)
if (!user) return new Response("Unauthorized", { status: 401 })
const kind = url.pathname === "/ws/config" ? "config" : "submissions"
const kind =
url.pathname === "/ws/config"
? "config"
: url.pathname === "/ws/collab"
? "collab"
: "submissions"
if (
bunServer.upgrade(request, {
data: {
userId: user.id,
kind,
token: readRequestSessionToken(request),
username: user.username,
adminType: user.adminType,
},
})
) {