Refactor socket into socket.lua
This commit is contained in:
parent
226aba437a
commit
fb22cc7528
@ -136,4 +136,4 @@ local function wrap(parent: term.Redirect): Buffer
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return { wrap = wrap }
|
return { wrap = wrap, Buffer = Buffer, ScreenContent = ScreenContent }
|
@ -1,7 +1,7 @@
|
|||||||
default:
|
default:
|
||||||
@just --list
|
@just --list
|
||||||
|
|
||||||
teal_files := "main.tl framebuffer.tl ringbuffer.tl"
|
teal_files := "main.tl framebuffer.tl ringbuffer.tl socket.tl"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
mkdir -p out
|
mkdir -p out
|
||||||
|
89
lua/main.tl
89
lua/main.tl
@ -1,74 +1,20 @@
|
|||||||
local json = require("json")
|
local json = require("json")
|
||||||
local fb = require("framebuffer")
|
local Framebuffer = require("framebuffer")
|
||||||
local ringbuffer = require("ringbuffer")
|
local Ringbuffer = require("ringbuffer")
|
||||||
|
local Socket = require("socket")
|
||||||
local UUID <const> = "8b9faf9f-9470-4a50-b405-0af5f0152550"
|
local UUID <const> = "8b9faf9f-9470-4a50-b405-0af5f0152550"
|
||||||
local ENDPOINT <const> = "ws://localhost:8000/ipmi/computer/" .. UUID .. "/ws"
|
local ENDPOINT <const> = "ws://localhost:8000/ipmi/computer/" .. UUID .. "/ws"
|
||||||
|
|
||||||
print("[MAIN] Init")
|
print("[MAIN] Init")
|
||||||
|
|
||||||
local enum SocketState
|
local socket = Socket.new(ENDPOINT)
|
||||||
"reset"
|
|
||||||
"error"
|
|
||||||
"ok"
|
|
||||||
"viewer_connected"
|
|
||||||
end
|
|
||||||
|
|
||||||
local BAD_STATES <const> : {SocketState: boolean} = {
|
|
||||||
["reset"] = true,
|
|
||||||
["error"] = true,
|
|
||||||
}
|
|
||||||
|
|
||||||
local type SocketStateCallback = function(new_state: SocketState)
|
|
||||||
|
|
||||||
local record Socket
|
|
||||||
state: SocketState
|
|
||||||
bad_state: function(self: Socket): boolean
|
|
||||||
set_state: function(self: Socket, state: SocketState)
|
|
||||||
on_state_change: function(self: Socket, cb: SocketStateCallback)
|
|
||||||
_callback: SocketStateCallback
|
|
||||||
ws: http.Websocket
|
|
||||||
end
|
|
||||||
|
|
||||||
local socket: Socket = {
|
|
||||||
state = "reset",
|
|
||||||
bad_state = function(self: Socket): boolean
|
|
||||||
return BAD_STATES[self.state] ~= nil
|
|
||||||
end,
|
|
||||||
set_state = function(self: Socket, state: SocketState)
|
|
||||||
self.state = state
|
|
||||||
self._callback(state)
|
|
||||||
end,
|
|
||||||
on_state_change = function(self: Socket, cb: SocketStateCallback)
|
|
||||||
self._callback = cb
|
|
||||||
end,
|
|
||||||
_callback = function(_: SocketState) end,
|
|
||||||
ws = nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
local function send(message: string)
|
|
||||||
-- "message" needs to be valid JSON
|
|
||||||
-- otherwise the server will not accept it
|
|
||||||
|
|
||||||
if socket:bad_state() then return end
|
|
||||||
|
|
||||||
local r = { pcall(socket.ws.send, message) }
|
|
||||||
|
|
||||||
if r[1] == false then
|
|
||||||
if (r[2] as string):sub(-11) == "closed file" then
|
|
||||||
socket:set_state("reset")
|
|
||||||
elseif (r[2] as string):sub(-9) == "too large" then
|
|
||||||
-- TODO handle
|
|
||||||
-- the connection stays open though
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set up framebuffer capture and statusline
|
-- Set up framebuffer capture and statusline
|
||||||
|
|
||||||
print("[MAIN] Setup framebuffer")
|
print("[MAIN] Setup framebuffer")
|
||||||
|
|
||||||
local orig_native = term.native
|
local orig_native = term.native
|
||||||
local buffer = fb.wrap(orig_native())
|
local buffer = Framebuffer.wrap(orig_native())
|
||||||
term.native = function(): term.Redirect
|
term.native = function(): term.Redirect
|
||||||
return buffer.target
|
return buffer.target
|
||||||
end
|
end
|
||||||
@ -89,30 +35,21 @@ end
|
|||||||
|
|
||||||
-- Create tasks
|
-- Create tasks
|
||||||
|
|
||||||
local bar_codes: { SocketState: {string} } = {
|
local bar_codes: { Socket.State: {string} } = {
|
||||||
["reset"] = {"[WS] RST", "78870111"},
|
["reset"] = {"[WS] RST", "78870111"},
|
||||||
["error"] = {"[WS] ERR", "78870EEE"},
|
["error"] = {"[WS] ERR", "78870EEE"},
|
||||||
["ok"] = {"[WS] OK\x03", "78870DD5"},
|
["ok"] = {"[WS] OK\x03", "78870DD5"},
|
||||||
["viewer_connected"] = {"[WS] CON", "78870999"},
|
["viewer_connected"] = {"[WS] CON", "78870999"},
|
||||||
}
|
}
|
||||||
|
|
||||||
socket:on_state_change(function(new_state: SocketState)
|
socket:on_state_change(function(new_state: Socket.State)
|
||||||
set_bar(table.unpack(bar_codes[new_state]))
|
set_bar(table.unpack(bar_codes[new_state]))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local ws_task = coroutine.create(function()
|
local ws_task = coroutine.create(function()
|
||||||
while true do
|
while true do
|
||||||
if socket:bad_state() then
|
if socket:is_bad_state() then
|
||||||
--set_bar("[WS] RST", "78870111")
|
socket:reconnect()
|
||||||
local r = http.websocket(ENDPOINT)
|
|
||||||
if r ~= false then
|
|
||||||
socket.ws = r as http.Websocket
|
|
||||||
--set_bar("[WS] OK\x03", "78870DD5")
|
|
||||||
socket:set_state("ok")
|
|
||||||
else
|
|
||||||
socket:set_state("error")
|
|
||||||
--set_bar("[WS] ERR", "78870EEE")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
sleep(1)
|
sleep(1)
|
||||||
end
|
end
|
||||||
@ -127,7 +64,7 @@ local report_task = coroutine.create(function()
|
|||||||
local message = json.encode({
|
local message = json.encode({
|
||||||
screen = buffer.serialize()
|
screen = buffer.serialize()
|
||||||
})
|
})
|
||||||
send(message)
|
socket:send(message)
|
||||||
last_report = now
|
last_report = now
|
||||||
end
|
end
|
||||||
sleep(0) -- until next gametick
|
sleep(0) -- until next gametick
|
||||||
@ -151,7 +88,7 @@ local tasks: {Task} = {
|
|||||||
{coro = report_task},
|
{coro = report_task},
|
||||||
}
|
}
|
||||||
|
|
||||||
local event_queue = ringbuffer.new(64)
|
local event_queue: Ringbuffer.Ringbuffer<table> = Ringbuffer.new(64)
|
||||||
event_queue:push({n = 0})
|
event_queue:push({n = 0})
|
||||||
|
|
||||||
local shell_running = true
|
local shell_running = true
|
||||||
@ -185,9 +122,7 @@ while shell_running do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if socket.state == "ok" then
|
socket:close()
|
||||||
socket.ws.close()
|
|
||||||
end
|
|
||||||
|
|
||||||
term.native = orig_native
|
term.native = orig_native
|
||||||
term.redirect(term.native())
|
term.redirect(term.native())
|
||||||
|
@ -37,5 +37,6 @@ local function new<T>(size: integer): Ringbuffer<T>
|
|||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
new = new
|
new = new,
|
||||||
|
Ringbuffer = Ringbuffer
|
||||||
}
|
}
|
85
lua/socket.tl
Normal file
85
lua/socket.tl
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
local enum State
|
||||||
|
"reset"
|
||||||
|
"error"
|
||||||
|
"ok"
|
||||||
|
"viewer_connected"
|
||||||
|
end
|
||||||
|
|
||||||
|
local BAD_STATES <const> : {State: boolean} = {
|
||||||
|
["reset"] = true,
|
||||||
|
["error"] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local type StateCallback = function(new_state: State)
|
||||||
|
|
||||||
|
local record Socket
|
||||||
|
state: State
|
||||||
|
is_bad_state: function(self: Socket): boolean
|
||||||
|
_set_state: function(self: Socket, state: State)
|
||||||
|
on_state_change: function(self: Socket, cb: StateCallback)
|
||||||
|
send: function(self: Socket, message: string)
|
||||||
|
reconnect: function(self: Socket)
|
||||||
|
close: function(self: Socket)
|
||||||
|
_endpoint: string
|
||||||
|
_callback: StateCallback
|
||||||
|
_ws: http.Websocket
|
||||||
|
end
|
||||||
|
|
||||||
|
local impl: table = {}
|
||||||
|
|
||||||
|
impl.is_bad_state = function(self: Socket): boolean
|
||||||
|
return BAD_STATES[self.state] ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
impl._set_state = function(self: Socket, state: State)
|
||||||
|
self.state = state
|
||||||
|
self._callback(state)
|
||||||
|
end
|
||||||
|
|
||||||
|
impl.on_state_change = function(self: Socket, cb: StateCallback)
|
||||||
|
self._callback = cb
|
||||||
|
end
|
||||||
|
|
||||||
|
impl.send = function(self: Socket, message: string)
|
||||||
|
-- "message" needs to be valid JSON
|
||||||
|
-- otherwise the server will not accept it
|
||||||
|
|
||||||
|
if self:is_bad_state() then return end
|
||||||
|
|
||||||
|
local r = { pcall(self._ws.send, message) }
|
||||||
|
|
||||||
|
if r[1] == false then
|
||||||
|
if (r[2] as string):sub(-11) == "closed file" then
|
||||||
|
self:_set_state("reset")
|
||||||
|
elseif (r[2] as string):sub(-9) == "too large" then
|
||||||
|
-- TODO handle
|
||||||
|
-- the connection stays open though
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
impl.reconnect = function(self: Socket)
|
||||||
|
local r = http.websocket(self._endpoint)
|
||||||
|
if r ~= false then
|
||||||
|
self._ws = r as http.Websocket
|
||||||
|
self:_set_state("ok")
|
||||||
|
else
|
||||||
|
self:_set_state("error")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
impl.close = function(self: Socket)
|
||||||
|
if self:is_bad_state() then return end
|
||||||
|
self._ws.close()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function new(endpoint: string): Socket
|
||||||
|
return setmetatable({
|
||||||
|
state = "reset",
|
||||||
|
_endpoint = endpoint,
|
||||||
|
_callback = function(_: State) end,
|
||||||
|
_ws = nil,
|
||||||
|
}, { __index = impl })
|
||||||
|
end
|
||||||
|
|
||||||
|
return { new = new, State = State, StateCallback = StateCallback, Socket = Socket }
|
@ -1,5 +1,5 @@
|
|||||||
local path = "{{ deploy_path }}"
|
local path = "{{ deploy_path }}"
|
||||||
files = { "main.lua", "json.lua", "framebuffer.lua", "ringbuffer.lua" }
|
files = { "main.lua", "json.lua", "framebuffer.lua", "ringbuffer.lua", "socket.lua" }
|
||||||
for _, file in ipairs(files) do
|
for _, file in ipairs(files) do
|
||||||
fs.delete(file)
|
fs.delete(file)
|
||||||
shell.run(("wget %s/lua/%s"):format(path, file))
|
shell.run(("wget %s/lua/%s"):format(path, file))
|
||||||
|
Loading…
Reference in New Issue
Block a user