diff --git a/lua/.gitignore b/lua/.gitignore new file mode 100644 index 0000000..c585e19 --- /dev/null +++ b/lua/.gitignore @@ -0,0 +1 @@ +out \ No newline at end of file diff --git a/lua/justfile b/lua/justfile new file mode 100644 index 0000000..3056042 --- /dev/null +++ b/lua/justfile @@ -0,0 +1,19 @@ +default: + @just --list + +teal_files := "main.tl framebuffer.tl ringbuffer.tl" + +build: + mkdir -p out + cp json.lua out + for file in {{teal_files}}; do \ + tl gen $file; \ + mv ${file%.tl}.lua out; \ + done + +alias b := build + +clean: + rm -r out + +alias c := clean \ No newline at end of file diff --git a/lua/main.tl b/lua/main.tl index ccbe073..5fa7641 100644 --- a/lua/main.tl +++ b/lua/main.tl @@ -8,17 +8,40 @@ print("[MAIN] Init") local enum SocketState "reset" - "connecting" -- currently unused + "error" "ok" + "viewer_connected" end +local BAD_STATES : {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, } @@ -26,13 +49,13 @@ local function send(message: string) -- "message" needs to be valid JSON -- otherwise the server will not accept it - if socket.state ~= "ok" then return end + 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.state = "reset" + socket:set_state("reset") elseif (r[2] as string):sub(-9) == "too large" then -- TODO handle -- the connection stays open though @@ -66,22 +89,32 @@ end -- Create tasks +local bar_codes: { SocketState: {string} } = { + ["reset"] = {"[WS] RST", "78870111"}, + ["error"] = {"[WS] ERR", "78870EEE"}, + ["ok"] = {"[WS] OK\x03", "78870DD5"}, + ["viewer_connected"] = {"[WS] CON", "78870999"}, +} + +socket:on_state_change(function(new_state: SocketState) + set_bar(table.unpack(bar_codes[new_state])) +end) + local ws_task = coroutine.create(function() while true do - if socket.state == "reset" then - set_bar("[WS] RST", "78870111") + if socket:bad_state() then + --set_bar("[WS] RST", "78870111") local r = http.websocket(ENDPOINT) if r ~= false then socket.ws = r as http.Websocket - set_bar("[WS] OK\x03", "78870DD5") - socket.state = "ok" + --set_bar("[WS] OK\x03", "78870DD5") + socket:set_state("ok") else - set_bar("[WS] ERR", "78870EEE") + socket:set_state("error") + --set_bar("[WS] ERR", "78870EEE") end end - repeat - sleep(1) - until socket.state ~= "ok" + sleep(1) end end) @@ -89,7 +122,8 @@ local report_task = coroutine.create(function() local last_report = -1.0 while true do local now = os.clock() - if now - last_report >= 0.05 then + local interval = (socket.state == "viewer_connected") and 0.05 or 1 + if now - last_report >= interval then local message = json.encode({ screen = buffer.serialize() }) @@ -151,6 +185,9 @@ while shell_running do end end +if socket.state == "ok" then + socket.ws.close() +end term.native = orig_native term.redirect(term.native()) diff --git a/server/lua b/server/lua new file mode 120000 index 0000000..df6ec1a --- /dev/null +++ b/server/lua @@ -0,0 +1 @@ +../lua/out \ No newline at end of file diff --git a/server/server/__init__.py b/server/server/__init__.py index 7ae8c91..e044d6c 100644 --- a/server/server/__init__.py +++ b/server/server/__init__.py @@ -1,7 +1,8 @@ import asyncio import json from fastapi import FastAPI, Request -from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles +from fastapi.responses import HTMLResponse, PlainTextResponse from .settings import settings from .user import user_auth @@ -16,6 +17,16 @@ app.mount("/map/", map_meta) app.mount("/tiles/", map_tiles) app.mount("/ipmi/", monitoring) +installer = j2env.get_template("install.lua").render(deploy_path=settings.deploy_path) + + +@app.get("/install") +async def get_installer(): + return PlainTextResponse(installer) + + +app.mount("/lua/", StaticFiles(directory=settings.lua_out_path)) + @app.on_event("startup") async def on_startup(): @@ -26,8 +37,6 @@ frontend = FastAPI() manifest = dict() if not settings.dev_mode: - from fastapi.staticfiles import StaticFiles - with open(f"{settings.frontend_path}/manifest.json", "r") as f: manifest = json.load(f) diff --git a/server/server/settings.py b/server/server/settings.py index 6191c93..6efdc02 100644 --- a/server/server/settings.py +++ b/server/server/settings.py @@ -7,6 +7,9 @@ class Settings(BaseSettings): frontend_path: str = "frontend" unmined_out_path: str = "unmined-out" + lua_out_path: str = "lua" + + deploy_path: str = "http://localhost:8000" settings = Settings() diff --git a/server/templates/install.lua b/server/templates/install.lua new file mode 100644 index 0000000..6905f89 --- /dev/null +++ b/server/templates/install.lua @@ -0,0 +1,6 @@ +local path = "{{ deploy_path }}" +files = { "main.lua", "json.lua", "framebuffer.lua", "ringbuffer.lua" } +for _, file in ipairs(files) do + fs.delete(file) + shell.run(("wget %s/lua/%s"):format(path, file)) +end \ No newline at end of file