local mt = dofile "/lib/multitask.lua" local p = mt.newPool({crash_on_error = true}) local spudnet = {} local api = {} spudnet.api = api spudnet.init = function(o) o = o or {} o.on_init = o.on_init or function() end if not o.channel then error("no channel specified") end if not o.mode then error("no mode specified") end o.subchannels = o.subchannels or {} local url = "wss://spudnet.osmarks.net/v4?enc=json&force_binary=true" local ws = nil local since_last_ping = os.epoch"utc" local init for i,v in ipairs(o.subchannels) do o.subchannels[i]=o.mode..":"..o.channel.."/"..v end local get_spudmsg = function(filter) while true do local e, url_, data = coroutine.yield("websocket_message") data = textutils.unserializeJSON(data) if url_ == url then if not filter or filter == data.type then return data end end end end api.send_raw = function(data) return p.add(function(this) local x = pcall(ws.send,textutils.serializeJSON(data),true) if not x then p.clear() p.add(init,{name="spudnet_init"}) end end) end api.send_raw_sync = function(data) local id = math.random(1,0xFFFFFF) data.cid = id p.await(api.send_raw(data)) while true do local m = get_spudmsg("ok") if m.cid == id then return true end end end api.receive = function(filter) while true do local m = get_spudmsg("message").data if filter then if m.type == filter then return m end else return m end end end api.send = function(data,subchannel) api.send_raw({ type="send", data=data, channel=o.mode..":"..o.channel.."/"..subchannel }) end api.send_sync = function(data,subchannel) api.send_raw_sync({ type="send", data=data, channel=o.mode..":"..o.channel.."/"..subchannel }) end local error_handler = function() while true do local a = get_spudmsg("error") if a.error == "timeout" then p.clear() p.add(init,{name="spudnet_init"}) else error("Error from SPUDNET ('"..(a["error"] or a["for"]).."'): "..a.detail) end end end local ping_handler = function() while true do local a = get_spudmsg("ping").seq since_last_ping = os.epoch"utc" api.send_raw({ type="pong", seq = a, }) os.queueEvent("spudnet_ping",seq) end end local terminate_handler = function() local x = os.pullEventRaw("terminate") if ws then ws.close() end p.clear() end local timeout_handler = function() while true do sleep(1) if os.epoch"utc" - since_last_ping >= 15000 then p.clear() p.add(init,{name="spudnet_init"}) os.queueEvent("spudnet_timeout") end end end init = function() p.add(terminate_handler,{name="spudnet_termination_handler"}) if ws then ws.close() end ws = nil while true do ws = http.websocket(url) if ws then break end sleep(0.3) end p.add(error_handler,{name="spudnet_error_handler"}) p.add(ping_handler,{name="spudnet_ping_handler"}) p.add(timeout_handler,{name="spudnet_timeout_handler"}) api.send_raw_sync({ type="identify", key=o.key, channels=o.subchannels, }) p.add(o.on_init) os.queueEvent("spudnet_ready") end p.add(init,{name="spudnet_init"}) p.run(false) end spudnet.pool = p return spudnet