aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2019-10-07 16:56:03 +0000
committers-ol <s-ol@users.noreply.github.com>2019-10-07 17:07:42 +0000
commit81e143fa8181a6adb58d7fba632bd31a13164410 (patch)
tree982875e849a593f9d5da28a445fd56b1eacb951a
parentlittle meta-link updates (diff)
downloadmmm-81e143fa8181a6adb58d7fba632bd31a13164410.tar.gz
mmm-81e143fa8181a6adb58d7fba632bd31a13164410.zip
add simple HTTP server
-rw-r--r--README.md1
-rw-r--r--build/import.moon1
-rw-r--r--build/render_all.moon36
-rw-r--r--build/server.moon119
-rw-r--r--build/util.moon37
-rw-r--r--mmm/mmmfs/fileder.moon9
6 files changed, 166 insertions, 37 deletions
diff --git a/README.md b/README.md
index f687309..94a7f66 100644
--- a/README.md
+++ b/README.md
@@ -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: (...) =>