core: connection: use subscription_id, add resume support

This commit is contained in:
undefined committed 2025-06-20 19:36:38 +08:00
1 parent 5cadd87712
commit 62ee7d73d5
10 files changed
+48 -27

No files matched your search

+2 -2
View File
@@ -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",
+1 -1
View File
@@ -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",
+6 -6
View File
@@ -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),
+1 -1
View File
@@ -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"
}
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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",
+29 -12
View File
@@ -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<string> = new Set();
private disposables: Map<string, () => 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);
}
}
}
+2 -2
View File
@@ -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",
@@ -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')) {
+1 -1
View File
@@ -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"