KASM-3102 Allow setting the idle timeout (#41)

refactor idle timeout to use date diff
This commit is contained in:
Matt McClaskey 2022-11-11 09:29:52 -05:00 committed by GitHub
parent c5350ba2d7
commit 3a6a63cde3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 56 deletions

View File

@ -46,9 +46,6 @@ import * as WebUtil from "./webutil.js";
const PAGE_TITLE = "KasmVNC"; const PAGE_TITLE = "KasmVNC";
var delta = 500;
var lastKeypressTime = 0;
var lastKeypressCode = -1;
var currentEventCount = -1; var currentEventCount = -1;
var idleCounter = 0; var idleCounter = 0;
@ -1423,46 +1420,41 @@ const UI = {
/**** /****
* Kasm VDI specific * Kasm VDI specific
*****/ *****/
if (WebUtil.isInsideKasmVDI()) if (WebUtil.isInsideKasmVDI()) {
{ if (window.addEventListener) { // Mozilla, Netscape, Firefox
if (window.addEventListener) { // Mozilla, Netscape, Firefox //window.addEventListener('load', WindowLoad, false);
//window.addEventListener('load', WindowLoad, false); window.addEventListener('message', UI.receiveMessage, false);
window.addEventListener('message', UI.receiveMessage, false); } else if (window.attachEvent) { //IE
} else if (window.attachEvent) { //IE window.attachEvent('onload', WindowLoad);
window.attachEvent('onload', WindowLoad); window.attachEvent('message', UI.receiveMessage);
window.attachEvent('message', UI.receiveMessage); }
} if (UI.rfb.clipboardDown){
if (UI.rfb.clipboardDown){ UI.rfb.addEventListener("clipboard", UI.clipboardRx);
UI.rfb.addEventListener("clipboard", UI.clipboardRx); }
} UI.rfb.addEventListener("disconnect", UI.disconnectedRx);
UI.rfb.addEventListener("disconnect", UI.disconnectedRx); document.getElementById('noVNC_control_bar_anchor').setAttribute('style', 'display: none');
document.getElementById('noVNC_control_bar_anchor').setAttribute('style', 'display: none');
//keep alive for websocket connection to stay open, since we may not control reverse proxies
//keep alive for websocket connection to stay open, since we may not control reverse proxies //send a keep alive within a window that we control
//send a keep alive within a window that we control UI._sessionTimeoutInterval = setInterval(function() {
setInterval(function() {
if (currentEventCount!=UI.rfb.sentEventsCounter) { const timeSinceLastActivityInS = (Date.now() - UI.rfb.lastActiveAt) / 1000;
idleCounter=0; let idleDisconnectInS = 1200; //20 minute default
currentEventCount=UI.rfb.sentEventsCounter; if (Number.isFinite(UI.rfb.idleDisconnect)) {
} else { idleDisconnectInS = parseFloat(UI.rfb.idleDisconnect) * 60;
idleCounter+=1; }
var idleDisconnect = parseFloat(UI.rfb.idleDisconnect); console.log("Current idle time " + timeSinceLastActivityInS + " max value is " + idleDisconnectInS);
if ((idleCounter / 2) >= idleDisconnect) {
//idle for longer than the limit, disconnect if (timeSinceLastActivityInS > idleDisconnectInS) {
currentEventCount = -1; parent.postMessage({ action: 'idle_session_timeout', value: 'Idle session timeout exceeded'}, '*' );
idleCounter = 0; } else {
parent.postMessage({ action: 'idle_session_timeout', value: 'Idle session timeout exceeded'}, '*' ); //send keep-alive
//UI.rfb.disconnect(); UI.rfb.sendKey(1, null, false);
} else { }
//send a keep alive }, 5000);
UI.rfb.sendKey(1, null, false); } else {
currentEventCount=UI.rfb.sentEventsCounter;
}
}
}, 30000);
} else {
document.getElementById('noVNC_status').style.visibility = "visible"; document.getElementById('noVNC_status').style.visibility = "visible";
} }
//key events for KasmVNC control //key events for KasmVNC control
document.addEventListener('keyup', function (event) { document.addEventListener('keyup', function (event) {
@ -1493,7 +1485,7 @@ const UI = {
UI.updateVisualState('disconnecting'); UI.updateVisualState('disconnecting');
// Don't display the connection settings until we're actually disconnected clearInterval(UI._sessionTimeoutInterval);
}, },
reconnect() { reconnect() {
@ -1680,6 +1672,14 @@ const UI = {
UI.toggleWebRTC(); UI.toggleWebRTC();
} }
break; break;
case 'set_idle_timeout':
//message value in seconds
const idle_timeout_min = Math.ceil(event.data.value / 60);
UI.forceSetting('idle_disconnect', idle_timeout_min, false);
UI.rfb.idleDisconnect = idle_timeout_min;
console.log(`Updated the idle timeout to ${event.data.value}s`);
break;
} }
} }
}, },

View File

@ -340,7 +340,7 @@ export default class RFB extends EventTargetMixin {
this.dragViewport = false; this.dragViewport = false;
this.focusOnClick = true; this.focusOnClick = true;
this.sentEventsCounter = 0; this.lastActiveAt = Date.now();
this._viewOnly = false; this._viewOnly = false;
this._clipViewport = false; this._clipViewport = false;
@ -813,8 +813,10 @@ export default class RFB extends EventTargetMixin {
sendKey(keysym, code, down) { sendKey(keysym, code, down) {
if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; } if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; }
this.sentEventsCounter+=1; if (code !== null) {
this._setLastActive();
}
if (down === undefined) { if (down === undefined) {
this.sendKey(keysym, code, true); this.sendKey(keysym, code, true);
this.sendKey(keysym, code, false); this.sendKey(keysym, code, false);
@ -872,8 +874,6 @@ export default class RFB extends EventTargetMixin {
if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; } if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; }
if (!(typeof text === 'string' && text.length > 0)) { return; } if (!(typeof text === 'string' && text.length > 0)) { return; }
this.sentEventsCounter+=1;
let data = new TextEncoder().encode(text); let data = new TextEncoder().encode(text);
let h = hashUInt8Array(data); let h = hashUInt8Array(data);
@ -894,7 +894,6 @@ export default class RFB extends EventTargetMixin {
async clipboardPasteDataFrom(clipdata) { async clipboardPasteDataFrom(clipdata) {
if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; } if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; }
this.sentEventsCounter+=1;
let dataset = []; let dataset = [];
let mimes = []; let mimes = [];
@ -965,6 +964,10 @@ export default class RFB extends EventTargetMixin {
// ===== PRIVATE METHODS ===== // ===== PRIVATE METHODS =====
_setLastActive() {
this.lastActiveAt = Date.now();
}
_changeTransitConnectionState(value) { _changeTransitConnectionState(value) {
Log.Info("Transit state change from " + this._transitConnectionState.toString() + ' to ' + value.toString()); Log.Info("Transit state change from " + this._transitConnectionState.toString() + ' to ' + value.toString());
this._transitConnectionState = value; this._transitConnectionState = value;
@ -977,7 +980,7 @@ export default class RFB extends EventTargetMixin {
try { try {
Log.Info(`connecting to ${this._url}`); Log.Info(`connecting to ${this._url}`);
this._sock.open(this._url, this._wsProtocols); this._sock.open(this._url, this._wsProtocols);
this.sentEventsCounter+=1; this._setLastActive();
} catch (e) { } catch (e) {
if (e.name === 'SyntaxError') { if (e.name === 'SyntaxError') {
this._fail("Invalid host or port (" + e + ")"); this._fail("Invalid host or port (" + e + ")");
@ -1301,8 +1304,6 @@ export default class RFB extends EventTargetMixin {
Math.floor(size.w), Math.floor(size.h), Math.floor(size.w), Math.floor(size.h),
this._screenID, this._screenFlags); this._screenID, this._screenFlags);
this.sentEventsCounter+=1;
Log.Debug('Requested new desktop size: ' + Log.Debug('Requested new desktop size: ' +
size.w + 'x' + size.h); size.w + 'x' + size.h);
} }
@ -1582,6 +1583,7 @@ export default class RFB extends EventTargetMixin {
this._canvas); this._canvas);
} }
this._setLastActive();
const mappedButton = this.mouseButtonMapper.get(ev.button); const mappedButton = this.mouseButtonMapper.get(ev.button);
switch (ev.type) { switch (ev.type) {
case 'mousedown': case 'mousedown':
@ -1633,13 +1635,10 @@ export default class RFB extends EventTargetMixin {
// Otherwise we treat this as a mouse click event. // Otherwise we treat this as a mouse click event.
// Send the button down event here, as the button up // Send the button down event here, as the button up
// event is sent at the end of this function. // event is sent at the end of this function.
this.sentEventsCounter+=1;
this._sendMouse(x, y, bmask); this._sendMouse(x, y, bmask);
} }
} }
this.sentEventsCounter+=1;
// Flush waiting move event first // Flush waiting move event first
if (this._mouseMoveTimer !== null) { if (this._mouseMoveTimer !== null) {
clearTimeout(this._mouseMoveTimer); clearTimeout(this._mouseMoveTimer);
@ -3460,7 +3459,6 @@ export default class RFB extends EventTargetMixin {
RFB.messages.setMaxVideoResolution(this._sock, RFB.messages.setMaxVideoResolution(this._sock,
this._maxVideoResolutionX, this._maxVideoResolutionX,
this._maxVideoResolutionY); this._maxVideoResolutionY);
this.sentEventsCounter+=1;
} }
this._sock.rQskipBytes(1); // number-of-screens this._sock.rQskipBytes(1); // number-of-screens