mirror of
https://github.com/damp11113-software/ccIDE.git
synced 2025-04-28 06:58:13 +00:00
support multiple upload to machine and make remote script to one file and support to run on startup
266 lines
10 KiB
JavaScript
266 lines
10 KiB
JavaScript
const WebSocket = require('ws');
|
|
|
|
class CCRemote {
|
|
constructor(ip = "127.0.0.1", port = 5133) {
|
|
this.socket = new WebSocket.Server({
|
|
port: port,
|
|
host: ip
|
|
});
|
|
|
|
this.clients = new Map(); // Map to track client data (numeric IDs)
|
|
this.clientIdCounter = 0; // Counter for numeric client IDs
|
|
|
|
console.log("Remote server is started");
|
|
fireNotify(
|
|
"Remote server started, waiting for clients to connect...",
|
|
"info"
|
|
);
|
|
|
|
this.socket.on('connection', (ws) => {
|
|
const clientId = this.clientIdCounter++;
|
|
this.clients.set(clientId, { ws, isAlive: true, name: `Client-${clientId}`, clientInfo: null });
|
|
|
|
if (this.clients.size >= 0) {
|
|
document.getElementById("navbar-button-computer-disconnect").disabled = false;
|
|
document.getElementById("navbar-button-computer-run").disabled = false;
|
|
}
|
|
|
|
console.log(`Client ${clientId} connected.`);
|
|
fireNotify(`Client ${clientId} connected`, "success");
|
|
|
|
// Send "info" command to the client immediately upon connection
|
|
this.sendCommandToClient(clientId, 'info', true);
|
|
|
|
ws.on('pong', () => {
|
|
this.clients.get(clientId).isAlive = true;
|
|
});
|
|
|
|
ws.on('message', (message) => {
|
|
console.log(`Message from Client ${clientId}: ${message}`);
|
|
// Handle info response
|
|
try {
|
|
const data = JSON.parse(message);
|
|
|
|
if (data.OSVersion && typeof data.OSVersion === 'string' &&
|
|
data.Name && typeof data.Name === 'string' &&
|
|
typeof data.ID === 'number' &&
|
|
typeof data.uptime === 'number' &&
|
|
typeof data.Type === 'number') {
|
|
|
|
// Update clientInfo with the received data
|
|
this.clients.get(clientId).clientInfo = data;
|
|
console.log(`Client ${clientId} info updated:`, data);
|
|
} else {
|
|
console.log(`Invalid data format from Client ${clientId}:`, data);
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error parsing message from Client ${clientId}:`, error);
|
|
}
|
|
});
|
|
|
|
ws.on('close', () => {
|
|
console.log(`Client ${clientId} disconnected.`);
|
|
this.clients.delete(clientId);
|
|
fireNotify(`Client ${clientId} disconnected`, "warning");
|
|
|
|
if (this.clients.size === 0) {
|
|
document.getElementById("navbar-button-computer-disconnect").disabled = true;
|
|
document.getElementById("navbar-button-computer-run").disabled = true;
|
|
}
|
|
});
|
|
|
|
ws.on('error', (error) => {
|
|
console.error(`Client ${clientId} error:`, error);
|
|
fireNotify(`Error with Client ${clientId}: ${error.message}`, "error");
|
|
});
|
|
});
|
|
|
|
// Ping clients every 30 seconds to check if they are alive
|
|
const interval = setInterval(() => {
|
|
for (const [clientId, clientData] of this.clients.entries()) {
|
|
if (clientData.isAlive === false) {
|
|
console.log(`Client ${clientId} did not respond to ping, terminating connection.`);
|
|
fireNotify(`Client ${clientId} did not respond to ping, disconnected`, "warning");
|
|
clientData.ws.terminate();
|
|
this.clients.delete(clientId);
|
|
continue;
|
|
}
|
|
|
|
clientData.isAlive = false;
|
|
clientData.ws.ping();
|
|
}
|
|
}, 30000);
|
|
|
|
this.socket.on('close', () => {
|
|
clearInterval(interval);
|
|
console.log('WebSocket server closed.');
|
|
fireNotify("WebSocket server closed.", "info");
|
|
});
|
|
|
|
this.socket.on('error', (error) => {
|
|
console.error('WebSocket server error:', error);
|
|
fireNotify(`WebSocket server error: ${error.message}`, "error");
|
|
});
|
|
}
|
|
|
|
// List all connected clients with their IDs, names, and clientInfo
|
|
// List all connected clients with their IDs, names, and clientInfo
|
|
async listClients() {
|
|
const clientList = [];
|
|
|
|
// Create an array of promises for fetching client info
|
|
const infoPromises = [];
|
|
|
|
// Loop over each client and trigger 'info' command to get the latest information
|
|
for (const [clientId, clientData] of this.clients.entries()) {
|
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
|
const infoPromise = new Promise((resolve) => {
|
|
// Set a timeout to handle cases where no response is received
|
|
const timeout = setTimeout(() => {
|
|
resolve({ id: clientId, name: clientData.name, info: null });
|
|
}, 5000); // Wait 5 seconds for a response
|
|
|
|
// Listen for the response from the client
|
|
const messageHandler = (message) => {
|
|
try {
|
|
const data = JSON.parse(message);
|
|
if (data.OSVersion && typeof data.OSVersion === 'string' &&
|
|
data.Name && typeof data.Name === 'string' &&
|
|
typeof data.ID === 'number' &&
|
|
typeof data.uptime === 'number' &&
|
|
typeof data.Type === 'number') {
|
|
|
|
// Resolve with the valid data
|
|
resolve({ id: clientId, name: clientData.name, info: data });
|
|
} else {
|
|
resolve({ id: clientId, name: clientData.name, info: null });
|
|
}
|
|
} catch (error) {
|
|
resolve({ id: clientId, name: clientData.name, info: null });
|
|
}
|
|
};
|
|
|
|
// Send the "info" command to the client
|
|
this.sendCommandToClient(clientId, 'info', true);
|
|
|
|
// Attach the handler for this specific client
|
|
clientData.ws.on('message', messageHandler);
|
|
});
|
|
|
|
// Add the promise to the array
|
|
infoPromises.push(infoPromise);
|
|
}
|
|
}
|
|
|
|
// Wait for all promises to resolve (all client info to be updated)
|
|
const resolvedClientInfo = await Promise.all(infoPromises);
|
|
|
|
// Construct the final list of clients with updated information
|
|
for (const clientInfo of resolvedClientInfo) {
|
|
clientList.push(clientInfo);
|
|
}
|
|
|
|
return clientList;
|
|
}
|
|
|
|
// Check if any client is connected
|
|
isClientConnect() {
|
|
return this.clients.size > 0;
|
|
}
|
|
|
|
// Send code to all clients
|
|
sendCode(code) {
|
|
this.clients.forEach((clientData, clientId) => {
|
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
|
clientData.ws.send("sendcode");
|
|
setTimeout(() => {
|
|
clientData.ws.send(code);
|
|
}, 500);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Send code to a specific client
|
|
sendCodeToClient(clientId, code) {
|
|
const client = this.clients.get(clientId);
|
|
if (!client || client.ws.readyState !== WebSocket.OPEN) {
|
|
console.error(`Client ${clientId} is not available or not connected.`);
|
|
fireNotify(`Client ${clientId} is not connected.`, "error");
|
|
return;
|
|
}
|
|
|
|
client.ws.send("sendcode");
|
|
setTimeout(() => {
|
|
client.ws.send(code);
|
|
}, 500);
|
|
}
|
|
|
|
// Run code on all clients
|
|
runCode() {
|
|
this.clients.forEach((clientData, clientId) => {
|
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
|
clientData.ws.send("runcode");
|
|
}
|
|
});
|
|
}
|
|
|
|
// Run code on a specific client
|
|
runCodeOnClient(clientId) {
|
|
const client = this.clients.get(clientId);
|
|
if (!client || client.ws.readyState !== WebSocket.OPEN) {
|
|
console.error(`Client ${clientId} is not available or not connected.`);
|
|
fireNotify(`Client ${clientId} is not connected.`, "error");
|
|
return;
|
|
}
|
|
|
|
client.ws.send("runcode");
|
|
}
|
|
|
|
// Disconnect all clients
|
|
disconnectAllClients() {
|
|
this.clients.forEach((clientData, clientId) => {
|
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
|
clientData.ws.send("exit");
|
|
clientData.ws.close();
|
|
fireNotify(`Client ${clientId} disconnected`, "warning");
|
|
}
|
|
});
|
|
this.clients.clear();
|
|
}
|
|
|
|
// Send a command to a specific client
|
|
sendCommandToClient(clientId, command, expectResponse = false) {
|
|
const client = this.clients.get(clientId);
|
|
if (!client || client.ws.readyState !== WebSocket.OPEN) {
|
|
console.error(`Client ${clientId} is not available or not connected.`);
|
|
fireNotify(`Client ${clientId} is not connected.`, "error");
|
|
return;
|
|
}
|
|
|
|
client.ws.send(command);
|
|
|
|
if (expectResponse) {
|
|
client.ws.on('message', (response) => {
|
|
console.log(`Response from Client ${clientId}: ${response}`);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Send a command to all clients
|
|
sendCommandToAll(command, expectResponse = false) {
|
|
for (const [clientId, clientData] of this.clients.entries()) {
|
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
|
clientData.ws.send(command);
|
|
|
|
if (expectResponse) {
|
|
clientData.ws.on('message', (response) => {
|
|
console.log(`Response from Client ${clientId}: ${response}`);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = { CCRemote };
|