From 7023ffd7754f4e4fc1e8539b363538dc6d289ce2 Mon Sep 17 00:00:00 2001 From: undefined Date: Fri, 19 Jan 2024 10:01:43 +0800 Subject: [PATCH] core&ui: add websocket compression --- packages/hydrooj/package.json | 1 + packages/hydrooj/src/service/server.ts | 12 ++++++++++-- .../ui-default/components/socket/index.ts | 19 +++++++++++++++---- packages/ui-default/package.json | 1 + .../ui-default/pages/record_detail.page.ts | 6 +++--- packages/ui-default/pages/record_main.page.ts | 6 +++--- 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 3f46203d5..a9c364ef6 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -50,6 +50,7 @@ "saslprep": "^1.0.3", "schemastery": "^3.14.3", "semver": "^7.5.4", + "shorty.js": "^1.0.0", "superagent": "^8.1.2", "tar": "^6.2.0", "thirty-two": "^1.0.2", diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index 44b5573c6..940150c09 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -10,6 +10,7 @@ import Compress from 'koa-compress'; import proxy from 'koa-proxies'; import cache from 'koa-static-cache'; import type { FindCursor } from 'mongodb'; +import { Shorty } from 'shorty.js'; import WebSocket from 'ws'; import { Counter, isClass, parseMemoryMB } from '@hydrooj/utils/lib/utils'; import { Context, Service } from '../context'; @@ -364,11 +365,14 @@ export function Route(name: string, path: string, RouteHandler: any, ...permPriv export class ConnectionHandler extends HandlerCommon { conn: WebSocket; + compression: Shorty; send(data: any) { - this.conn.send(JSON.stringify(data, serializer({ + let payload = JSON.stringify(data, serializer({ showDisplayName: this.user?.hasPerm(PERM.PERM_VIEW_DISPLAYNAME), - }))); + })); + if (this.compression) payload = this.compression.deflate(payload); + this.conn.send(payload); } close(code: number, reason: string) { @@ -409,6 +413,10 @@ export function Connection( const disposables = []; try { checker.call(h); + if (args.shorty) { + h.compression = new Shorty(); + conn.send('shorty'); + } if (h._prepare) await h._prepare(args); if (h.prepare) await h.prepare(args); // eslint-disable-next-line @typescript-eslint/no-shadow diff --git a/packages/ui-default/components/socket/index.ts b/packages/ui-default/components/socket/index.ts index 91a96975a..b741602e8 100644 --- a/packages/ui-default/components/socket/index.ts +++ b/packages/ui-default/components/socket/index.ts @@ -1,11 +1,15 @@ import ReconnectingWebSocket from 'reconnecting-websocket'; +import { Shorty } from 'shorty.js'; export default class Sock { sock: ReconnectingWebSocket; interval: NodeJS.Timeout; - constructor(public url: string, nocookie = false) { + constructor(public url: string, nocookie = false, shorty = false) { const i = new URL(url, window.location.href); + if (shorty) { + i.searchParams.append('shorty', 'on'); + } if (i.host !== window.location.host && !nocookie && document.cookie.includes('sid=')) { i.searchParams.append('sid', document.cookie.split('sid=')[1].split(';')[0]); } @@ -26,20 +30,27 @@ export default class Sock { if (this.interval) clearInterval(this.interval); this.onclose?.(code, reason); }; + let decompress: Shorty = null; this.sock.onmessage = (message) => { if (message.data === 'pong') return; if (message.data === 'ping') { this.sock.send('pong'); return; } + if (message.data === 'shorty') { + decompress = new Shorty(); + return; + } if (process.env.NODE_ENV !== 'production') console.log('Sock.onmessage: ', message); - const msg = JSON.parse(message.data); + let data = message.data; + if (decompress) data = decompress.inflate(data); + const msg = JSON.parse(data); if (msg.error === 'PermissionError' || msg.error === 'PrivilegeError') this.close(); - else this.onmessage?.(message); + else this.onmessage?.(message, data); }; } - onmessage: (message: MessageEvent) => void; + onmessage: (message: MessageEvent, data: string) => void; onclose: (code: number, reason: string) => void; onopen: (sock: ReconnectingWebSocket) => void; diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index c95ff0acf..26137b6b0 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -103,6 +103,7 @@ "redux-thunk": "^3.1.0", "rupture": "^0.7.1", "schemastery": "^3.14.3", + "shorty.js": "^1.0.0", "slideout": "^1.0.1", "sticky-kit": "^1.1.3", "style-loader": "^3.3.4", diff --git a/packages/ui-default/pages/record_detail.page.ts b/packages/ui-default/pages/record_detail.page.ts index b4df9c896..67826790a 100644 --- a/packages/ui-default/pages/record_detail.page.ts +++ b/packages/ui-default/pages/record_detail.page.ts @@ -8,10 +8,10 @@ const page = new NamedPage('record_detail', async () => { import('diff-dom'), ]); - const sock = new WebSocket(UiContext.ws_prefix + UiContext.socketUrl); + const sock = new WebSocket(UiContext.ws_prefix + UiContext.socketUrl, false, true); const dd = new DiffDOM(); - sock.onmessage = (message) => { - const msg = JSON.parse(message.data); + sock.onmessage = (_, data) => { + const msg = JSON.parse(data); const newStatus = $(msg.status_html); const oldStatus = $('#status'); dd.apply(oldStatus[0], dd.diff(oldStatus[0], newStatus[0])); diff --git a/packages/ui-default/pages/record_main.page.ts b/packages/ui-default/pages/record_main.page.ts index 47e1476c2..608c43ff8 100644 --- a/packages/ui-default/pages/record_main.page.ts +++ b/packages/ui-default/pages/record_main.page.ts @@ -11,12 +11,12 @@ const page = new NamedPage('record_main', async () => { import('diff-dom'), ]); - const sock = new WebSocket(UiContext.ws_prefix + UiContext.socketUrl); + const sock = new WebSocket(UiContext.ws_prefix + UiContext.socketUrl, false, true); const dd = new DiffDOM(); sock.onopen = () => sock.send(JSON.stringify({ rids: UiContext.rids })); - sock.onmessage = (message) => { - const msg = JSON.parse(message.data); + sock.onmessage = (_, data) => { + const msg = JSON.parse(data); const $newTr = $(msg.html); const $oldTr = $(`.record_main__table tr[data-rid="${$newTr.attr('data-rid')}"]`); if ($oldTr.length) {