diff --git a/cvmts/src/CollabVMServer.ts b/cvmts/src/CollabVMServer.ts index 1a37704..cd8d14d 100644 --- a/cvmts/src/CollabVMServer.ts +++ b/cvmts/src/CollabVMServer.ts @@ -30,9 +30,6 @@ const kCVMTSAssetsRoot = path.resolve(__dirname, '../../assets'); const kRestartTimeout = 5000; -// Rate in milliseconds that the 'sync' instruction should be sent to users. -const kSyncRateMs = 500; - type ChatHistory = { user: string; msg: string; @@ -88,8 +85,6 @@ export default class CollabVMServer { private ModPerms: number; private VM: VM; - private lastSync: number = Date.now(); - // Authentication manager private auth: AuthManager | null; @@ -99,6 +94,9 @@ export default class CollabVMServer { // Ban manager private banmgr: BanManager; + // queue of rects, reset every frame + private rectQueue: Rect[] = []; + private logger = pino({ name: 'CVMTS.Server' }); constructor(config: IConfig, vm: VM, banmgr: BanManager, auth: AuthManager | null, geoipReader: ReaderModel | null) { @@ -141,6 +139,7 @@ export default class CollabVMServer { // add events self.VM.GetDisplay()?.on('resize', (size: Size) => self.OnDisplayResized(size)); self.VM.GetDisplay()?.on('rect', (rect: Rect) => self.OnDisplayRectangle(rect)); + self.VM.GetDisplay()?.on('frame', () => self.OnDisplayFrame()); } } @@ -850,7 +849,20 @@ export default class CollabVMServer { } } - private async OnDisplayRectangle(rect: Rect) { + private OnDisplayRectangle(rect: Rect) { + this.rectQueue.push(rect); + } + + private OnDisplayResized(size: Size) { + this.clients + .filter((c) => c.connectedToNode || c.viewMode == 1) + .forEach((c) => { + if (this.screenHidden && c.rank == Rank.Unregistered) return; + c.sendMsg(cvm.guacEncode('size', '0', size.width.toString(), size.height.toString())); + }); + } + + private async OnDisplayFrame() { let self = this; let doRect = async (rect: Rect) => { @@ -875,35 +887,20 @@ export default class CollabVMServer { c.socket.sendBinary(encodedbin); } else { c.sendMsg(cvm.guacEncode('png', '0', '0', rect.x.toString(), rect.y.toString(), encodedb64)); + c.sendMsg(cvm.guacEncode('sync', Date.now().toString())); } }); }; - await Promise.all([doRect(rect)]); + let promises: Promise[] = []; - // Send a sync if the time since the last sync has hit or went above the rate - // to send one - let syncDeltaMs = Date.now() - self.lastSync; - if (syncDeltaMs >= kSyncRateMs) { - let syncNow = Date.now(); - self.clients - .filter((c) => c.connectedToNode || c.viewMode == 1) - .forEach((c) => { - if (self.screenHidden && c.rank == Rank.Unregistered) return; - c.sendMsg(cvm.guacEncode('sync', syncNow.toString())); - }); + for (let rect of self.rectQueue) promises.push(doRect(rect)); - self.lastSync = syncNow; - } - } + // javascript is a very solidly designed language with no holes + // or usability traps inside of it whatsoever + this.rectQueue.length = 0; - private OnDisplayResized(size: Size) { - this.clients - .filter((c) => c.connectedToNode || c.viewMode == 1) - .forEach((c) => { - if (this.screenHidden && c.rank == Rank.Unregistered) return; - c.sendMsg(cvm.guacEncode('size', '0', size.width.toString(), size.height.toString())); - }); + await Promise.all(promises); } private async SendFullScreenWithSize(client: User) {