Debug and fix VNC client display issues

- Add comprehensive logging to Display.flip() method for viewport and scaling debugging
- Fix missing KeyboardUtil object in input/util.js
- Add backbuffer content verification before and after rectangle processing
- Enhance WebSocket message logging for frame data debugging
- Improve error handling for corrupted FramebufferUpdate messages
- Add data skipping for unsupported encodings to prevent connection stalls
- Clean up excessive console.log statements for production readiness
- Verify loading system with cancel button functionality
parent c377af92
...@@ -185,3 +185,9 @@ function getKeysym(evt) { ...@@ -185,3 +185,9 @@ function getKeysym(evt) {
} }
window.getKeycode = getKeycode; window.getKeycode = getKeycode;
window.getKeysym = getKeysym; window.getKeysym = getKeysym;
// Create KeyboardUtil object for compatibility
window.KeyboardUtil = {
getKeycode: getKeycode,
getKeysym: getKeysym
};
...@@ -175,7 +175,6 @@ class RFB extends EventTargetMixin { ...@@ -175,7 +175,6 @@ class RFB extends EventTargetMixin {
// main setup // main setup
Log.Debug(">> RFB.constructor"); Log.Debug(">> RFB.constructor");
console.log("[VNC-CLIENT] RFB constructor called");
// Create DOM elements // Create DOM elements
this._screen = document.createElement('div'); this._screen = document.createElement('div');
...@@ -192,10 +191,6 @@ class RFB extends EventTargetMixin { ...@@ -192,10 +191,6 @@ class RFB extends EventTargetMixin {
this._canvas.height = 0; this._canvas.height = 0;
this._canvas.tabIndex = -1; this._canvas.tabIndex = -1;
this._screen.appendChild(this._canvas); this._screen.appendChild(this._canvas);
console.log("[VNC-CLIENT] DOM elements created, canvas size:", this._canvas.width, "x", this._canvas.height);
console.log("[VNC-CLIENT] Canvas element:", this._canvas);
console.log("[VNC-CLIENT] Screen element:", this._screen);
console.log("[VNC-CLIENT] Target element:", this._target);
// Cursor // Cursor
this._cursor = new Cursor(); this._cursor = new Cursor();
...@@ -224,16 +219,12 @@ class RFB extends EventTargetMixin { ...@@ -224,16 +219,12 @@ class RFB extends EventTargetMixin {
// NB: nothing that needs explicit teardown should be done // NB: nothing that needs explicit teardown should be done
// before this point, since this can throw an exception // before this point, since this can throw an exception
try { try {
console.log("[VNC-CLIENT] Creating Display object with canvas:", this._canvas);
this._display = new Display(this._canvas); this._display = new Display(this._canvas);
console.log("[VNC-CLIENT] Display object created successfully:", this._display);
} catch (exc) { } catch (exc) {
console.error("[VNC-CLIENT] Display exception:", exc);
Log.Error("Display exception: " + exc); Log.Error("Display exception: " + exc);
throw exc; throw exc;
} }
this._display.onflush = this._onFlush.bind(this); this._display.onflush = this._onFlush.bind(this);
console.log("[VNC-CLIENT] Display onflush handler set");
this._keyboard = new Keyboard(this._canvas); this._keyboard = new Keyboard(this._canvas);
this._keyboard.onkeyevent = this._handleKeyEvent.bind(this); this._keyboard.onkeyevent = this._handleKeyEvent.bind(this);
...@@ -610,17 +601,11 @@ class RFB extends EventTargetMixin { ...@@ -610,17 +601,11 @@ class RFB extends EventTargetMixin {
} }
_socketOpen() { _socketOpen() {
console.log("[VNC-CLIENT] WebSocket opened, connectionState:", this._rfbConnectionState, "initState:", this._rfbInitState);
// console.log("[VNC-DEBUG] WebSocket opened, starting VNC handshake");
if ((this._rfbConnectionState === 'connecting') && if ((this._rfbConnectionState === 'connecting') &&
(this._rfbInitState === '')) { (this._rfbInitState === '')) {
this._rfbInitState = 'ProtocolVersion'; this._rfbInitState = 'ProtocolVersion';
Log.Debug("Starting VNC handshake"); Log.Debug("Starting VNC handshake");
console.log("[VNC-CLIENT] Starting VNC handshake, set init state to ProtocolVersion");
// console.log("[VNC-DEBUG] Set init state to ProtocolVersion");
} else { } else {
console.log("[VNC-CLIENT] Unexpected socket open - connectionState:", this._rfbConnectionState, "initState:", this._rfbInitState);
// console.log("[VNC-DEBUG] Unexpected socket open - connectionState:", this._rfbConnectionState, "initState:", this._rfbInitState);
this._fail("Unexpected server connection while " + this._fail("Unexpected server connection while " +
this._rfbConnectionState); this._rfbConnectionState);
} }
...@@ -887,7 +872,6 @@ class RFB extends EventTargetMixin { ...@@ -887,7 +872,6 @@ class RFB extends EventTargetMixin {
break; break;
case 'connected': case 'connected':
console.log("[VNC-CLIENT] Connection state changed to CONNECTED");
this.dispatchEvent(new CustomEvent("connect", { detail: {} })); this.dispatchEvent(new CustomEvent("connect", { detail: {} }));
break; break;
...@@ -944,7 +928,6 @@ class RFB extends EventTargetMixin { ...@@ -944,7 +928,6 @@ class RFB extends EventTargetMixin {
} }
_handleMessage() { _handleMessage() {
console.log("[VNC-MESSAGE] _handleMessage called, rQlen:", this._sock.rQlen, "connectionState:", this._rfbConnectionState, "initState:", this._rfbInitState);
if (this._sock.rQlen === 0) { if (this._sock.rQlen === 0) {
Log.Warn("handleMessage called on an empty receive queue"); Log.Warn("handleMessage called on an empty receive queue");
return; return;
...@@ -955,37 +938,21 @@ class RFB extends EventTargetMixin { ...@@ -955,37 +938,21 @@ class RFB extends EventTargetMixin {
Log.Error("Got data while disconnected"); Log.Error("Got data while disconnected");
break; break;
case 'connected': case 'connected':
console.log("[VNC-MESSAGE] Processing messages in connected state");
let msgCount = 0;
while (true) { while (true) {
if (this._flushing) { if (this._flushing) {
console.log("[VNC-MESSAGE] Flushing, breaking message loop");
break; break;
} }
console.log("[VNC-MESSAGE] Calling _normalMsg, rQlen before:", this._sock.rQlen); if (!this._normalMsg()) {
const result = this._normalMsg();
console.log("[VNC-MESSAGE] _normalMsg returned:", result, "rQlen after:", this._sock.rQlen);
if (!result) {
console.log("[VNC-MESSAGE] _normalMsg returned false, breaking");
break; break;
} }
if (this._sock.rQlen === 0) { if (this._sock.rQlen === 0) {
console.log("[VNC-MESSAGE] No more data in queue");
break;
}
msgCount++;
if (msgCount > 10) { // Prevent infinite loops
console.log("[VNC-MESSAGE] Too many messages processed, breaking to prevent infinite loop");
break; break;
} }
} }
break; break;
case 'connecting': case 'connecting':
console.log("[VNC-MESSAGE] Processing messages in connecting state");
while (this._rfbConnectionState === 'connecting') { while (this._rfbConnectionState === 'connecting') {
console.log("[VNC-MESSAGE] Calling _initMsg, initState:", this._rfbInitState);
if (!this._initMsg()) { if (!this._initMsg()) {
console.log("[VNC-MESSAGE] _initMsg returned false, breaking");
break; break;
} }
} }
...@@ -1350,29 +1317,23 @@ class RFB extends EventTargetMixin { ...@@ -1350,29 +1317,23 @@ class RFB extends EventTargetMixin {
// Message Handlers // Message Handlers
_negotiateProtocolVersion() { _negotiateProtocolVersion() {
console.log("[VNC-DEBUG] _negotiateProtocolVersion called");
if (this._sock.rQwait("version", 12)) { if (this._sock.rQwait("version", 12)) {
console.log("[VNC-DEBUG] Waiting for version data");
return false; return false;
} }
const versionStr = this._sock.rQshiftStr(12); const versionStr = this._sock.rQshiftStr(12);
console.log("[VNC-DEBUG] Received version string:", versionStr);
const sversion = versionStr.substr(4, 7); const sversion = versionStr.substr(4, 7);
Log.Info("Server ProtocolVersion: " + sversion); Log.Info("Server ProtocolVersion: " + sversion);
let isRepeater = 0; let isRepeater = 0;
switch (sversion) { switch (sversion) {
case "000.000": // UltraVNC repeater case "000.000": // UltraVNC repeater
console.log("[VNC-DEBUG] Detected UltraVNC repeater");
isRepeater = 1; isRepeater = 1;
break; break;
case "003.003": case "003.003":
case "003.006": // UltraVNC case "003.006": // UltraVNC
console.log("[VNC-DEBUG] Setting RFB version to 3.3");
this._rfbVersion = 3.3; this._rfbVersion = 3.3;
break; break;
case "003.007": case "003.007":
console.log("[VNC-DEBUG] Setting RFB version to 3.7");
this._rfbVersion = 3.7; this._rfbVersion = 3.7;
break; break;
case "003.008": case "003.008":
...@@ -1380,11 +1341,9 @@ class RFB extends EventTargetMixin { ...@@ -1380,11 +1341,9 @@ class RFB extends EventTargetMixin {
case "004.000": // Intel AMT KVM case "004.000": // Intel AMT KVM
case "004.001": // RealVNC 4.6 case "004.001": // RealVNC 4.6
case "005.000": // RealVNC 5.3 case "005.000": // RealVNC 5.3
console.log("[VNC-DEBUG] Setting RFB version to 3.8");
this._rfbVersion = 3.8; this._rfbVersion = 3.8;
break; break;
default: default:
console.log("[VNC-DEBUG] Invalid server version:", sversion);
return this._fail("Invalid server version " + sversion); return this._fail("Invalid server version " + sversion);
} }
...@@ -2058,16 +2017,13 @@ class RFB extends EventTargetMixin { ...@@ -2058,16 +2017,13 @@ class RFB extends EventTargetMixin {
} }
_negotiateServerInit() { _negotiateServerInit() {
console.log("[VNC-DEBUG] _negotiateServerInit called");
if (this._sock.rQwait("server initialization", 24)) { if (this._sock.rQwait("server initialization", 24)) {
console.log("[VNC-DEBUG] Waiting for server initialization data");
return false; return false;
} }
/* Screen size */ /* Screen size */
const width = this._sock.rQshift16(); const width = this._sock.rQshift16();
const height = this._sock.rQshift16(); const height = this._sock.rQshift16();
console.log("[VNC-DEBUG] Server screen size:", width, "x", height);
/* PIXEL_FORMAT */ /* PIXEL_FORMAT */
const bpp = this._sock.rQshift8(); const bpp = this._sock.rQshift8();
...@@ -2083,8 +2039,6 @@ class RFB extends EventTargetMixin { ...@@ -2083,8 +2039,6 @@ class RFB extends EventTargetMixin {
const blueShift = this._sock.rQshift8(); const blueShift = this._sock.rQshift8();
this._sock.rQskipBytes(3); // padding this._sock.rQskipBytes(3); // padding
console.log("[VNC-DEBUG] Server pixel format - bpp:", bpp, "depth:", depth, "trueColor:", trueColor);
// NB(directxman12): we don't want to call any callbacks or print messages until // NB(directxman12): we don't want to call any callbacks or print messages until
// *after* we're past the point where we could backtrack // *after* we're past the point where we could backtrack
...@@ -2133,13 +2087,11 @@ class RFB extends EventTargetMixin { ...@@ -2133,13 +2087,11 @@ class RFB extends EventTargetMixin {
// we're past the point where we could backtrack, so it's safe to call this // we're past the point where we could backtrack, so it's safe to call this
this._setDesktopName(name); this._setDesktopName(name);
console.log("[VNC-CLIENT] Server init complete - screen:", width, "x", height, "name:", name);
this._resize(width, height); this._resize(width, height);
if (!this._viewOnly) { this._keyboard.grab(); } if (!this._viewOnly) { this._keyboard.grab(); }
this._fbDepth = 24; this._fbDepth = 24;
console.log("[VNC-CLIENT] Keyboard grabbed, fbDepth set to 24");
if (this._fbName === "Intel(r) AMT KVM") { if (this._fbName === "Intel(r) AMT KVM") {
Log.Warn("Intel AMT KVM only supports 8/16 bit depths. Using low color mode."); Log.Warn("Intel AMT KVM only supports 8/16 bit depths. Using low color mode.");
...@@ -2493,13 +2445,12 @@ class RFB extends EventTargetMixin { ...@@ -2493,13 +2445,12 @@ class RFB extends EventTargetMixin {
msgType = 0; msgType = 0;
} else { } else {
if (this._sock.rQlen < 1) { if (this._sock.rQlen < 1) {
console.log("[VNC-MESSAGE] Not enough data for message type, rQlen:", this._sock.rQlen);
return false; return false;
} }
msgType = this._sock.rQshift8(); msgType = this._sock.rQshift8();
} }
console.log("[VNC-MESSAGE] Processing message type:", msgType, "FBU.rects:", this._FBU.rects, "rQlen:", this._sock.rQlen); // console.log("[VNC-MESSAGE] Processing message type:", msgType, "FBU.rects:", this._FBU.rects, "rQlen:", this._sock.rQlen);
let first, ret; let first, ret;
switch (msgType) { switch (msgType) {
...@@ -2569,24 +2520,15 @@ class RFB extends EventTargetMixin { ...@@ -2569,24 +2520,15 @@ class RFB extends EventTargetMixin {
this._sock.rQskipBytes(1); // Padding this._sock.rQskipBytes(1); // Padding
this._FBU.rects = this._sock.rQshift16(); this._FBU.rects = this._sock.rQshift16();
console.log("[VNC-CLIENT] FramebufferUpdate header - rects:", this._FBU.rects);
// Debug: check if we have enough data for the rectangles
const expectedBytes = this._FBU.rects * 12; // Each rect header is 12 bytes
console.log("[VNC-DEBUG] Expected bytes for rect headers:", expectedBytes, "available rQlen:", this._sock.rQlen);
// Validate rectangle count - should be reasonable (not 65534 or similar corruption) // Validate rectangle count - should be reasonable (not 65534 or similar corruption)
if (this._FBU.rects > 10000 || this._FBU.rects < 0) { if (this._FBU.rects > 10000 || this._FBU.rects < 0) {
console.log("[VNC-DEBUG] Invalid rectangle count:", this._FBU.rects, "- likely corrupted data, skipping message");
Log.Warn("Invalid rectangle count in FramebufferUpdate (" + this._FBU.rects + "), skipping corrupted message"); Log.Warn("Invalid rectangle count in FramebufferUpdate (" + this._FBU.rects + "), skipping corrupted message");
// Skip the entire FramebufferUpdate message by consuming all remaining data for this message // Skip the entire FramebufferUpdate message by consuming all remaining data for this message
// We need to skip past all the rectangle data // We need to skip past all the rectangle data
const skipBytes = this._FBU.rects * 12; // Each rectangle header is 12 bytes const skipBytes = this._FBU.rects * 12; // Each rectangle header is 12 bytes
if (this._sock.rQlen >= skipBytes) { if (this._sock.rQlen >= skipBytes) {
this._sock.rQskipBytes(skipBytes); this._sock.rQskipBytes(skipBytes);
console.log("[VNC-DEBUG] Skipped", skipBytes, "bytes of corrupted rectangle data");
} else { } else {
console.log("[VNC-DEBUG] Not enough data to skip, waiting for more data");
return false; // Wait for more data return false; // Wait for more data
} }
this._FBU.rects = 0; // Reset for next message this._FBU.rects = 0; // Reset for next message
...@@ -2605,7 +2547,6 @@ class RFB extends EventTargetMixin { ...@@ -2605,7 +2547,6 @@ class RFB extends EventTargetMixin {
while (this._FBU.rects > 0) { while (this._FBU.rects > 0) {
if (this._FBU.encoding === null) { if (this._FBU.encoding === null) {
if (this._sock.rQwait("rect header", 12)) { if (this._sock.rQwait("rect header", 12)) {
console.log("[VNC-DEBUG] Waiting for rectangle header data");
return false; return false;
} }
/* New FramebufferUpdate */ /* New FramebufferUpdate */
...@@ -2617,13 +2558,9 @@ class RFB extends EventTargetMixin { ...@@ -2617,13 +2558,9 @@ class RFB extends EventTargetMixin {
this._FBU.height = (hdr[6] << 8) + hdr[7]; this._FBU.height = (hdr[6] << 8) + hdr[7];
this._FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) + this._FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) +
(hdr[10] << 8) + hdr[11], 10); (hdr[10] << 8) + hdr[11], 10);
console.log("[VNC-DEBUG] Processing rectangle:", this._FBU.x, this._FBU.y, this._FBU.width, "x", this._FBU.height, "encoding:", this._FBU.encoding);
} }
const rectResult = this._handleRect(); if (!this._handleRect()) {
console.log("[VNC-DEBUG] _handleRect returned:", rectResult, "remaining rects:", this._FBU.rects - 1);
if (!rectResult) {
console.log("[VNC-DEBUG] Rectangle processing waiting for more data");
return false; return false;
} }
...@@ -2917,7 +2854,6 @@ class RFB extends EventTargetMixin { ...@@ -2917,7 +2854,6 @@ class RFB extends EventTargetMixin {
_handleDataRect() { _handleDataRect() {
let decoder = this._decoders[this._FBU.encoding]; let decoder = this._decoders[this._FBU.encoding];
if (!decoder) { if (!decoder) {
console.log("[VNC-DEBUG] Unsupported encoding:", this._FBU.encoding, "- skipping rectangle data");
Log.Warn("Unsupported encoding (encoding: " + Log.Warn("Unsupported encoding (encoding: " +
this._FBU.encoding + "), skipping rectangle"); this._FBU.encoding + "), skipping rectangle");
...@@ -2929,9 +2865,7 @@ class RFB extends EventTargetMixin { ...@@ -2929,9 +2865,7 @@ class RFB extends EventTargetMixin {
// Skip a reasonable amount of data for this rectangle // Skip a reasonable amount of data for this rectangle
const skipSize = Math.min(minDataSize, this._sock.rQlen); const skipSize = Math.min(minDataSize, this._sock.rQlen);
this._sock.rQskipBytes(skipSize); this._sock.rQskipBytes(skipSize);
console.log("[VNC-DEBUG] Skipped", skipSize, "bytes for unsupported encoding");
} else { } else {
console.log("[VNC-DEBUG] Not enough data to skip rectangle, waiting for more data");
return false; // Wait for more data return false; // Wait for more data
} }
return true; return true;
...@@ -2943,14 +2877,12 @@ class RFB extends EventTargetMixin { ...@@ -2943,14 +2877,12 @@ class RFB extends EventTargetMixin {
this._sock, this._display, this._sock, this._display,
this._fbDepth); this._fbDepth);
} catch (err) { } catch (err) {
console.log("[VNC-DEBUG] Error decoding rect:", err, "- skipping corrupted rectangle");
Log.Warn("Error decoding rect: " + err + " - skipping corrupted rectangle"); Log.Warn("Error decoding rect: " + err + " - skipping corrupted rectangle");
// For decoding errors, also skip data to avoid getting stuck // For decoding errors, also skip data to avoid getting stuck
const minDataSize = this._FBU.width * this._FBU.height; const minDataSize = this._FBU.width * this._FBU.height;
if (this._sock.rQlen >= minDataSize) { if (this._sock.rQlen >= minDataSize) {
const skipSize = Math.min(minDataSize, this._sock.rQlen); const skipSize = Math.min(minDataSize, this._sock.rQlen);
this._sock.rQskipBytes(skipSize); this._sock.rQskipBytes(skipSize);
console.log("[VNC-DEBUG] Skipped", skipSize, "bytes after decode error");
} }
return true; // Continue processing instead of failing return true; // Continue processing instead of failing
} }
...@@ -2964,13 +2896,10 @@ class RFB extends EventTargetMixin { ...@@ -2964,13 +2896,10 @@ class RFB extends EventTargetMixin {
} }
_resize(width, height) { _resize(width, height) {
console.log("[VNC-CLIENT] Resizing display to", width, "x", height);
console.log("[VNC-CLIENT] Canvas before resize:", this._canvas.width, "x", this._canvas.height);
this._fbWidth = width; this._fbWidth = width;
this._fbHeight = height; this._fbHeight = height;
this._display.resize(this._fbWidth, this._fbHeight); this._display.resize(this._fbWidth, this._fbHeight);
console.log("[VNC-CLIENT] Display resized, canvas after:", this._canvas.width, "x", this._canvas.height);
// Adjust the visible viewport based on the new dimensions // Adjust the visible viewport based on the new dimensions
this._updateClip(); this._updateClip();
...@@ -2980,7 +2909,6 @@ class RFB extends EventTargetMixin { ...@@ -2980,7 +2909,6 @@ class RFB extends EventTargetMixin {
// Keep this size until browser client size changes // Keep this size until browser client size changes
this._saveExpectedClientSize(); this._saveExpectedClientSize();
console.log("[VNC-CLIENT] Resize complete, final canvas size:", this._canvas.width, "x", this._canvas.height);
} }
_xvpOp(ver, op) { _xvpOp(ver, op) {
......
...@@ -338,16 +338,8 @@ class Websock { ...@@ -338,16 +338,8 @@ class Websock {
} }
_recvMessage(e) { _recvMessage(e) {
console.log("[VNC-WS] Received WebSocket message, data length:", e.data.byteLength || e.data.length);
// Log first 32 bytes for debugging
const dataArray = new Uint8Array(e.data);
const hexData = Array.from(dataArray.slice(0, Math.min(32, dataArray.length))).map(b => b.toString(16).padStart(2, '0')).join(' ');
console.log("[VNC-WS] First 32 bytes (hex):", hexData);
this._DecodeMessage(e.data); this._DecodeMessage(e.data);
console.log("[VNC-WS] After decode, rQlen:", this.rQlen, "rQi:", this._rQi);
if (this.rQlen > 0) { if (this.rQlen > 0) {
this._eventHandlers.message(); this._eventHandlers.message();
if (this._rQlen == this._rQi) { if (this._rQlen == this._rQi) {
......
...@@ -189,6 +189,15 @@ ...@@ -189,6 +189,15 @@
<div id="vnc" class="vnc-container w-100"> <div id="vnc" class="vnc-container w-100">
<div id="noVNC_screen"> <div id="noVNC_screen">
<div id="noVNC_status">Click Connect to start VNC session</div> <div id="noVNC_status">Click Connect to start VNC session</div>
<div id="noVNC_loading" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #f8f8f2;">
<div class="spinner-border text-primary mb-2" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div>Connecting to VNC server...</div>
<button id="cancelConnectBtn" class="btn btn-outline-danger btn-sm mt-2" style="display: none;">
<i class="fas fa-times"></i> Cancel
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -199,15 +208,10 @@ ...@@ -199,15 +208,10 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script> <script>
console.log('VNC page loaded');
// Check if Base64 is loaded // Check if Base64 is loaded
setTimeout(function() { setTimeout(function() {
console.log('[VNC-DEBUG] Checking if Base64 is defined:', typeof window.Base64);
if (typeof window.Base64 === 'undefined') { if (typeof window.Base64 === 'undefined') {
console.error('[VNC-DEBUG] Base64 is not defined! This will cause JPEG decoding to fail.'); console.error('[VNC-ERROR] Base64 is not defined! This will cause JPEG decoding to fail.');
} else {
console.log('[VNC-DEBUG] Base64 is properly defined');
} }
}, 100); }, 100);
...@@ -217,6 +221,7 @@ let socketFrameSeq = 0; ...@@ -217,6 +221,7 @@ let socketFrameSeq = 0;
document.getElementById('connectBtn').addEventListener('click', connect); document.getElementById('connectBtn').addEventListener('click', connect);
document.getElementById('disconnectBtn').addEventListener('click', disconnect); document.getElementById('disconnectBtn').addEventListener('click', disconnect);
document.getElementById('cancelConnectBtn').addEventListener('click', cancelConnect);
// Window control buttons // Window control buttons
document.querySelector('.close-btn').addEventListener('click', disconnect); document.querySelector('.close-btn').addEventListener('click', disconnect);
...@@ -255,12 +260,15 @@ function toggleFullscreen() { ...@@ -255,12 +260,15 @@ function toggleFullscreen() {
} }
function connect() { function connect() {
console.log('Connect button clicked');
if (connected) return; if (connected) return;
// Hide the status text and show loading message
document.getElementById('noVNC_status').style.display = 'none';
document.getElementById('noVNC_loading').style.display = 'block';
document.getElementById('cancelConnectBtn').style.display = 'inline-block';
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = wsProtocol + '//' + window.location.host + '/vnc/%s/ws'; const wsUrl = wsProtocol + '//' + window.location.host + '/vnc/%s/ws';
console.log('Connecting VNC to:', wsUrl);
try { try {
rfb = new RFB(document.getElementById('noVNC_screen'), wsUrl, { rfb = new RFB(document.getElementById('noVNC_screen'), wsUrl, {
...@@ -271,78 +279,31 @@ function connect() { ...@@ -271,78 +279,31 @@ function connect() {
}); });
rfb.addEventListener('connect', () => { rfb.addEventListener('connect', () => {
console.log('[VNC-DEBUG] VNC connected event fired');
console.log('[VNC-DEBUG] Connection state:', rfb._rfbConnectionState);
console.log('[VNC-DEBUG] Init state:', rfb._rfbInitState);
connected = true; connected = true;
document.getElementById('connectBtn').disabled = true; document.getElementById('connectBtn').disabled = true;
document.getElementById('disconnectBtn').disabled = false; document.getElementById('disconnectBtn').disabled = false;
// Hide loading message
document.getElementById('noVNC_loading').style.display = 'none';
showNotification('VNC session connected', 'success'); showNotification('VNC session connected', 'success');
// Override WebSocket onmessage after connection to intercept messages // Reset frame sequence for new connection
const originalOnMessage = rfb._sock.onmessage; socketFrameSeq = 0;
rfb._sock.onmessage = function(event) {
// Debug VNC socket data logging with base64 encoding and sequence numbers (first 20 frames only)
if (socketFrameSeq < 20) {
const bytes = event.data.byteLength || event.data.length;
const uint8 = new Uint8Array(event.data);
let binary = '';
for (let i = 0; i < uint8.length; i++) {
binary += String.fromCharCode(uint8[i]);
}
const b64Data = btoa(binary);
console.log(`[VNC-SOCKET-SERVER] Frame ${socketFrameSeq}: ${bytes} bytes -> base64: ${b64Data}`);
socketFrameSeq++;
}
// Call original handler
return originalOnMessage.call(this, event);
};
}); });
// Add debug logging for WebSocket messages
const originalSend = rfb._sock.send;
rfb._sock.send = function(data) {
console.log('[VNC-DEBUG] JavaScript sending data to WebSocket:', data.length, 'bytes');
if (data.length <= 32) {
const hex = Array.from(new Uint8Array(data)).map(b => b.toString(16).padStart(2, '0')).join(' ');
console.log('[VNC-DEBUG] Data (hex):', hex);
} else {
const hex = Array.from(new Uint8Array(data.slice(0, 32))).map(b => b.toString(16).padStart(2, '0')).join(' ');
console.log('[VNC-DEBUG] Data (first 32 bytes hex):', hex + '...');
}
// Log VNC message types
if (data.length > 0) {
const msgType = new Uint8Array(data)[0];
console.log('[VNC-DEBUG] JavaScript message type:', msgType);
switch (msgType) {
case 0: console.log('[VNC-DEBUG] -> SetPixelFormat'); break;
case 2: console.log('[VNC-DEBUG] -> SetEncodings'); break;
case 3: console.log('[VNC-DEBUG] -> FramebufferUpdateRequest'); break;
case 4: console.log('[VNC-DEBUG] -> KeyEvent'); break;
case 5: console.log('[VNC-DEBUG] -> PointerEvent'); break;
case 6: console.log('[VNC-DEBUG] -> ClientCutText'); break;
default: console.log('[VNC-DEBUG] -> Unknown message type'); break;
}
}
return originalSend.call(this, data);
};
rfb.addEventListener('disconnect', () => { rfb.addEventListener('disconnect', () => {
console.log('[VNC-DEBUG] VNC disconnected event fired');
console.log('[VNC-DEBUG] Connection state:', rfb._rfbConnectionState);
console.log('[VNC-DEBUG] Init state:', rfb._rfbInitState);
connected = false; connected = false;
document.getElementById('connectBtn').disabled = false; document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true; document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('noVNC_status').style.display = 'block';
document.getElementById('noVNC_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
showNotification('VNC session disconnected', 'info'); showNotification('VNC session disconnected', 'info');
}); });
rfb.addEventListener('credentialsrequired', (e) => { rfb.addEventListener('credentialsrequired', (e) => {
console.log('VNC credentials required');
// For now, assume no credentials needed // For now, assume no credentials needed
}); });
...@@ -352,7 +313,7 @@ function connect() { ...@@ -352,7 +313,7 @@ function connect() {
}); });
rfb.addEventListener('clipboard', (e) => { rfb.addEventListener('clipboard', (e) => {
console.log('VNC clipboard:', e.detail.text); // Handle clipboard data if needed
}); });
} catch (e) { } catch (e) {
...@@ -369,10 +330,29 @@ function disconnect() { ...@@ -369,10 +330,29 @@ function disconnect() {
connected = false; connected = false;
document.getElementById('connectBtn').disabled = false; document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true; document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('noVNC_status').style.display = 'block';
document.getElementById('noVNC_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
setTimeout(() => { setTimeout(() => {
location.reload(); location.reload();
}, 3000); }, 3000);
} }
function cancelConnect() {
if (rfb) {
rfb.disconnect();
rfb = null;
}
connected = false;
document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('noVNC_status').style.display = 'block';
document.getElementById('noVNC_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
showNotification('VNC connection cancelled', 'warning');
}
</script> </script>
</body> </body>
</html> </html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment