webmcp
view framework/bin/mcp.lua @ 215:ba3dd4a17e3d
Some code cleanup/rearrangement for request handling
| author | jbe | 
|---|---|
| date | Mon Jan 12 01:48:11 2015 +0100 (2015-01-12) | 
| parents | 6ac7133bb58e | 
| children | 7f9c9c4434a1 | 
 line source
     1 #!/usr/bin/env moonbridge
     3 WEBMCP_VERSION = "2.0.0_devel"
     5 -- check if interactive mode
     6 if listen then  -- defined by moonbridge
     7   WEBMCP_MODE = "listen"
     8 else
     9   WEBMCP_MODE = "interactive"
    10 end
    12 -- configuration names are provided as 4th, 5th, etc. argument
    13 WEBMCP_CONFIG_NAMES = {select(4, ...)}
    15 -- determine framework and bath path from command line arguments
    16 -- or print usage synopsis (if applicable)
    17 do
    18   local arg1, arg2, arg3 = ...
    19   local helpout
    20   if
    21     arg1 == "-h" or arg1 == "--help" or
    22     arg2 == "-h" or arg2 == "--help"  -- if first arg is provided by wrapper
    23   then
    24     helpout = io.stdout
    25   elseif
    26     #config_args < 1 or
    27     (WEBMCP_MODE == "interactive") ~= (arg3 == "INTERACTIVE")
    28   then
    29     helpout = io.stderr
    30   end
    31   helpout:write("Usage: moonbridge -- <framework path>/bin/mcp.lua <framework path> <app base path> <app name> <config name> [<config name> ...]\n")
    32   helpout:write("   or: lua -i <framework path>/bin/mcp.lua <framework path> <app base path> INTERACTIVE <config name> [<config name> ...]\n")
    33   if helpout then
    34     if helpout == io.stderr then
    35       return 1
    36     else
    37       return 0
    38     end
    39   end
    40   local function append_trailing_slash(str)
    41     return string.sub(str, "([^/])$", function(last) return last .. "/" end)
    42   end
    43   WEBMCP_FRAMEWORK_PATH = append_trailing_slash(arg1)
    44   WEBMCP_BASE_PATH      = append_trailing_slash(arg2)
    45   if WEBMCP_MODE == "listen" then
    46     WEBMCP_APP_NAME = arg3
    47   end
    48 end
    50 -- setup search paths for libraries
    51 do
    52   package.path = WEBMCP_FRAMEWORK_PATH .. "lib/?.lua;" .. package.path
    53   -- find out which file name extension shared libraries have
    54   local slib_exts = {}
    55   for ext in string.gmatch(package.cpath, "%?%.([A-Za-z0-9_-]+)") do
    56     slib_exts[ext] = true
    57   end
    58   local paths = {}
    59   for ext in pairs(slib_exts) do
    60     paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "accelerator/?." .. ext
    61   end
    62   for ext in pairs(slib_exts) do
    63     paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "lib/?." .. ext
    64   end
    65   paths[#paths+1] = package.cpath
    66   package.cpath = table.concat(paths, ";")
    67 end
    69 -- autoloader system for WebMCP environment "$WEBMCP_FRAMEWORK_PATH/env/",
    70 -- application environment extensions "$WEBMCP_BASE_PATH/env/"
    71 -- and models "$WEBMCP_BASE_PATH/model/"
    72 do
    73   local weakkey_mt = { __mode = "k" }
    74   local autoloader_category = setmetatable({}, weakkey_mt)
    75   local autoloader_path     = setmetatable({}, weakkey_mt)
    76   local autoloader_mt       = {}
    77   local function install_autoloader(self, category, path)
    78     autoloader_category[self] = category
    79     autoloader_path[self]     = path
    80     setmetatable(self, autoloader_mt)
    81   end
    82   local function try_exec(filename)
    83     local file = io.open(filename, "r")
    84     if file then
    85       local filedata = file:read("*a")
    86       io.close(file)
    87       local func, errmsg = load(filedata, "=" .. filename)
    88       if func then
    89         func()
    90         return true
    91       else
    92         error(errmsg, 0)
    93       end
    94     else
    95       return false
    96     end
    97   end
    98   local function compose_path_string(base, path, key)
    99     if #path == 0 then
   100       return base .. "/" .. key
   101     else
   102       return base .. table.concat(path, "/") .. "/" .. key
   103     end
   104   end
   105   function autoloader_mt.__index(self, key)
   106     local category, base_path, merge_base_path, file_key
   107     local merge = false
   108     if
   109       string.find(key, "^[a-z_][A-Za-z0-9_]*$") and
   110       not string.find(key, "^__")
   111     then
   112       category        = "env"
   113       base_path       = WEBMCP_FRAMEWORK_PATH .. "env/"
   114       merge           = true
   115       merge_base_path = WEBMCP_BASE_PATH .. "env/"
   116       file_key        = key
   117     elseif string.find(key, "^[A-Z][A-Za-z0-9]*$") then
   118       category        = "model"
   119       base_path       = WEBMCP_BASE_PATH .. "model/"
   120       local first = true
   121       file_key = string.gsub(key, "[A-Z]",
   122         function(c)
   123           if first then
   124             first = false
   125             return string.lower(c)
   126           else
   127             return "_" .. string.lower(c)
   128           end
   129         end
   130       )
   131     else
   132       return
   133     end
   134     local required_category = autoloader_category[self]
   135     if required_category and required_category ~= category then return end
   136     local path = autoloader_path[self]
   137     local path_string = compose_path_string(base_path, path, file_key)
   138     local merge_path_string
   139     if merge then
   140       merge_path_string = compose_path_string(
   141         merge_base_path, path, file_key
   142       )
   143     end
   144     local function try_dir(dirname)
   145       local dir = io.open(dirname)
   146       if dir then
   147         io.close(dir)
   148         local obj = {}
   149         local sub_path = {}
   150         for i = 1, #path do sub_path[i] = path[i] end
   151         sub_path[#path+1] = file_key
   152         install_autoloader(obj, category, sub_path)
   153         rawset(self, key, obj)
   154         try_exec(path_string .. "/__init.lua")
   155         if merge then try_exec(merge_path_string .. "/__init.lua") end
   156         return true
   157       else
   158         return false
   159       end
   160     end
   161     if merge and try_exec(merge_path_string .. ".lua") then
   162     elseif merge and try_dir(merge_path_string .. "/") then
   163     elseif try_exec(path_string .. ".lua") then
   164     elseif try_dir(path_string .. "/") then
   165     else end
   166     return rawget(self, key)
   167   end
   168   install_autoloader(_G, nil, {})
   169   try_exec(WEBMCP_FRAMEWORK_PATH .. "env/__init.lua")
   170   try_exec(WEBMCP_BASE_PATH .. "env/__init.lua")
   171 end
   173 -- replace Moonbridge listen function
   174 local moonbridge_listen = listen
   175 local listeners
   176 function listen(args)
   177   listeners[#listeners+1] = args
   178 end
   180 -- prohibit (unintended) definition of new global variables
   181 _ENV = setmetatable({}, {
   182   __index = _G,
   183   __newindex = function()
   184     error("Setting of global variable prohibited")
   185   end
   186 })
   188 -- execute configurations
   189 for i, config_name in ipairs(WEBMCP_CONFIG_NAMES) do
   190   execute.config(config_name)
   191   execute.prefork_initializers()
   192 end
   194 -- interactive console mode
   195 if WEBMCP_MODE == "interactive" then
   196   execute.postfork_initializers()
   197   trace.disable()  -- avoids memory leakage (TODO: needs general solution for moonbridge?)
   198 end
   200 -- invoke moonbridge
   201 if WEBMCP_MODE == "listen" then
   202   local http = require("moonbridge_http")
   203   for i, listener in ipairs(listeners) do
   204     listener.prepare = execute.postfork_initializers
   205     listener.connect = http.generate_handler(
   206       request.handler,
   207       request.get_http_options()
   208     )
   209     listener.finish = execute.finalizers
   210     moonbridge_listen(listener)
   211   end
   212 end
