mirror of
https://github.com/osmarks/random-stuff
synced 2024-12-28 02:50:33 +00:00
88 lines
2.9 KiB
Lua
88 lines
2.9 KiB
Lua
|
local function spudnet()
|
||
|
local channel = settings.get "offload_channel"
|
||
|
|
||
|
if not http or not http.websocket then return "Websockets do not actually exist on this platform" end
|
||
|
|
||
|
local ws
|
||
|
local try_connect_loop, recv
|
||
|
|
||
|
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 assert_ok(packet)
|
||
|
if packet.type == "error" then error(("%s %s %s"):format(packet["for"], packet.error, packet.detail)) end
|
||
|
end
|
||
|
|
||
|
local function connect()
|
||
|
if ws then ws.close() end
|
||
|
local err
|
||
|
local url = "wss://spudnet.osmarks.net/v4?enc=json&rand=" .. math.random(0, 0xFFFFFFF)
|
||
|
ws, err = http.websocket(url)
|
||
|
if not ws then print("websocket failure %s", err) return false end
|
||
|
ws.url = url
|
||
|
|
||
|
send_packet { type = "identify", implementation = "ni-ctl SPUDNET interface", key = settings.get "spudnet_key" }
|
||
|
assert_ok(recv())
|
||
|
send_packet { type = "set_channels", channels = {channel} }
|
||
|
assert_ok(recv())
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
recv = function()
|
||
|
while true do
|
||
|
local e, u, x, y = os.pullEvent()
|
||
|
if e == "websocket_message" and u == ws.url then
|
||
|
return textutils.unserialiseJSON(x)
|
||
|
elseif e == "websocket_closed" and u == ws.url then
|
||
|
printError(("websocket: %s/%d"):format(x, y or 0))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
try_connect_loop = function()
|
||
|
while not connect() do
|
||
|
sleep(0.5)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
try_connect_loop()
|
||
|
|
||
|
local function send(data)
|
||
|
send_packet { type = "send", channel = channel, data = data }
|
||
|
assert_ok(recv())
|
||
|
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, packet)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return send, function() parallel.waitForAll(ping_timer, main) end
|
||
|
end
|
||
|
|
||
|
return spudnet
|