From 6ac458e6f378886b5ac8e7d9b8a30a9f06cacf31 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Thu, 27 Aug 2026 00:48:54 -0600 Subject: [PATCH] =?UTF-8?q?refactor(WebSocket):=20=E5=88=A4=E9=A2=98/?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=9B=BE=E6=8E=A8=E9=80=81=E6=94=B9=E7=94=A8?= =?UTF-8?q?=E9=A9=BC=E5=B3=B0=EF=BC=8C=E5=8E=BB=E6=8E=89=E6=B2=A1=E4=BA=BA?= =?UTF-8?q?=E8=AF=BB=E7=9A=84=E4=B8=89=E4=B8=AA=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit submission_id / time_cost / memory_cost / err_info 是 OJ2 两端自己定的线上格式, 没有第三方消费(/ws/submissions 只有 apps/web 一个客户端),没理由留着 snake。 flowchart 那条更别扭:同一个对象里 submission_id 是 snake、criteriaDetails 是驼峰。 三个字段直接删掉而不是改名 —— 它们是从 statistic_info 原样抄出来的一份,前端 一处都没读过(useSubmissionMonitor 只用 submissionId / result / status)。耗时和 错误信息在提交详情里本来就有,判完了去拉一次就是,不必让推送顺带背一份 JSONB 的形状。score 保留,它不涉及大小写。 **没动的都是有外部约束的**,别顺手一起改: - 发给判题沙箱的请求体(language_config / max_cpu_time / max_memory / test_case_id / io_mode)和它回的字段(cpu_time / memory / test_case)—— 那是沙箱的 API,不是我们的 - 测试点 info 文件的键,沙箱直接读那个文件 - submission.statistic_info 里的 time_cost / err_info / ast_results —— 判题机按这套写,12 万条历史提交就是这形状 - acm_problems_status、progress_detail 这些存量 JSONB - AST 规则键(for_loop)、成就指标(accepted_count)、reaction 语义键 —— 那是词汇表标识符不是字段名,for_loop 还要映射到 tree-sitter 的 while_statement 验证:起 dev 栈(api + worker + 沙箱),学生账号真提一次代码,抓 /ws/submissions 的帧: {"type":"submission_update","submissionId":"bf13b7f0…","result":6,"status":"pending"} {"type":"submission_update","submissionId":"bf13b7f0…","result":7,"status":"judging"} {"type":"submission_update","submissionId":"bf13b7f0…","result":-2,"status":"finished","score":0} subscribe 帧也换成 submissionId 并被接受(否则会回一个 error 帧,没有)。 流程图那条路径要 AI 评分才跑得起来,本机没配,只做了类型检查。 前后端同一个 docker 栈一起构建部署,没有版本错配窗口。 Co-Authored-By: Claude Opus 5 --- apps/api/src/flowchart/run.ts | 4 ++-- apps/api/src/judge/run.ts | 15 +++------------ apps/api/src/websocket.ts | 19 ++++++++----------- .../composables/useSubmissionMonitor.ts | 2 +- apps/web/src/shared/composables/websocket.ts | 13 +++++-------- packages/contract/src/flowchart.ts | 2 +- packages/contract/src/submission.ts | 13 +++++++++---- 7 files changed, 29 insertions(+), 39 deletions(-) diff --git a/apps/api/src/flowchart/run.ts b/apps/api/src/flowchart/run.ts index 223fb98..1fef1d7 100644 --- a/apps/api/src/flowchart/run.ts +++ b/apps/api/src/flowchart/run.ts @@ -57,7 +57,7 @@ export async function evaluateFlowchart(job: FlowchartJobData) { }).where(eq(schema.flowchartSubmission.id, row.flowchart.id)) await publishFlowchartUpdate(row.flowchart.userId, flowchartUpdateSchema.parse({ type: "flowchart_evaluation_completed", - submission_id: row.flowchart.id, + submissionId: row.flowchart.id, score: result.score, grade: result.grade, feedback: result.feedback, @@ -69,7 +69,7 @@ export async function evaluateFlowchart(job: FlowchartJobData) { await db.update(schema.flowchartSubmission).set({ status: 3 }).where(eq(schema.flowchartSubmission.id, row.flowchart.id)) await publishFlowchartUpdate(row.flowchart.userId, flowchartUpdateSchema.parse({ type: "flowchart_evaluation_failed", - submission_id: row.flowchart.id, + submissionId: row.flowchart.id, error: message, })) throw error diff --git a/apps/api/src/judge/run.ts b/apps/api/src/judge/run.ts index b8f7128..409f23b 100644 --- a/apps/api/src/judge/run.ts +++ b/apps/api/src/judge/run.ts @@ -317,10 +317,9 @@ async function markSystemError(submissionId: string, userId: number, error: unkn if (updated.length > 0) { await publishSubmissionUpdate(userId, { type: "submission_update", - submission_id: submissionId, + submissionId, result: JudgeStatus.SYSTEM_ERROR, status: "error", - err_info: message, }) } } @@ -353,7 +352,7 @@ export async function judgeSubmission(job: JudgeJobData) { .where(eq(schema.submission.id, row.submission.id)) await publishSubmissionUpdate(row.submission.userId, { type: "submission_update", - submission_id: row.submission.id, + submissionId: row.submission.id, result: JudgeStatus.JUDGING, status: "judging", }) @@ -463,17 +462,9 @@ export async function judgeSubmission(job: JudgeJobData) { await publishSubmissionUpdate(row.submission.userId, { type: "submission_update", - submission_id: row.submission.id, + submissionId: row.submission.id, result, status: "finished", - time_cost: - typeof statisticInfo.time_cost === "number" - ? statisticInfo.time_cost - : undefined, - memory_cost: - typeof statisticInfo.memory_cost === "number" - ? statisticInfo.memory_cost - : undefined, score: typeof statisticInfo.score === "number" ? statisticInfo.score : undefined, }) diff --git a/apps/api/src/websocket.ts b/apps/api/src/websocket.ts index 11cc54f..01508c9 100644 --- a/apps/api/src/websocket.ts +++ b/apps/api/src/websocket.ts @@ -67,7 +67,7 @@ async function handleMessage( return } - let message: { type?: unknown; timestamp?: unknown; submission_id?: unknown } + let message: { type?: unknown; timestamp?: unknown; submissionId?: unknown } try { message = JSON.parse(raw) as typeof message } catch { @@ -79,7 +79,7 @@ async function handleMessage( ws.send(JSON.stringify({ type: "pong", timestamp: message.timestamp })) return } - if (message.type !== "subscribe" || typeof message.submission_id !== "string") { + if (message.type !== "subscribe" || typeof message.submissionId !== "string") { ws.send(JSON.stringify({ type: "error", message: "Invalid message" })) return } @@ -93,7 +93,7 @@ async function handleMessage( .from(schema.submission) .where( and( - eq(schema.submission.id, message.submission_id), + eq(schema.submission.id, message.submissionId), eq(schema.submission.userId, ws.data.userId), ), ) @@ -103,17 +103,17 @@ async function handleMessage( const [flowchart] = await db .select({ id: schema.flowchartSubmission.id, status: schema.flowchartSubmission.status, score: schema.flowchartSubmission.aiScore, grade: schema.flowchartSubmission.aiGrade }) .from(schema.flowchartSubmission) - .where(and(eq(schema.flowchartSubmission.id, message.submission_id), eq(schema.flowchartSubmission.userId, ws.data.userId))) + .where(and(eq(schema.flowchartSubmission.id, message.submissionId), eq(schema.flowchartSubmission.userId, ws.data.userId))) .limit(1) if (!flowchart) { ws.send(JSON.stringify({ type: "error", message: "Submission not found" })) return } const replay = flowchart.status === 2 - ? { type: "flowchart_evaluation_completed", submission_id: flowchart.id, score: flowchart.score ?? undefined, grade: flowchart.grade ?? undefined } + ? { type: "flowchart_evaluation_completed", submissionId: flowchart.id, score: flowchart.score ?? undefined, grade: flowchart.grade ?? undefined } : flowchart.status === 3 - ? { type: "flowchart_evaluation_failed", submission_id: flowchart.id, error: "Evaluation failed" } - : { type: "flowchart_evaluation_update", submission_id: flowchart.id } + ? { type: "flowchart_evaluation_failed", submissionId: flowchart.id, error: "Evaluation failed" } + : { type: "flowchart_evaluation_update", submissionId: flowchart.id } ws.send(JSON.stringify(flowchartUpdateSchema.parse(replay))) return } @@ -129,13 +129,10 @@ async function handleMessage( : "finished" const parsed = submissionUpdateSchema.safeParse({ type: "submission_update", - submission_id: submission.id, + submissionId: submission.id, result: submission.result, status, - time_cost: statistics.time_cost, - memory_cost: statistics.memory_cost, score: statistics.score, - err_info: statistics.err_info, }) if (parsed.success) ws.send(JSON.stringify(parsed.data)) } diff --git a/apps/web/src/oj/problem/composables/useSubmissionMonitor.ts b/apps/web/src/oj/problem/composables/useSubmissionMonitor.ts index ca523a6..eb675bc 100644 --- a/apps/web/src/oj/problem/composables/useSubmissionMonitor.ts +++ b/apps/web/src/oj/problem/composables/useSubmissionMonitor.ts @@ -62,7 +62,7 @@ export function useSubmissionMonitor() { console.log("[SubmissionMonitor] 收到WebSocket更新:", data) - if (data.submission_id !== submissionId.value) { + if (data.submissionId !== submissionId.value) { console.log("[SubmissionMonitor] 提交ID不匹配,忽略") return } diff --git a/apps/web/src/shared/composables/websocket.ts b/apps/web/src/shared/composables/websocket.ts index bbda82b..98c1340 100644 --- a/apps/web/src/shared/composables/websocket.ts +++ b/apps/web/src/shared/composables/websocket.ts @@ -287,13 +287,10 @@ export class BaseWebSocket { */ export interface SubmissionUpdate extends WebSocketMessage { type: "submission_update" - submission_id: string + submissionId: string result: number status: "pending" | "judging" | "finished" | "error" - time_cost?: number - memory_cost?: number score?: number - err_info?: string } /** @@ -314,7 +311,7 @@ class SubmissionWebSocket extends BaseWebSocket { this.pendingSubmissionId = submissionId const success = this.send({ type: "subscribe", - submission_id: submissionId, + submissionId, }) if (success) this.pendingSubmissionId = "" } @@ -325,7 +322,7 @@ class SubmissionWebSocket extends BaseWebSocket { if ( this.send({ type: "subscribe", - submission_id: submissionId, + submissionId, }) ) { this.pendingSubmissionId = "" @@ -429,7 +426,7 @@ export interface FlowchartEvaluationUpdate extends WebSocketMessage { | "flowchart_evaluation_completed" | "flowchart_evaluation_failed" | "flowchart_evaluation_update" - submission_id: string + submissionId: string score?: number grade?: string feedback?: string @@ -453,7 +450,7 @@ class FlowchartWebSocket extends BaseWebSocket { subscribe(submissionId: string) { const success = this.send({ type: "subscribe", - submission_id: submissionId, + submissionId, }) if (!success) { console.error("[Flowchart WebSocket] 订阅失败: 连接未就绪") diff --git a/packages/contract/src/flowchart.ts b/packages/contract/src/flowchart.ts index 7bfdcb5..f1c8588 100644 --- a/packages/contract/src/flowchart.ts +++ b/packages/contract/src/flowchart.ts @@ -78,7 +78,7 @@ export const flowchartUpdateSchema = z.object({ "flowchart_evaluation_failed", "flowchart_evaluation_update", ]), - submission_id: z.string(), + submissionId: z.string(), score: z.number().optional(), grade: z.string().optional(), feedback: z.string().optional(), diff --git a/packages/contract/src/submission.ts b/packages/contract/src/submission.ts index 8d06ab6..65bc0e8 100644 --- a/packages/contract/src/submission.ts +++ b/packages/contract/src/submission.ts @@ -68,15 +68,20 @@ export const embeddedSubmissionSchema = submissionDetailSchema // 站内信页面拿它拼 `/problem/<题号>` 链接,给数字 id 会拼出打不开的地址。 .extend({ problem: z.string() }) +/** + * 判题进度推送。**只带前端真正要用的东西**:靠 submissionId 认领、靠 result / + * status 决定是继续等还是去拉详情。 + * + * 这里曾经还带着 time_cost / memory_cost / err_info —— 从 statistic_info 原样 + * 抄一份出来,前端一处都没读过。耗时和错误信息在提交详情里本来就有,判完了去 + * 拉一次就是了,不必让推送顺带背一份 JSONB 的形状。 + */ export const submissionUpdateSchema = z.object({ type: z.literal("submission_update"), - submission_id: z.string(), + submissionId: z.string(), result: judgeStatusSchema, status: z.enum(["pending", "judging", "finished", "error"]), - time_cost: z.number().optional(), - memory_cost: z.number().optional(), score: z.number().optional(), - err_info: z.string().optional(), }) export const submissionListItemSchema = z.object({