152 lines
3.2 KiB
Lua
152 lines
3.2 KiB
Lua
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
|