feat(rfb): add encoding, FPS and bandwidth event emissions

- Add encodingchange event when encoding type changes
- Add FPS counter event emitted every second
- Add bandwidth tracking in websock.js (bytes sent/received)
- Add bandwidth event with download/upload kbps every 2 seconds
This commit is contained in:
Alberto Larraz 2026-01-21 06:19:19 +00:00
parent 6d0a974665
commit 15afc5f42d
2 changed files with 62 additions and 0 deletions

View File

@ -187,6 +187,12 @@ export default class RFB extends EventTargetMixin {
encoding: null,
};
// Encoding and FPS tracking
this._lastEncoding = null;
this._frameCount = 0;
this._lastFpsTime = performance.now();
this._lastBandwidthTime = performance.now();
// Mouse state
this._mousePos = {};
this._mouseButtonMask = 0;
@ -2663,6 +2669,13 @@ export default class RFB extends EventTargetMixin {
this._FBU.encoding = this._sock.rQshift32();
/* Encodings are signed */
this._FBU.encoding >>= 0;
// Emit encoding change event for real encodings (not pseudo-encodings)
if (this._lastEncoding !== this._FBU.encoding && this._FBU.encoding >= 0) {
this._lastEncoding = this._FBU.encoding;
this.dispatchEvent(new CustomEvent("encodingchange",
{ detail: { encoding: this._FBU.encoding } }));
}
}
if (!this._handleRect()) {
@ -2675,6 +2688,25 @@ export default class RFB extends EventTargetMixin {
this._display.flip();
// FPS counter
this._frameCount++;
const now = performance.now();
if (now - this._lastFpsTime >= 1000) {
this.dispatchEvent(new CustomEvent("fps",
{ detail: { fps: this._frameCount } }));
this._frameCount = 0;
this._lastFpsTime = now;
}
// Bandwidth counter (every 2 seconds for smoother readings)
if (now - this._lastBandwidthTime >= 2000) {
const stats = this._sock.getBandwidthStats();
this.dispatchEvent(new CustomEvent("bandwidth",
{ detail: stats }));
this._sock.resetBandwidthStats();
this._lastBandwidthTime = now;
}
return true; // We finished this FBU
}

View File

@ -68,6 +68,34 @@ export default class Websock {
close: () => {},
error: () => {}
};
// Bandwidth tracking
this._bytesReceived = 0;
this._bytesSent = 0;
this._bandwidthStartTime = performance.now();
}
// Bandwidth statistics
getBandwidthStats() {
const now = performance.now();
const elapsed = (now - this._bandwidthStartTime) / 1000; // seconds
if (elapsed < 0.1) return { down: 0, up: 0, totalDown: 0, totalUp: 0 };
const downKbps = (this._bytesReceived * 8 / 1000) / elapsed;
const upKbps = (this._bytesSent * 8 / 1000) / elapsed;
return {
down: downKbps,
up: upKbps,
totalDown: this._bytesReceived,
totalUp: this._bytesSent
};
}
resetBandwidthStats() {
this._bytesReceived = 0;
this._bytesSent = 0;
this._bandwidthStartTime = performance.now();
}
// Getters and setters
@ -220,6 +248,7 @@ export default class Websock {
flush() {
if (this._sQlen > 0 && this.readyState === 'open') {
this._bytesSent += this._sQlen;
this._websocket.send(new Uint8Array(this._sQ.buffer, 0, this._sQlen));
this._sQlen = 0;
}
@ -354,6 +383,7 @@ export default class Websock {
this._rQi = 0;
}
const u8 = new Uint8Array(e.data);
this._bytesReceived += u8.length;
if (u8.length > this._rQbufferSize - this._rQlen) {
this._expandCompactRQ(u8.length);
}