From 62ee7d73d5e769e32b1aa8691a207635c8d59a84 Mon Sep 17 00:00:00 2001 From: undefined Date: Fri, 20 Jun 2025 19:36:38 +0800 Subject: [PATCH] core: connection: use subscription_id, add resume support --- framework/eslint-config/package.json | 4 +- package.json | 2 +- packages/blog/index.ts | 12 +++--- packages/blog/package.json | 2 +- packages/components/package.json | 2 +- packages/hydrooj/package.json | 2 +- packages/hydrooj/src/handler/connection.ts | 41 +++++++++++++------ packages/ui-default/package.json | 4 +- .../ui-default/pages/problem_main.page.tsx | 4 ++ packages/utils/package.json | 2 +- 10 files changed, 48 insertions(+), 27 deletions(-) diff --git a/framework/eslint-config/package.json b/framework/eslint-config/package.json index d012f584a..7c5f5f187 100644 --- a/framework/eslint-config/package.json +++ b/framework/eslint-config/package.json @@ -8,8 +8,8 @@ "@eslint/compat": "^1.3.0", "@eslint/eslintrc": "^3.3.1", "@stylistic/eslint-plugin": "^4.4.1", - "@typescript-eslint/eslint-plugin": "^8.34.0", - "@typescript-eslint/parser": "^8.34.0", + "@typescript-eslint/eslint-plugin": "^8.34.1", + "@typescript-eslint/parser": "^8.34.1", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-de-morgan": "^1.3.0", "eslint-plugin-github": "^6.0.0", diff --git a/package.json b/package.json index debfce4c9..a3fc487de 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "mongodb-memory-server": "10.1.4", "nyc": "^17.1.0", "ora": "^8.2.0", - "oxlint": "^1.1.0", + "oxlint": "^1.2.0", "package-json": "^10.0.1", "semver": "^7.7.2", "simple-git": "^3.28.0", diff --git a/packages/blog/index.ts b/packages/blog/index.ts index d03afca76..97aa367c1 100644 --- a/packages/blog/index.ts +++ b/packages/blog/index.ts @@ -134,7 +134,7 @@ class BlogUserHandler extends BlogHandler { class BlogDetailHandler extends BlogHandler { @param('did', Types.ObjectId) - async get(domainId: string, did: ObjectId) { + async get({ domainId }, did: ObjectId) { const dsdoc = this.user.hasPriv(PRIV.PRIV_USER_PROFILE) ? await BlogModel.getStatus(did, this.user._id) : null; @@ -156,13 +156,13 @@ class BlogDetailHandler extends BlogHandler { } @param('did', Types.ObjectId) - async postStar(domainId: string, did: ObjectId) { + async postStar({ }, did: ObjectId) { await BlogModel.setStar(did, this.user._id, true); this.back({ star: true }); } @param('did', Types.ObjectId) - async postUnstar(domainId: string, did: ObjectId) { + async postUnstar({ }, did: ObjectId) { await BlogModel.setStar(did, this.user._id, false); this.back({ star: false }); } @@ -176,7 +176,7 @@ class BlogEditHandler extends BlogHandler { @param('title', Types.Title) @param('content', Types.Content) - async postCreate(domainId: string, title: string, content: string) { + async postCreate({ }, title: string, content: string) { await this.limitRate('add_blog', 3600, 60); const did = await BlogModel.add(this.user._id, title, content, this.request.ip); this.response.body = { did }; @@ -186,7 +186,7 @@ class BlogEditHandler extends BlogHandler { @param('did', Types.ObjectId) @param('title', Types.Title) @param('content', Types.Content) - async postUpdate(domainId: string, did: ObjectId, title: string, content: string) { + async postUpdate({ }, did: ObjectId, title: string, content: string) { if (!this.user.own(this.ddoc!)) this.checkPriv(PRIV.PRIV_EDIT_SYSTEM); await Promise.all([ BlogModel.edit(did, title, content), @@ -197,7 +197,7 @@ class BlogEditHandler extends BlogHandler { } @param('did', Types.ObjectId) - async postDelete(domainId: string, did: ObjectId) { + async postDelete({ }, did: ObjectId) { if (!this.user.own(this.ddoc!)) this.checkPriv(PRIV.PRIV_EDIT_SYSTEM); await Promise.all([ BlogModel.del(did), diff --git a/packages/blog/package.json b/packages/blog/package.json index c61d1c9ab..75f485b3a 100644 --- a/packages/blog/package.json +++ b/packages/blog/package.json @@ -1,5 +1,5 @@ { "name": "@hydrooj/blog", - "version": "0.1.0-beta.0", + "version": "0.1.0-beta.1", "license": "AGPL-3.0-or-later" } diff --git a/packages/components/package.json b/packages/components/package.json index fa8922738..e07dd62c1 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -15,7 +15,7 @@ "devDependencies": { "@types/diff": "^8.0.0", "@types/js-yaml": "^4.0.9", - "@types/lodash": "^4.17.17", + "@types/lodash": "^4.17.18", "sass": "^1.89.2" }, "peerDependencies": { diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 22e929774..f58eff2da 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -60,7 +60,7 @@ "@types/fs-extra": "^11.0.4", "@types/js-yaml": "^4.0.9", "@types/koa-static-cache": "^5.1.4", - "@types/lodash": "^4.17.17", + "@types/lodash": "^4.17.18", "@types/mime-types": "^2.1.4", "@types/mongodb-uri": "^0.9.4", "@types/nodemailer": "^6.4.17", diff --git a/packages/hydrooj/src/handler/connection.ts b/packages/hydrooj/src/handler/connection.ts index 7094a2310..a3b792319 100644 --- a/packages/hydrooj/src/handler/connection.ts +++ b/packages/hydrooj/src/handler/connection.ts @@ -11,7 +11,9 @@ import { Logger } from '../utils'; const logger = new Logger('connection'); class WebsocketEventsConnectionManagerHandler extends ConnectionHandler { + noCheckPermView = true; category = '#gateway'; + private id = Math.random().toString(16).substring(2); private privileged = false; private channels: Set = new Set(); private disposables: Map void> = new Map(); @@ -21,7 +23,7 @@ class WebsocketEventsConnectionManagerHandler extends ConnectionHandler { const token = this.request.headers['x-hydro-websocket-gateway']; if (token) { if (!secret || token !== secret) throw new ForbiddenError('Invalid token'); - logger.info('Gateway websocket connection from %s', this.request.ip); + logger.info('Gateway websocket connection from %s, id=%s', this.request.ip, this.id); this.privileged = true; } await this.ctx.parallel('subscription/init', this, this.privileged); @@ -41,8 +43,13 @@ class WebsocketEventsConnectionManagerHandler extends ConnectionHandler { } async message(payload: any) { - if (['resume', 'subscribe'].includes(payload.operation)) await this.subscribe(payload); - if (payload.operation === 'unsubscribe') await this.unsubscribe(payload); + console.log(payload); + try { + if (['resume', 'subscribe'].includes(payload.operation)) await this.subscribe(payload); + if (payload.operation === 'unsubscribe') await this.unsubscribe(payload); + } catch (e) { + logger.error('Failed to process message %o: %o', payload, e); + } } async unsubscribe(payload: any) { @@ -65,9 +72,11 @@ class WebsocketEventsConnectionManagerHandler extends ConnectionHandler { ? await TokenModel.get(payload.credential, TokenModel.TYPE_SESSION) : null; const op = payload.operation || ''; - if (!session && op !== 'resume') return; - if (op === 'resume' && !this.privileged) return; - const user = op === 'resume' ? null : await UserModel.getById('system', session.uid); + if (op === 'resume' && !this.privileged) { + this.send({ operation: 'resume_failed' }); + return; + } + const user = op === 'resume' ? null : await UserModel.getById('system', session?.uid || 0); for (const channel of payload.channels || []) { try { const result = op === 'resume' @@ -84,12 +93,20 @@ class WebsocketEventsConnectionManagerHandler extends ConnectionHandler { reject.push(channel); } } - this.send({ - operation: 'verify', - accept, - reject, - connection_id: payload.connection_id, - }); + if (op !== 'resume') { + this.send({ + operation: 'verify', + accept, + reject, + subscription_id: payload.subscription_id, + }); + } + } + + async cleanup() { + if (this.privileged) { + logger.info('Gateway websocket disconnected from %s, id=%s', this.request.ip, this.id); + } } } diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index b8d82b070..23bcea72d 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -21,7 +21,7 @@ "@fontsource/source-code-pro": "^5.2.6", "@fontsource/ubuntu-mono": "^5.2.6", "@hydrooj/utils": "workspace:^", - "@sentry/browser": "^9.29.0", + "@sentry/browser": "^9.30.0", "@sentry/webpack-plugin": "^3.5.0", "@simplewebauthn/browser": "13.1.0", "@svgr/webpack": "^8.1.0", @@ -66,7 +66,7 @@ "jquery.easing": "^1.4.1", "jquery.transit": "^0.9.12", "matchmedia-polyfill": "^0.3.2", - "md-editor-rt": "^5.6.1", + "md-editor-rt": "^5.7.0", "mini-css-extract-plugin": "^2.9.2", "moment": "^2.30.1", "monaco-editor": "0.52.2", diff --git a/packages/ui-default/pages/problem_main.page.tsx b/packages/ui-default/pages/problem_main.page.tsx index a8b12837f..ea791ff5c 100644 --- a/packages/ui-default/pages/problem_main.page.tsx +++ b/packages/ui-default/pages/problem_main.page.tsx @@ -315,6 +315,10 @@ function ProblemSelectionDisplay(props) { // eslint-disable-line setPids((o) => o.filter((i) => !all.includes(i))); }); }, []); + React.useEffect(() => { + (window as any).__getPids = () => pids; + (window as any).__setPids = (newIds: string[]) => setPids(newIds); + }, [pids]); const updateCheckboxSelection = React.useCallback(() => { for (const i of $('[data-checkbox-group="problem"]:checked')) { diff --git a/packages/utils/package.json b/packages/utils/package.json index e1d7cf50f..97f12bdfa 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -18,7 +18,7 @@ "js-yaml": "^4.1.0", "reggol": "^2.1.0", "search-query-parser": "^1.6.0", - "systeminformation": "^5.27.1" + "systeminformation": "^5.27.6" }, "devDependencies": { "@types/fs-extra": "^11.0.4"