util-evo-imp-server.lua / last modification: 2020-01-30 14:16
if not modules then modules = { } end modules ['util-imp-evohome-server'] = {
    version   = 1.002,
    comment   = "simple server for simple evohome extensions",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE",
    license   = "see context related readme files"
}

local P, C, patterns, lpegmatch = lpeg.P, lpeg.C, lpeg.patterns, lpeg.match
local urlhashed, urlquery, urlunescapeget  = url.hashed, url.query, url.unescapeget
local ioflush = io.flush

local newline    = patterns.newline
local spacer     = patterns.spacer
local whitespace = patterns.whitespace
local method     = P("GET")
                 + P("POST")
local identify   = (1-method)^0
                 * C(method)
                 * spacer^1
                 * C((1-spacer)^1)
                 * spacer^1
                 * P("HTTP/")
                 * (1-whitespace)^0
                 * C(P(1)^0)

do

    local loaded = package.loaded

    if not loaded.socket then loaded.socket = loaded["socket.core"] end
    if not loaded.mime   then loaded.mime   = loaded["mime.core"]   end

end

local evohome  = require("util-evo")
                 require("trac-lmx")

local report   = logs.reporter("evohome","server")
local convert  = lmx.convert

function evohome.server(specification)

    local filename = specification.filename

    if not filename then
        report("unable to run server, no filename given")
        return
    end

    local step, process, presets = evohome.actions.poller(filename)

    if not (step and process and presets) then
        report("unable to run server, invalid presets")
        return
    end

    local template = presets.files.template

    if not template then
        report("unable to run server, no template given")
        return
    end

    local port = specification.port or (presets.server and presets.server.port) or 8068
    local host = specification.host or (presets.server and presets.server.host) or "*"

    package.extraluapath(presets.filepath)

    local socket = socket or require("socket")
    local copas  = copas  or require("copas")

    local function copashttp(skt)
        local client = copas.wrap(skt)
        local request, e = client:receive()
        if not e then
            local method, fullurl, body = lpegmatch(identify,request)
            if method ~= "" and fullurl ~= "" then
                local fullurl = urlunescapeget(fullurl)
                local hashed  = urlhashed(fullurl)
                process(hashed.queries or { })
                ioflush()
            end
            -- todo: split off css and use that instead of general one, now too much
            local content = convert(presets.results and presets.results.template or template,false,presets)
            if not content then
                report("error in converting template")
                content = "error in template"
            end
            client:send("HTTP/1.1 200 OK\r\n")
            client:send("Connection: close\r\n")
            client:send("Content-Length: " .. #content .. "\r\n")
            client:send("Content-Type: text/html\r\n")
            client:send("Location: " .. host .. "\r\n")
            client:send("Cache-Control: no-cache, no-store, must-revalidate, max-age=0\r\n")
            client:send("\r\n")
            client:send(content)
            client:send("\r\n")
            client:close()
        end
    end

    local function copaspoll()
        while step do
            local delay = step()
            if type(delay) == "number" then
                copas.sleep(delay or 0)
            end
        end
    end

    local server = socket.bind(host,port)

    if server then
        report("server started at %s:%s",host,port)
        ioflush()
        copas.addserver(server,copashttp)
        copas.addthread(copaspoll)
        copas.loop()
    else
        report("unable to start server at %s:%s",host,port)
        os.exit()
    end

end

return evohome