Skip to content

Instantly share code, notes, and snippets.

@Kyonru
Last active October 18, 2025 17:45
Show Gist options
  • Select an option

  • Save Kyonru/f3ba3f4961a119ddad2d2f08f6a322fc to your computer and use it in GitHub Desktop.

Select an option

Save Kyonru/f3ba3f4961a119ddad2d2f08f6a322fc to your computer and use it in GitHub Desktop.
Server utils for love2d presentation https://github.com/Kyonru/love2d-barcamp
---@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