Last active
October 18, 2025 17:45
-
-
Save Kyonru/f3ba3f4961a119ddad2d2f08f6a322fc to your computer and use it in GitHub Desktop.
Server utils for love2d presentation https://github.com/Kyonru/love2d-barcamp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ---@diagnostic disable: invisible | |
| --- From https://github.com/rxi/json.lua | |
| local json = require("json") | |
| local server = {} | |
| function server.allowedHeaders() | |
| local response = [[ | |
| HTTP/1.1 204 No Content | |
| Access-Control-Allow-Origin: * | |
| Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT | |
| Access-Control-Allow-Headers: x-api-key | |
| Access-Control-Max-Age: 86400 | |
| Content-Length: 0 | |
| ]] | |
| return response | |
| end | |
| ---@param body string | |
| function server.buildResponse(body) | |
| local response = table.concat({ | |
| "HTTP/1.1 200 OK", | |
| "Content-Type: application/json", | |
| "Access-Control-Allow-Origin: *", | |
| "Access-Control-Allow-Headers: Content-Type, x-api-key, X-Requested-With, Access-Control-Request-Headers", | |
| "Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS", | |
| "Content-Length: " .. #body, | |
| "", | |
| body, | |
| }, "\r\n") | |
| return response | |
| end | |
| --- @class FeatherRequest | |
| --- @field method string | |
| --- @field path string | |
| --- @field params table | |
| --- @field headers table | |
| --- Builds a request object from a raw request string | |
| --- @param client table | |
| --- @return FeatherRequest | |
| function server.buildRequest(client) | |
| local request = client:receive() | |
| local method, pathWithQuery = request:match("^(%u+)%s+([^%s]+)") | |
| local path, queryString = pathWithQuery:match("^([^?]+)%??(.*)$") | |
| local function parseQuery(qs) | |
| local params = {} | |
| for key, val in qs:gmatch("([^&=?]+)=([^&=?]+)") do | |
| params[key] = val | |
| end | |
| return params | |
| end | |
| local params = parseQuery(queryString) | |
| local line = client:receive() | |
| local raw_headers = line | |
| while line ~= "" do | |
| raw_headers = raw_headers .. "\n" .. line | |
| line = client:receive() | |
| end | |
| local headers = {} | |
| for header in raw_headers:gmatch("[^\r\n]+") do | |
| local key, value = header:match("^([^:]+):%s*(.*)$") | |
| if key and value then | |
| headers[key] = value | |
| end | |
| end | |
| return { | |
| method = method, | |
| path = path, | |
| params = params, | |
| headers = headers, | |
| } | |
| end | |
| --- check if the given address is in the whitelist | |
| ---@param addr string | |
| ---@param whitelist table | |
| function server.isInWhitelist(addr, whitelist) | |
| for _, a in pairs(whitelist) do | |
| local ptn = "^" .. a:gsub("%.", "%%."):gsub("%*", "%%d*") .. "$" | |
| if addr:match(ptn) then | |
| return true | |
| end | |
| end | |
| return false | |
| end | |
| function server.createResponse(body) | |
| return server.buildResponse(json.encode(body)) | |
| end | |
| --- Handle get request | |
| local function handleGetRequest(request, dt) | |
| local data = {} | |
| if request.path == "/checkout" and request.params.commit then | |
| local commit = request.params.commit | |
| --- @type boolean | nil | |
| local success = false | |
| if commit:match("^[0-9a-fA-F]+$") then | |
| success = os.execute(string.format("cd ./creating-games-with-love-demo && git checkout %s", commit)) | |
| end | |
| if success then | |
| love.event.quit("restart") | |
| end | |
| end | |
| return data | |
| end | |
| -- Handle a request from a client | |
| ---@param client table | |
| function server.handleRequest(client, whitelist, dt) | |
| if client then | |
| client:settimeout(1) | |
| local request = server.buildRequest(client) | |
| local addr = client:getsockname() | |
| if not server.isInWhitelist(addr, whitelist) then | |
| print("non-whitelisted connection attempt: ", addr) | |
| client:close() | |
| end | |
| if request then | |
| local response = {} | |
| if request.method == "OPTIONS" then | |
| local optionsResponse = server.allowedHeaders() | |
| client:send(optionsResponse) | |
| client:close() | |
| return | |
| end | |
| if request.method == "GET" then | |
| response.data = handleGetRequest(request, dt) | |
| end | |
| client:send(server.createResponse(response.data or {})) | |
| end | |
| client:close() | |
| end | |
| end | |
| return server |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment