git.s-ol.nu mmm / 81e143f
add simple HTTP server s-ol 3 years ago
6 changed file(s) with 166 addition(s) and 37 deletion(s). Raw diff Collapse all Expand all
4545
4646 - [MoonScript][moonscript]: `luarocks install moonscript`
4747 - [lua-sqlite3](https://luarocks.org/modules/moteus/sqlite3): `luarocks install sqlite3`
48 - [lua-http](https://github.com/daurnimator/lua-http): `luarocks install http`
4849 - [discount](https://luarocks.org/modules/craigb/discount): `luarocks install discount` (requires libmarkdown2)
4950 - [busted](https://olivinelabs.com/busted/): `luarocks install busted` (for testing only)
5051
2929
3030 key, value
3131
32
3332 with SQLStore name: output, verbose: true
3433 import_fileder = (fileder, dirpath) ->
3534 for file in lfs.dir dirpath
7272 "
7373 \close!
7474
75 import SQLStore from require 'mmm.mmmfs.drivers.sql'
76 import Fileder, Key from require 'mmm.mmmfs.fileder'
77
78 -- split filename into dirname + basename
79 dir_base = (path) ->
80 dir, base = path\match '(.-)([^/]-)$'
81 if dir and #dir > 0
82 dir = dir\sub 1, #dir - 1
83
84 dir, base
85
86 load_tree = (store, root='') ->
87 fileders = setmetatable {},
88 __index: (path) =>
89 with val = Fileder {}
90 .path = path
91 rawset @, path, val
92
93 root = fileders[root]
94 root.facets['name: alpha'] = ''
95 for fn, ft in store\list_facets root.path
96 val = store\load_facet root.path, fn, ft
97 root.facets[Key fn, ft] = val
98
99 for path in store\list_all_fileders root.path
100 fileder = fileders[path]
101
102 parent, name = dir_base path
103 fileder.facets['name: alpha'] = name
104 table.insert fileders[parent].children, fileder
105
106 for fn, ft in store\list_facets path
107 val = store\load_facet path, fn, ft
108 fileder.facets[Key fn, ft] = val
109
110 root
11175
11276 tree = load_tree SQLStore :name
11377
0 add = (tmpl) ->
1 package.path ..= ";#{tmpl}.lua"
2 package.moonpath ..= ";#{tmpl}.moon"
3
4 add '?'
5 add '?.server'
6 add '?/init'
7 add '?/init.server'
8
9 require 'mmm'
10 import dir_base, load_tree from require 'build.util'
11 import Key from require 'mmm.mmmfs.fileder'
12 import SQLStore from require 'mmm.mmmfs.drivers.sql'
13
14 server = require 'http.server'
15 headers = require 'http.headers'
16
17 tojson = (obj) ->
18 switch type obj
19 when 'string'
20 string.format '%q', obj
21 when 'table'
22 if obj[1] or not next obj
23 "[#{table.concat [tojson c for c in *obj], ','}]"
24 else
25 "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}"
26 when 'number'
27 tostring obj
28 when 'boolean'
29 tostring obj
30 when nil
31 'null'
32
33 class Server
34 new: (@tree, opts={}) =>
35 opts = {k,v for k,v in pairs opts}
36 opts.host = 'localhost' unless opts.host
37 opts.port = 8000 unless opts.port
38 opts.onstream = @\stream
39 opts.onerror = @\error
40
41 @server = server.listen opts
42
43 listen: =>
44 assert @server\listen!
45
46 _, ip, port = @server\localname!
47 print "SV", "running at #{ip}:#{port}"
48 assert @server\loop!
49
50 handle: (method, path, facet) =>
51 fileder = @tree\walk path
52 switch method
53 when 'GET', 'HEAD'
54 if fileder and facet
55 -- fileder and facet given
56 if not fileder\has_facet facet.name
57 return 404, "facet '#{facet.name}' not found in fileder '#{path}'"
58
59 val = fileder\get facet
60 if val
61 200, val
62 else
63 406, 'cant convert facet'
64 elseif fileder
65 -- no facet given
66 facets = [{k.name, k.type} for k,v in pairs fileder.facets]
67 children = [f.path for f in *fileder.children]
68 print facets
69 print children
70 contents = tojson :facets, :children
71 200, contents
72 else
73 -- fileder not found
74 404, "fileder '#{path}' not found"
75 else
76 501, 'not implemented'
77
78 stream: (sv, stream) =>
79 req = stream\get_headers!
80 method = req\get ':method'
81 path = req\get ':path'
82
83 path, facet = dir_base path
84 print "'#{path}', '#{facet}'"
85 facet = if #facet > 0
86 facet = '' if facet == ':'
87 accept = req\get 'mmm-accept'
88 Key facet, accept or 'text/html'
89 else
90 nil
91
92 status, body = @handle method, path, facet
93
94 res = headers.new!
95 response_type = if status > 299 then 'text/plain'
96 else if facet then facet.type
97 else 'text/plain'
98 res\append ':status', tostring status
99 res\append 'content-type', response_type
100
101 if method == 'HEAD'
102 stream\write_headers res, true
103 else
104 stream\write_headers res, false
105 stream\write_chunk body, true
106
107 error: (sv, ctx, op, err, errno) =>
108 msg = "#{op} on #{tostring ctx} failed"
109 msg = "#{msg}: #{err}" if err
110 print msg
111
112 -- usage:
113 -- moon server.moon [db.sqlite3]
114 { file } = arg
115
116 tree = load_tree SQLStore :file
117 server = Server tree
118 server\listen!
00 require 'lfs'
1 import Fileder, Key from require 'mmm.mmmfs.fileder'
12
23 get_path = (root) ->
34 cwd = lfs.currentdir!
1011
1112 path
1213
14 -- split filename into dirname + basename
15 dir_base = (path) ->
16 dir, base = path\match '(.-)([^/]-)$'
17 if dir and #dir > 0
18 dir = dir\sub 1, #dir - 1
19
20 dir, base
21
22 load_tree = (store, root='') ->
23 fileders = setmetatable {},
24 __index: (path) =>
25 with val = Fileder {}
26 .path = path
27 rawset @, path, val
28
29 root = fileders[root]
30 root.facets['name: alpha'] = ''
31 for fn, ft in store\list_facets root.path
32 val = store\load_facet root.path, fn, ft
33 root.facets[Key fn, ft] = val
34
35 for path in store\list_all_fileders root.path
36 fileder = fileders[path]
37
38 parent, name = dir_base path
39 fileder.facets['name: alpha'] = name
40 table.insert fileders[parent].children, fileder
41
42 for fn, ft in store\list_facets path
43 val = store\load_facet path, fn, ft
44 fileder.facets[Key fn, ft] = val
45
46 root
47
1348 {
1449 :get_path
50 :dir_base
51 :load_tree
1552 }
122122 [name for name in pairs names]
123123
124124 -- check whether a facet is directly available
125 -- when passing a Key, set type to false to check for name only
125126 has: (...) =>
126127 want = Key ...
127128
129130 continue if key.original
130131
131132 if key.name == want.name and key.type == want.type
133 return key
134
135 -- check whether any facet with that name exists
136 has_facet: (want) =>
137 for key in pairs @facets
138 continue if key.original
139
140 if key.name == want
132141 return key
133142
134143 -- find facet and type according to criteria, nil if no value or conversion path