diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2019-10-07 16:56:03 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2019-10-07 17:07:42 +0000 |
| commit | 81e143fa8181a6adb58d7fba632bd31a13164410 (patch) | |
| tree | 982875e849a593f9d5da28a445fd56b1eacb951a | |
| parent | little meta-link updates (diff) | |
| download | mmm-81e143fa8181a6adb58d7fba632bd31a13164410.tar.gz mmm-81e143fa8181a6adb58d7fba632bd31a13164410.zip | |
add simple HTTP server
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | build/import.moon | 1 | ||||
| -rw-r--r-- | build/render_all.moon | 36 | ||||
| -rw-r--r-- | build/server.moon | 119 | ||||
| -rw-r--r-- | build/util.moon | 37 | ||||
| -rw-r--r-- | mmm/mmmfs/fileder.moon | 9 |
6 files changed, 166 insertions, 37 deletions
@@ -46,6 +46,7 @@ You will need: - [MoonScript][moonscript]: `luarocks install moonscript` - [lua-sqlite3](https://luarocks.org/modules/moteus/sqlite3): `luarocks install sqlite3` +- [lua-http](https://github.com/daurnimator/lua-http): `luarocks install http` - [discount](https://luarocks.org/modules/craigb/discount): `luarocks install discount` (requires libmarkdown2) - [busted](https://olivinelabs.com/busted/): `luarocks install busted` (for testing only) diff --git a/build/import.moon b/build/import.moon index 624b54a..b5def43 100644 --- a/build/import.moon +++ b/build/import.moon @@ -30,7 +30,6 @@ load_facet = (filename, filepath) -> key, value - with SQLStore name: output, verbose: true import_fileder = (fileder, dirpath) -> for file in lfs.dir dirpath diff --git a/build/render_all.moon b/build/render_all.moon index dfbed27..14e4cce 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -73,42 +73,6 @@ render = (fileder, output) -> " \close! -import SQLStore from require 'mmm.mmmfs.drivers.sql' -import Fileder, Key from require 'mmm.mmmfs.fileder' - --- split filename into dirname + basename -dir_base = (path) -> - dir, base = path\match '(.-)([^/]-)$' - if dir and #dir > 0 - dir = dir\sub 1, #dir - 1 - - dir, base - -load_tree = (store, root='') -> - fileders = setmetatable {}, - __index: (path) => - with val = Fileder {} - .path = path - rawset @, path, val - - root = fileders[root] - root.facets['name: alpha'] = '' - for fn, ft in store\list_facets root.path - val = store\load_facet root.path, fn, ft - root.facets[Key fn, ft] = val - - for path in store\list_all_fileders root.path - fileder = fileders[path] - - parent, name = dir_base path - fileder.facets['name: alpha'] = name - table.insert fileders[parent].children, fileder - - for fn, ft in store\list_facets path - val = store\load_facet path, fn, ft - fileder.facets[Key fn, ft] = val - - root tree = load_tree SQLStore :name diff --git a/build/server.moon b/build/server.moon new file mode 100644 index 0000000..dd491d3 --- /dev/null +++ b/build/server.moon @@ -0,0 +1,119 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +import dir_base, load_tree from require 'build.util' +import Key from require 'mmm.mmmfs.fileder' +import SQLStore from require 'mmm.mmmfs.drivers.sql' + +server = require 'http.server' +headers = require 'http.headers' + +tojson = (obj) -> + switch type obj + when 'string' + string.format '%q', obj + when 'table' + if obj[1] or not next obj + "[#{table.concat [tojson c for c in *obj], ','}]" + else + "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}" + when 'number' + tostring obj + when 'boolean' + tostring obj + when nil + 'null' + +class Server + new: (@tree, opts={}) => + opts = {k,v for k,v in pairs opts} + opts.host = 'localhost' unless opts.host + opts.port = 8000 unless opts.port + opts.onstream = @\stream + opts.onerror = @\error + + @server = server.listen opts + + listen: => + assert @server\listen! + + _, ip, port = @server\localname! + print "SV", "running at #{ip}:#{port}" + assert @server\loop! + + handle: (method, path, facet) => + fileder = @tree\walk path + switch method + when 'GET', 'HEAD' + if fileder and facet + -- fileder and facet given + if not fileder\has_facet facet.name + return 404, "facet '#{facet.name}' not found in fileder '#{path}'" + + val = fileder\get facet + if val + 200, val + else + 406, 'cant convert facet' + elseif fileder + -- no facet given + facets = [{k.name, k.type} for k,v in pairs fileder.facets] + children = [f.path for f in *fileder.children] + print facets + print children + contents = tojson :facets, :children + 200, contents + else + -- fileder not found + 404, "fileder '#{path}' not found" + else + 501, 'not implemented' + + stream: (sv, stream) => + req = stream\get_headers! + method = req\get ':method' + path = req\get ':path' + + path, facet = dir_base path + print "'#{path}', '#{facet}'" + facet = if #facet > 0 + facet = '' if facet == ':' + accept = req\get 'mmm-accept' + Key facet, accept or 'text/html' + else + nil + + status, body = @handle method, path, facet + + res = headers.new! + response_type = if status > 299 then 'text/plain' + else if facet then facet.type + else 'text/plain' + res\append ':status', tostring status + res\append 'content-type', response_type + + if method == 'HEAD' + stream\write_headers res, true + else + stream\write_headers res, false + stream\write_chunk body, true + + error: (sv, ctx, op, err, errno) => + msg = "#{op} on #{tostring ctx} failed" + msg = "#{msg}: #{err}" if err + print msg + +-- usage: +-- moon server.moon [db.sqlite3] +{ file } = arg + +tree = load_tree SQLStore :file +server = Server tree +server\listen! diff --git a/build/util.moon b/build/util.moon index b9c9613..92450c7 100644 --- a/build/util.moon +++ b/build/util.moon @@ -1,4 +1,5 @@ require 'lfs' +import Fileder, Key from require 'mmm.mmmfs.fileder' get_path = (root) -> cwd = lfs.currentdir! @@ -11,6 +12,42 @@ get_path = (root) -> path +-- split filename into dirname + basename +dir_base = (path) -> + dir, base = path\match '(.-)([^/]-)$' + if dir and #dir > 0 + dir = dir\sub 1, #dir - 1 + + dir, base + +load_tree = (store, root='') -> + fileders = setmetatable {}, + __index: (path) => + with val = Fileder {} + .path = path + rawset @, path, val + + root = fileders[root] + root.facets['name: alpha'] = '' + for fn, ft in store\list_facets root.path + val = store\load_facet root.path, fn, ft + root.facets[Key fn, ft] = val + + for path in store\list_all_fileders root.path + fileder = fileders[path] + + parent, name = dir_base path + fileder.facets['name: alpha'] = name + table.insert fileders[parent].children, fileder + + for fn, ft in store\list_facets path + val = store\load_facet path, fn, ft + fileder.facets[Key fn, ft] = val + + root + { :get_path + :dir_base + :load_tree } diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 0400141..87dad78 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -123,6 +123,7 @@ class Fileder [name for name in pairs names] -- check whether a facet is directly available + -- when passing a Key, set type to false to check for name only has: (...) => want = Key ... @@ -132,6 +133,14 @@ class Fileder if key.name == want.name and key.type == want.type return key + -- check whether any facet with that name exists + has_facet: (want) => + for key in pairs @facets + continue if key.original + + if key.name == want + return key + -- find facet and type according to criteria, nil if no value or conversion path -- * ... - arguments like Key find: (...) => |
