Spaces:
Runtime error
Runtime error
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Simulator</title> | |
| </head> | |
| <body> | |
| <canvas id="displayCanvas" width="256" height="256"></canvas> | |
| <script> | |
| const canvas = document.getElementById('displayCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| let socket; | |
| let isConnected = false; | |
| let reconnectAttempts = 0; | |
| const MAX_RECONNECT_DELAY = 30000; // Maximum delay between reconnection attempts (30 seconds) | |
| let isProcessing = false; | |
| function connect() { | |
| socket = new WebSocket(`wss://${window.location.host}/ws`); | |
| socket.onopen = function(event) { | |
| console.log("WebSocket connection established"); | |
| isConnected = true; | |
| reconnectAttempts = 0; | |
| //startHeartbeat(); | |
| }; | |
| socket.onclose = function(event) { | |
| console.log("WebSocket connection closed. Attempting to reconnect..."); | |
| isConnected = false; | |
| clearInterval(heartbeatInterval); | |
| scheduleReconnection(); | |
| }; | |
| socket.onerror = function(error) { | |
| console.error("WebSocket error:", error); | |
| }; | |
| socket.onmessage = function (event) { | |
| const data = JSON.parse(event.data); | |
| if (data.type === "heartbeat_response") { | |
| console.log("Heartbeat response received"); | |
| } else if (data.image) { | |
| const img = new Image(); | |
| img.onload = function() { | |
| ctx.drawImage(img, 0, 0, canvas.width, canvas.height); | |
| isProcessing = false; // Allow new inputs after drawing the image | |
| }; | |
| img.src = 'data:image/png;base64,' + data.image; | |
| } | |
| }; | |
| } | |
| function scheduleReconnection() { | |
| const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), MAX_RECONNECT_DELAY); | |
| console.log(`Scheduling reconnection in ${delay}ms`); | |
| setTimeout(connect, delay); | |
| reconnectAttempts++; | |
| } | |
| let heartbeatInterval; | |
| function startHeartbeat() { | |
| heartbeatInterval = setInterval(() => { | |
| if (isConnected) { | |
| try { | |
| socket.send(JSON.stringify({ type: "heartbeat" })); | |
| console.error("finished sending heartbeat:", error); | |
| } catch (error) { | |
| console.error("Error sending heartbeat:", error); | |
| } | |
| } | |
| }, 1000); // Send heartbeat every 15 seconds | |
| } | |
| // Initial connection | |
| connect(); | |
| let lastSentPosition = null; | |
| let lastSentTime = 0; | |
| const SEND_INTERVAL = 50; // Send updates every 50ms | |
| function sendMousePosition(x, y, forceUpdate = false) { | |
| const currentTime = Date.now(); | |
| if (isConnected && !isProcessing && (forceUpdate || !lastSentPosition || currentTime - lastSentTime >= SEND_INTERVAL)) { | |
| try { | |
| socket.send(JSON.stringify({ | |
| "action_type": "move", | |
| "mouse_position": [x, y] | |
| })); | |
| lastSentPosition = { x, y }; | |
| lastSentTime = currentTime; | |
| } catch (error) { | |
| console.error("Error sending mouse position:", error); | |
| } | |
| } | |
| } | |
| // Capture mouse movements and clicks | |
| canvas.addEventListener("mousemove", function (event) { | |
| if (!isConnected || isProcessing) return; | |
| let rect = canvas.getBoundingClientRect(); | |
| let x = event.clientX - rect.left; | |
| let y = event.clientY - rect.top; | |
| // Client-side prediction | |
| ctx.beginPath(); | |
| ctx.moveTo(lastSentPosition ? lastSentPosition.x : x, lastSentPosition ? lastSentPosition.y : y); | |
| ctx.lineTo(x, y); | |
| ctx.stroke(); | |
| sendMousePosition(x, y); | |
| }); | |
| canvas.addEventListener("click", function (event) { | |
| if (!isConnected || isProcessing) return; | |
| let rect = canvas.getBoundingClientRect(); | |
| let x = event.clientX - rect.left; | |
| let y = event.clientY - rect.top; | |
| isProcessing = false; | |
| try { | |
| socket.send(JSON.stringify({ | |
| "action_type": "left_click", | |
| "mouse_position": [x, y] | |
| })); | |
| } catch (error) { | |
| console.error("Error sending click action:", error); | |
| } | |
| }); | |
| // Graceful disconnection | |
| window.addEventListener('beforeunload', function (e) { | |
| if (isConnected) { | |
| try { | |
| //socket.send(JSON.stringify({ type: "disconnect" })); | |
| //socket.close(); | |
| } catch (error) { | |
| console.error("Error during disconnection:", error); | |
| } | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |