local lamp = peripheral.find "colorful_lamp" lamp.setLampColor(32767) local sensor = peripheral.find "plethora:sensor" local label = os.getComputerLabel() local switch_config = dofile "config.lua" local function spudnet() if not http or not http.websocket then return "Websockets do not actually exist on this platform" end local ws local function send_packet(msg) local ok, err = pcall(ws.send, textutils.serialiseJSON(msg)) if not ok then printError(err) try_connect_loop() end end local function send(data) send_packet { type = "send", channel = "comm:arr", data = data } end local function connect() if ws then ws.close() end ws, err = http.websocket "wss://spudnet.osmarks.net/v4?enc=json" if not ws then print("websocket failure %s", err) return false end ws.url = "wss://spudnet.osmarks.net/v4?enc=json" send_packet { type = "identify", implementation = "ARR switching unit", key = settings.get "spudnet_key" } send_packet { type = "set_channels", channels = { "comm:arr" } } print("websocket connected") return true end local function try_connect_loop() while not connect() do sleep(0.5) end end try_connect_loop() local function recv() while true do local e, u, x = os.pullEvent "websocket_message" if u == ws.url then return textutils.unserialiseJSON(x) end end end local ping_timeout_timer = nil local function ping_timer() while true do local _, t = os.pullEvent "timer" if t == ping_timeout_timer and ping_timeout_timer then -- 15 seconds since last ping, we probably got disconnected print "SPUDNET timed out, attempting reconnect" try_connect_loop() end end end local function main() while true do local packet = recv() if packet.type == "ping" then send_packet { type = "pong", seq = packet.seq } if ping_timeout_timer then os.cancelTimer(ping_timeout_timer) end ping_timeout_timer = os.startTimer(15) elseif packet.type == "error" then print("SPUDNET error", packet["for"], packet.error, packet.detail, textutils.serialise(packet)) elseif packet.type == "message" then os.queueEvent("spudnet_message", packet.data) end end end return send, function() parallel.waitForAll(ping_timer, main) end end local spudnet_send, spudnet_handler = spudnet() local directions = { ["+ "] = "east", [" +"] = "south", ["- "] = "west", [" -"] = "north" } local function direction_name(vec) local function symbol(v) if math.abs(v) < 0.1 then return " " elseif v < 0 then return "-" else return "+" end end return directions[symbol(vec.x) .. symbol(vec.z)] end local function main() while true do local entities = sensor.sense() for _, entity in pairs(entities) do entity.position = vector.new(entity.x, entity.y, entity.z) + switch_config.offset entity.velocity = vector.new(entity.motionX, entity.motionY, entity.motionZ) end table.sort(entities, function(a, b) return a.position:length() < b.position:length() end) local carts = {} for _, entity in pairs(entities) do if entity.displayName == "entity.MinecartRideable.name" then entity.riders = {} table.insert(carts, entity) break end end local new_carts = {} local relevant_carts = 0 for _, cart in pairs(carts) do local new = { pos = direction_name(cart.position), dir = direction_name(cart.velocity), distance = cart.position:length(), riders = {}, id = cart.id } for _, entity in pairs(entities) do if entity.displayName ~= "entity.MinecartRideable.name" and entity ~= cart and (cart.position - entity.position):length() < 1 then table.insert(new.riders, entity.displayName) break end end if new.dir and #new.riders > 0 then relevant_carts = relevant_carts + 1 end table.insert(new_carts, new) end spudnet_send { id = label, type = "sw_ping", carts = new_carts } if relevant_carts == 0 then sleep(0.5) elseif relevant_carts == 1 then sleep(0.25) else sleep(0.1) end end end local function spudnet_listen() while true do local _, data = os.pullEvent "spudnet_message" if type(data) == "table" and data.type == "sw_cmd" and (data.id == label or data.id == nil) then --print(data.type, data.cmd) if data.cmd == "set" then print("set") if data.lamp then lamp.setLampColor(data.lamp) end if data.switch ~= nil then rs.setOutput(switch_config.side, data.switch == 1) end spudnet_send { type = "sw_ack", cid = data.cid } elseif data.cmd == "update" then local h, e = http.get "https://pastebin.com/raw/g9gfxwsb" if not h then printError(e) else lamp.setLampColor(1023) local t = h.readAll() h.close() local f, e = load(t) if f then local f = fs.open("startup", "w") f.write(t) f.close() print "reboot" sleep(1) os.reboot() else printError(e) end end end end end end parallel.waitForAll(spudnet_handler, main, spudnet_listen)