util-evo-imp-server.lua /size: 4148 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['util-imp-evohome-server'] = {
2    version   = 1.002,
3    comment   = "simple server for simple evohome extensions",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE",
6    license   = "see context related readme files"
7}
8
9local P, C, patterns, lpegmatch = lpeg.P, lpeg.C, lpeg.patterns, lpeg.match
10local urlhashed, urlquery, urlunescapeget  = url.hashed, url.query, url.unescapeget
11local ioflush = io.flush
12
13local newline    = patterns.newline
14local spacer     = patterns.spacer
15local whitespace = patterns.whitespace
16local method     = P("GET")
17                 + P("POST")
18local identify   = (1-method)^0
19                 * C(method)
20                 * spacer^1
21                 * C((1-spacer)^1)
22                 * spacer^1
23                 * P("HTTP/")
24                 * (1-whitespace)^0
25                 * C(P(1)^0)
26
27do
28
29    local loaded = package.loaded
30
31    if not loaded.socket then loaded.socket = loaded["socket.core"] end
32    if not loaded.mime   then loaded.mime   = loaded["mime.core"]   end
33
34end
35
36local evohome  = require("util-evo")
37                 require("trac-lmx")
38
39local report   = logs.reporter("evohome","server")
40local convert  = lmx.convert
41
42function evohome.server(specification)
43
44    local filename = specification.filename
45
46    if not filename then
47        report("unable to run server, no filename given")
48        return
49    end
50
51    local step, process, presets = evohome.actions.poller(filename)
52
53    if not (step and process and presets) then
54        report("unable to run server, invalid presets")
55        return
56    end
57
58    local template = presets.files.template
59
60    if not template then
61        report("unable to run server, no template given")
62        return
63    end
64
65    local port = specification.port or (presets.server and presets.server.port) or 8068
66    local host = specification.host or (presets.server and presets.server.host) or "*"
67
68    if presets.initial == "alloff" then
69        report("turning all zones off")
70        evohome.actions.alloff(presets)
71    else
72        report("using default initial state")
73    end
74
75    package.extraluapath(presets.filepath)
76
77    local socket = socket or require("socket")
78    local copas  = copas  or require("copas")
79
80    local function copashttp(skt)
81        local client = copas.wrap(skt)
82        local request, e = client:receive()
83        if not e then
84            local method, fullurl, body = lpegmatch(identify,request)
85            if method ~= "" and fullurl ~= "" then
86                local fullurl = urlunescapeget(fullurl)
87                local hashed  = urlhashed(fullurl)
88                process(hashed.queries or { })
89                ioflush()
90            end
91            -- todo: split off css and use that instead of general one, now too much
92            local content = convert(presets.results and presets.results.template or template,false,presets)
93            if not content then
94                report("error in converting template")
95                content = "error in template"
96            end
97            client:send("HTTP/1.1 200 OK\r\n")
98            client:send("Connection: close\r\n")
99            client:send("Content-Length: " .. #content .. "\r\n")
100            client:send("Content-Type: text/html\r\n")
101            client:send("Location: " .. host .. "\r\n")
102            client:send("Cache-Control: no-cache, no-store, must-revalidate, max-age=0\r\n")
103            client:send("\r\n")
104            client:send(content)
105            client:send("\r\n")
106            client:close()
107        end
108    end
109
110    local function copaspoll()
111        while step do
112            local delay = step()
113            if type(delay) == "number" then
114                copas.sleep(delay or 0)
115            end
116        end
117    end
118
119    local server = socket.bind(host,port)
120
121    if server then
122        report("server started at %s:%s",host,port)
123        ioflush()
124        copas.addserver(server,copashttp)
125        copas.addthread(copaspoll)
126        copas.loop()
127    else
128        report("unable to start server at %s:%s",host,port)
129        os.exit()
130    end
131
132end
133
134return evohome
135