neural-os / static /index.html
yuntian-deng's picture
Update static/index.html
f831ea6
raw
history blame
5.37 kB
<!DOCTYPE html>
<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>