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
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 |