update 1.6

support multiple upload to machine and make remote script to one file and support to run on startup
This commit is contained in:
dharm pimsen 2024-11-24 14:33:49 +07:00
parent a5ac8c99c8
commit 5200e86f7d
10 changed files with 469 additions and 208 deletions

View File

@ -1,50 +0,0 @@
local ws = assert(http.websocket("ws://127.0.0.1:5133"))
print("connected to server")
local id
local isrunning = true
function exitcheck()
while true do
local event = os.pullEventRaw("terminate")
if event == "terminate" then
print("Exiting...")
isrunning = false
ws.close()
break
end
end
end
function main()
while isrunning do
print("ready")
local message, error = ws.receive()
if message then
print("Received message:", message)
if message == "ping" then
ws.send("pong")
elseif message == "sendcode" then
local file = io.open("main.lua", "w")
print("waiting for code")
local filedata, error = ws.receive()
file:write(filedata)
file:close()
elseif message == "runcode" then
id = multishell.launch({}, "main.lua")
multishell.setTitle(id, "Code")
multishell.setFocus(id)
elseif message == "exit" then
print("Exiting...")
break
end
else
print("WebSocket error:", error)
break
end
end
end
parallel.waitForAny(exitcheck, main)
print("Exited")

View File

@ -1,6 +1,6 @@
{
"name": "ccide",
"version": "1.5",
"version": "1.6",
"description": "ComputerCraft mod virtual lua IDE",
"main": "index.js",
"scripts": {

View File

@ -6,34 +6,18 @@ special thank for [ccblockly](https://github.com/Mirka1405/ccblockly) for idea
![Screenshot 2024-08-20 202018](https://github.com/user-attachments/assets/ba6c1ca6-ce91-41c9-b412-b1f3a8f2e735)
# Quick Start
1. install nodejs and git
2. git clone cd to this project
3. Install dependency use `npm install .`
1. install nodejs and git.
2. git clone and cd to this project .
3. Install dependency use `npm install .`.
4. To run this IDE use `npm run dev` or if you using windows you can use `run.bat` to run it.
5. Done!
## Install Remote code into computercraft
it very simple! to install Remote code.
### Run from URL
for advanced computer/pocket/turtle
```
wget run https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/advremote.lua
```
for non advance computer/pocket/turtle
```
wget run https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/remote.lua
```
### Download and Run
for advanced computer/pocket/turtle
```
wget https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/advremote.lua advremote.lua
advremote
```
for non advanced computer/pocket/turtle
```
wget https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/remote.lua remote.lua
remote
wget https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/startup.lua
```
And restart the computer.
If error "Domain not permitted" try [this solution](https://github.com/cc-tweaked/CC-Tweaked/discussions/626#discussioncomment-241924).
## official support library, peripheral and module function
@ -150,7 +134,7 @@ https://github.com/user-attachments/assets/195231d4-8fd8-4101-8068-70bc038a5c4f
https://github.com/user-attachments/assets/8f114cfa-d87c-47d0-a670-a13dc975ab06
# For adapting in other project
This project is based for every block based IDE from DPSoftware Foundation
This project is for every block based IDE from DPSoftware Foundation.
# License
This project is licensed under the [GPL v3 License](https://github.com/DPSoftware-Foundation/ccIDE/blob/main/LICENSE).

View File

@ -1,48 +0,0 @@
local ws = assert(http.websocket("ws://127.0.0.1:5133"))
print("connected to server")
local id
local isrunning = true
function exitcheck()
while true do
local event = os.pullEventRaw("terminate")
if event == "terminate" then
print("Exiting...")
isrunning = false
ws.close()
break
end
end
end
function main()
while isrunning do
print("ready")
local message, error = ws.receive()
if message then
print("Received message:", message)
if message == "ping" then
ws.send("pong")
elseif message == "sendcode" then
local file = io.open("main.lua", "w")
print("waiting for code")
local filedata, error = ws.receive()
file:write(filedata)
file:close()
elseif message == "runcode" then
shell.run("main")
elseif message == "exit" then
print("Exiting...")
break
end
else
print("WebSocket error:", error)
break
end
end
end
parallel.waitForAny(exitcheck, main)
print("Exited")

View File

@ -7,105 +7,258 @@ class CCRemote {
host: ip
});
console.log("Remote server is started");
this.clients = new Map(); // Map to track client data (numeric IDs)
this.clientIdCounter = 0; // Counter for numeric client IDs
fireNotify("Computer isn't connect", "warning", "https://github.com/DPSoftware-Foundation/ccIDE#install-remote-code-into-computercraft")
console.log("Remote server is started");
fireNotify(
"Remote server started, waiting for clients to connect...",
"info"
);
this.socket.on('connection', (ws) => {
document.getElementById("navbar-button-computer-disconnect").disabled = false;
document.getElementById("navbar-button-computer-run").disabled = false;
const clientId = this.clientIdCounter++;
this.clients.set(clientId, { ws, isAlive: true, name: `Client-${clientId}`, clientInfo: null });
fireNotify("Computer connected", "success")
if (this.clients.size >= 0) {
document.getElementById("navbar-button-computer-disconnect").disabled = false;
document.getElementById("navbar-button-computer-run").disabled = false;
}
console.log('WebSocket connection established.');
console.log(`Client ${clientId} connected.`);
fireNotify(`Client ${clientId} connected`, "success");
// Send "info" command to the client immediately upon connection
this.sendCommandToClient(clientId, 'info', true);
// Set up heartbeat
ws.isAlive = true;
ws.on('pong', () => {
ws.isAlive = true;
this.clients.get(clientId).isAlive = true;
});
ws.on('message', (message) => {
console.log(`Received 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', () => {
document.getElementById("navbar-button-computer-disconnect").disabled = true;
document.getElementById("navbar-button-computer-run").disabled = true;
console.log(`Client ${clientId} disconnected.`);
this.clients.delete(clientId);
fireNotify(`Client ${clientId} disconnected`, "warning");
fireNotify("Computer 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 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(() => {
this.socket.clients.forEach((ws) => {
if (ws.isAlive === false) {
console.log('Client did not respond to ping, terminating connection.');
return ws.terminate();
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;
}
ws.isAlive = false;
ws.ping();
});
}, 1000);
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");
});
}
isClientConnect() {
for (const client of this.socket.clients) {
if (client.readyState === WebSocket.OPEN) {
return true;
// 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);
}
}
return false;
// 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;
}
sendCommand(command) {
this.socket.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(command);
}
});
// Check if any client is connected
isClientConnect() {
return this.clients.size > 0;
}
sendCode(Code) {
this.socket.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send("sendcode");
// Send code to all clients
sendCode(code) {
this.clients.forEach((clientData, clientId) => {
if (clientData.ws.readyState === WebSocket.OPEN) {
clientData.ws.send("sendcode");
setTimeout(() => {
client.send(Code);
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.socket.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send("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.socket.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.close();
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}`);
});
}
}
}
}
}

View File

@ -9,6 +9,16 @@ const circles = document.querySelectorAll(".circle");
let upcurrentActive = 1;
let uploadError = false; // Flag to track if there's an error
const defineicon = {
5: path.join(__dirname, '..', 'assets', 'basic_computer.png'),
6: path.join(__dirname, '..', 'assets', 'adv_computer.png'),
7: path.join(__dirname, '..', 'assets', 'command_computer.png'),
2: path.join(__dirname, '..', 'assets', 'pocket_computer.png'),
4: path.join(__dirname, '..', 'assets', 'adv_pocket_computer.png'),
1: path.join(__dirname, '..', 'assets', 'turtle.png'),
3: path.join(__dirname, '..', 'assets', 'adv_turtle.png')
}
const uploadUpdateProgress = () => {
circles.forEach((circle, index) => {
if (index < upcurrentActive) {
@ -34,7 +44,6 @@ const uploadUpdateProgress = () => {
};
function clientexit() {
ccInstance.sendCommand("exit")
ccInstance.disconnectAllClients();
}
@ -42,15 +51,17 @@ function gencodeonly() {
return luaGenerator.workspaceToCode(workspace);
}
let selectedClientId = null;
async function gencode() {
console.log("Starting generate code")
document.getElementById('upload-popup').style.display = 'block';
upcurrentActive = 1;
uploadError = false;
uploadUpdateProgress();
// compile/convert code
console.log("Generating code...")
// Compile/convert code
console.log("Generating code...");
upcurrentActive++;
uploadUpdateProgress();
document.getElementById('upload-status').textContent = "Generating code";
@ -61,37 +72,108 @@ async function gencode() {
uploadError = true;
uploadUpdateProgress();
document.getElementById('upload-status').textContent = e;
return
return;
}
upcurrentActive++;
uploadUpdateProgress();
if (ccInstance.isClientConnect()) {
// upload to computercraft with remote
console.log("Uploading code to machine...")
document.getElementById('upload-status').textContent = "Uploading code to machine";
ccInstance.sendCode(code);
await delay(500)
// execute with remote
console.log("Executing code in machine...")
document.getElementById('upload-status').textContent = "Executing code";
upcurrentActive++;
uploadUpdateProgress();
ccInstance.runCode();
if (ccInstance.isClientConnect()) {
const clients = await ccInstance.listClients();
document.getElementById('upload-status').innerHTML = "";
const ClientLists = document.createElement('div');
ClientLists.classList.add("library-content");
clients.forEach(client => {
console.log(`Info:`, client.info);
const ClientItem = document.createElement('div');
ClientItem.classList.add('library-item', 'overflow-auto', 'library-container');
ClientItem.setAttribute('data-clientid', client.id);
const img = document.createElement('img');
img.classList.add('libimage');
img.src = defineicon[client.info.Type];
ClientItem.appendChild(img);
const ClientDetails = document.createElement('div');
ClientDetails.classList.add('library-details');
const title = document.createElement('h3');
title.textContent = client.info.Name;
ClientDetails.appendChild(title);
const description = document.createElement('p');
description.innerHTML = `OS: ${client.info.OSVersion} | ID: ${client.info.ID} | Uptime: ${client.info.uptime}s`;
ClientDetails.appendChild(description);
ClientItem.appendChild(ClientDetails);
// Add event listener for user selection
ClientItem.addEventListener('click', () => {
selectedClientId = client.id; // Correctly store the client ID
ClientItem.classList.add('selected'); // Optional: Style selected item
});
ClientLists.appendChild(ClientItem);
});
const title = document.createElement("h3");
title.textContent = "Upload to machine";
document.getElementById('upload-status').appendChild(title);
document.getElementById('upload-status').appendChild(ClientLists);
// Wait for user selection
const waitForSelection = () => new Promise((resolve, reject) => {
const checkSelection = setInterval(() => {
if (selectedClientId !== null) {
clearInterval(checkSelection);
resolve(selectedClientId);
}
}, 100); // Check every 100ms if a client is selected
});
// Wait until the user selects a client
try {
const selectedClientId = await waitForSelection();
console.log(`Selected client: ${selectedClientId}`);
document.getElementById('upload-status').innerHTML = "";
// Now proceed with uploading code to the selected client
console.log("Uploading code to machine...");
document.getElementById('upload-status').textContent = "Uploading code to machine";
ccInstance.sendCodeToClient(selectedClientId, code);
await delay(500);
// Execute with remote
console.log("Executing code in machine...");
document.getElementById('upload-status').textContent = "Executing code";
upcurrentActive++;
uploadUpdateProgress();
ccInstance.runCodeOnClient(selectedClientId);
} catch (error) {
console.error("Error waiting for selection:", error);
uploadError = true;
uploadUpdateProgress();
document.getElementById('upload-status').innerHTML = `Error selecting client.`;
}
} else {
console.log("Machine is not connected")
console.log("Machine is not connected");
uploadError = true;
uploadUpdateProgress();
document.getElementById('upload-status').innerHTML = `Please Connect Computer to IDE.\nInstruction: <a href="https://github.com/DPSoftware-Foundation/ccIDE#install-remote-code-into-computercraft">Install Remote code into computercraft</a> in github. (Please press SHIFT or CTRL and click)`;
return
document.getElementById('upload-status').innerHTML = `Please Connect Computer to IDE.\nInstruction: <a href="https://github.com/DPSoftware-Foundation/ccIDE#install-remote-code-into-computercraft">Install Remote code into computercraft</a> in github.`;
return;
}
// done!
console.log("Run code done!")
// Done!
console.log("Run code done!");
document.getElementById('upload-status').textContent = "Done!";
await delay(1000)
await delay(1000);
document.getElementById('upload-popup').style.animation = 'fadeOut 0.3s ease'; // Apply fade-out animation
selectedClientId = null;
setTimeout(function() {
document.getElementById('upload-popup').style.display = 'none'; // Hide popup after animation completes
document.getElementById('upload-popup').style.animation = ''; // Reset animation property

View File

@ -54,8 +54,8 @@
<div id="blocklyDiv"></div>
</section>
<div class="popup" id="upload-popup">
<div class="popup-content">
<div class="popup" id="upload-popup" style="overflow-y:hidden;">
<div class="popup-content p-3" style="max-width: 720px; position: relative; margin-top: 100px;">
<button type="button" class="btn-close float-end" aria-label="Close" id="uploadCloseBtn"></button>
<div class="upload-progress-container" style="text-align: center;">
<div class="progress-container">
@ -73,7 +73,7 @@
<svg viewBox="0 0 24 24"><path d="m20 22-3.86-1.55c.7-1.53 1.2-3.11 1.51-4.72L20 22M7.86 20.45 4 22l2.35-6.27c.31 1.61.81 3.19 1.51 4.72M12 2s5 2 5 10c0 3.1-.75 5.75-1.67 7.83A2 2 0 0 1 13.5 21h-3a2 2 0 0 1-1.83-1.17C7.76 17.75 7 15.1 7 12c0-8 5-10 5-10m0 10c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z" /></svg>
</div>
</div>
<p id="upload-status"></p>
<div id="upload-status"></div>
</div>
</div>
</div>
@ -132,7 +132,6 @@
<img src="../assets/network-require.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Network Require">
</div>
</div>
</div>
</div>
<div class="button-container">

View File

@ -1,10 +1,18 @@
:root {
--line-border-fill: #3498db;
--line-border-empty: #e0e0e0;
--line-border-empty: #7f8c8d; /* Lighter gray for dark mode */
--background-color: #121212; /* Dark background for body */
--text-color: #e0e0e0; /* Lighter text color */
--button-bg: #333; /* Dark button background */
--button-hover-bg: #0066cc; /* Button hover color */
--progress-bg: #3498db; /* Progress bar fill color */
--error-color: #e74c3c; /* Error state color */
}
body {
background-color: #212121;
background-color: var(--background-color);
color: var(--text-color);
font-family: 'Arial', sans-serif;
overflow: hidden; /* Hide scrollbars */
}
@ -88,7 +96,7 @@ body {
}
.navbar-button {
background-color: #2c3e50;
background-color: var(--button-bg);
color: white;
border: none;
border-radius: 50%; /* Make the button circular */
@ -114,7 +122,7 @@ body {
}
.navbar-button:hover {
background-color: #0066cc; /* Darken color on hover */
background-color: var(--button-hover-bg); /* Darken color on hover */
z-index: 99;
}
@ -149,7 +157,8 @@ body {
/* Styles for the upload-popup content */
.popup-content {
background-color: #fefefe;
background-color: #333;
color: #fefefe;
margin: 15% auto; /* Center the upload-popup vertically and horizontally */
padding: 20px;
border: 1px solid #888;
@ -203,7 +212,7 @@ body {
}
.progress {
background-color: var(--line-border-fill);
background-color: var(--progress-bg);
position: absolute;
top: 50%;
left: 0;
@ -215,10 +224,9 @@ body {
}
.progress.error {
background-color: red; /* Set to red color for error state */
background-color: var(--error-color); /* Set to red color for error state */
}
.circle {
background-color: #fff;
color: #999;
@ -238,7 +246,7 @@ body {
}
.circle.error {
border-color: red; /* Optionally, change border color to red */
border-color: var(--error-color); /* Optionally, change border color to red */
color: white; /* Optionally, adjust text color for visibility */
}
@ -268,10 +276,10 @@ body {
.library-item {
cursor: pointer;
padding: 10px;
border-bottom: 1px solid #e9ecef;
border-bottom: 1px solid #7f8c8d; /* Lighter border */
}
.library-item.selected {
background-color: #e9ecef;
background-color: #34495e; /* Darker background for selected items */
}
.library-content {
flex: 1;
@ -280,11 +288,27 @@ body {
max-height: 720px; /* Ensure a max height for scrolling */
}
.library-item:hover {
background-color: #cacaca;
background-color: #7f8c8d; /* Hover effect for items */
}
.button-container {
display: flex;
justify-content: flex-end;
gap: 10px;
justify-content: center;
align-items: center;
margin-top: 10px;
}
.btn-invisible {
background: transparent;
border: none;
padding: 5px;
cursor: pointer;
}
.swipe-text {
font-size: 14px;
color: #ccc;
}
.pointer-pointer {
cursor: pointer;
}

117
startup.lua Normal file
View File

@ -0,0 +1,117 @@
print("checking computer type...")
local machineType = 0
local isAdvanced = false
local isPocket = false
local isTurtle = false
local isCommand = false
-- Check if advanced (multishell exists in advanced computers and advanced pocket computers)
if multishell then
isAdvanced = true
end
-- Check if Pocket Computer (API specific to Pocket Computers)
if pocket then
isPocket = true
end
-- Check if Turtle (turtle API is available for turtles)
if turtle then
isTurtle = true
end
if commands then
isCommand = true
end
-- Determine machine type
if isTurtle then
if isAdvanced then
machineType = 3 -- Advanced Turtle
else
machineType = 1 -- Standard Turtle
end
elseif isPocket then
if isAdvanced then
machineType = 4 -- Advanced Pocket Computer
else
machineType = 2 -- Standard Pocket Computer
end
else
if isAdvanced then
if isCommand then
machineType = 7 -- Command Computer
else
machineType = 6 -- Advanced Computer
end
else
machineType = 5 -- Standard Computer
end
end
print("Machine Type: " .. machineType)
print("connecting to IDE...")
local ws = assert(http.websocket("ws://127.0.0.1:5133"))
print("connected to server")
local id
local isrunning = true
function exitcheck()
while true do
local event = os.pullEventRaw("terminate")
if event == "terminate" then
print("Exiting...")
isrunning = false
ws.close()
break
end
end
end
function main()
while isrunning do
print("ready")
local message, error = ws.receive()
if message then
print("Received message:", message)
if message == "ping" then
ws.send("pong")
elseif message == "info" then
info = {
OSVersion = os.version(),
ID = os.getComputerID(),
Name = os.getComputerLabel() or "No Name",
Type = machineType,
uptime = os.clock()
}
ws.send(textutils.serialiseJSON(info))
elseif message == "sendcode" then
local file = io.open("main.lua", "w")
print("waiting for code")
local filedata, error = ws.receive()
file:write(filedata)
file:close()
elseif message == "runcode" then
if isAdvanced then
id = multishell.launch({}, "main.lua")
multishell.setTitle(id, "Code")
multishell.setFocus(id)
else
shell.run("main")
end
elseif message == "exit" then
print("Exiting...")
break
end
else
print("WebSocket error:", error)
break
end
end
end
parallel.waitForAny(exitcheck, main)
print("Exited")