local secretToken = "$TOKEN" local connectionUri = "$HOST" local waitSeconds = 5 -- https://github.com/cc-tweaked/CC-Tweaked/blob/9cf70b10effeeed23e0e9c537bbbe0b2ff0d1a0f/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java#L29 -- Chunk size must be less than packet size (type reply, success, chunkids, content: chunk) 16 kb for buffer local maxMessageSize = (128 - 16) * 1024 local function chunkString(value, chunkSize) if not chunkSize then chunkSize = maxMessageSize end local length = value:len() local total = math.ceil(length / chunkSize) local chunks = {} if length == 0 then total = 1 chunks[1] = "" else local i = 1 for i=1,total do local pos = 1 + ((i - 1) * chunkSize) chunks[i] = value:sub(pos, pos + chunkSize - 1) end end return total, chunks end local function sendJson(socket, message) return socket.send(textutils.serializeJSON(message)) end local function sendResponse(socket, id, result, success) if success == nil then success = 0 end local total, chunks = chunkString(result) for i, chunk in pairs(chunks) do sendJson(socket, { type = "reply", id = id, result = chunk, chunk = i, total = total, success = success }) end end -- error: no rs system -- return rssystem rs local function getPeripheral(name) local dev = peripheral.find(name) if not dev then error({message = "No peripheral '"..name.."' attached to the computer!"}) end return dev end local function runRsCommand(params) local script, reason = loadstring("local rs = peripheral.find(\"rsBridge\") if not rs then error({message = \"RS Bridge is not attached!\"}) end return rs."..params.command) if not script then error({message = "Invalid command: "..reason.."!"}) end local result = table.pack(pcall(script)) local success = result[1] if not success then error({message = "Command execution failed: "..result[2].."!"}) end local retvals = {} retvals.n = result.n - 1 for i=1,retvals.n do retvals[tostring(i)] = result[i + 1] end return textutils.serializeJSON(retvals) end local function getPeripheralInfo(side) return {type = peripheral.getType(side), methods = peripheral.getMethods(side), side = side} end local function getPeripheralList() local pers = {} for i,side in pairs(peripheral.getNames()) do pers[side] = getPeripheralInfo(side) end return pers end -- error: any error during execution -- return string result local function getResponse(parsed) if parsed.method == "energyusage" then return tostring(getPeripheral("rsBridge").getEnergyUsage()) elseif parsed.method == "energystorage" then return tostring(getPeripheral("rsBridge").getEnergyStorage()) elseif parsed.method == "listitems" then return textutils.serializeJSON(getPeripheral("rsBridge").listItems()) elseif parsed.method == "listfluids" then return textutils.serializeJSON(getPeripheral("rsBridge").listFluids()) elseif parsed.method == "craft" then return tostring(getPeripheral("rsBridge").craftItem(parsed.params)) elseif parsed.method == "getitem" then local item = getPeripheral("rsBridge").getItem(parsed.params) if not item then error({message = "Requested item not found!"}) end return textutils.serializeJSON(item) elseif parsed.method == "command" then return runRsCommand(parsed.params) elseif parsed.method == "peripherals" then return textutils.serializeJSON(getPeripheralList()) elseif parsed.method == "getonline" then return textutils.serializeJSON(getPeripheral("playerDetector").getOnlinePlayers()) elseif parsed.method == "whereis" then local pos = getPeripheral("playerDetector").getPlayerPos(parsed.params.username) if not pos then return "null" end return textutils.serializeJSON(pos) elseif parsed.method == "send" then if not parsed.params.username then getPeripheral("chatBox").sendMessage(parsed.params.message, parsed.params.prefix) else getPeripheral("chatBox").sendMessageToPlayer(parsed.params.message, parsed.params.username, parsed.params.prefix) end return "true" end error({message = "No message handler for method: "..parsed.method.."!"}) end local function logJSON(json, prefix) if not prefix then prefix = "" end for k,v in pairs(json) do local key = prefix..k if type(v) == "table" then logJSON(v, key..".") else print(key, "=", textutils.serializeJSON(v)) end end end -- return bool success local function handleMessage(socket, message) local parsed, reason = textutils.unserializeJSON(message) if not parsed then print("Received message:", message) printError("Message could not be parsed:", reason) return false end pcall(function() print("Received JSON:") logJSON(parsed) end) if parsed.type == "request" then local success, result = pcall(function() return getResponse(parsed) end) if not success then if not result.message then sendResponse(socket, parsed.id, result, 2) else sendResponse(socket, parsed.id, result.message, 1) end else sendResponse(socket, parsed.id, result, 0) end return true end printError("Invalid message type:", parsed.type) return false end local function responder(socket) while true do local message, binary = socket.receive() if not not message and not binary then if message == "outdated" then printError("Current script is outdated! Please update from the host!") return end handleMessage(socket, message) end end end local function termWaiter() os.pullEvent("terminate") end local function chatEventListener(socket) while true do event, username, message, uuid, hidden = os.pullEvent("chat") sendJson(socket, {type = "chat", username = username, message = message, uuid = uuid, hidden = hidden}) print("Chat event relayed!") end end local function peripheralDetachEventListener(socket) while true do event, side = os.pullEvent("peripheral_detach") sendJson(socket, {type = "peripheral_detach", side = side}) print("Peripheral was detached!") end end local function peripheralAttachEventListener(socket) while true do event, side = os.pullEvent("peripheral") sendJson(socket, {type = "peripheral", peripheral = getPeripheralInfo(side) }) print("Peripheral was attached!") end end local function eventListeners(socket) parallel.waitForAny( termWaiter, function() chatEventListener(socket) end, function() peripheralDetachEventListener(socket) end, function() peripheralAttachEventListener(socket) end ) end local function socketClient() print("Connecting to the socket server at "..connectionUri.."...") local socket, reason = http.websocket(connectionUri) if not socket then error("Socket server could not be reached: "..reason) end print("Connection successful!") socket.send("login="..secretToken) parallel.waitForAny( function() responder(socket) end, function() eventListeners(socket) end ) socket.close() end local function main() while true do local status, error = pcall(socketClient) if status then break end printError("An uncaught exception was raised:", error) printError("Restarting in", waitSeconds, "seconds...") sleep(waitSeconds) end end local oldPullEvent = os.pullEvent os.pullEvent = os.pullEventRaw pcall(main) os.pullEvent = oldPullEvent