webmcp
view framework/bin/mcp.lua @ 209:2cb27106aa73
Removed functions request.get_config, request.get_app_basepath, request.get_app_name
| author | jbe | 
|---|---|
| date | Sat Jan 10 00:19:38 2015 +0100 (2015-01-10) | 
| parents | 2c2bcde0df79 | 
| children | 474cf0cfb85b | 
 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 -- prohibit (unintended) definition of new global variables
   174 _ENV = setmetatable({}, {
   175   __index = _G,
   176   __newindex = function()
   177     error("Setting of global variable prohibited")
   178   end
   179 })
   181 -- execute configurations
   182 for i, config_name in ipairs(WEBMCP_CONFIG_NAMES) do
   183   execute.config(config_name)
   184 end
   186 -- interactive console mode
   187 if WEBMCP_MODE == "interactive" then
   188   trace.disable()  -- avoids memory leakage (TODO: needs general solution for moonbridge?)
   189 end
   191 -- invoke moonbridge
   192 if WEBMCP_MODE == "listen" then
   193   local http = require("moonbridge_http")
   194   local moonbridge_listen = listen
   195   local listeners
   196   function _G.listen(args)
   197     listeners[#listeners+1] = args
   198   end
   199   for i = 1, #extraargs/2 do
   200     local config = {}
   201     listeners = {}
   202     execute.config(config_name)
   203     for i, listener in ipairs(listeners) do
   204       listener.prepare = execute.prefork_initializers
   205       listener.connect = http.generate_handler(
   206         request.get_http_options(),
   207         function(req)
   208           execute.postfork_initializers()
   209           request.handler(req)
   210         end
   211       )
   212       listener.finish = execute.finalizers
   213       moonbridge_listen(listener)
   214     end
   215   end
   216 end
   218 --[[ TODO: following lines to be moved to execute.server(...)
   220 local success, error_info = xpcall(
   221   function()
   223     -- restore slots if coming from http redirect
   224     if cgi.params.tempstore then
   225       trace.restore_slots{}
   226       local blob = tempstore.pop(cgi.params.tempstore)
   227       if blob then slot.restore_all(blob) end
   228     end
   230     local function file_exists(filename)
   231       local file = io.open(filename, "r")
   232       if file then
   233         io.close(file)
   234         return true
   235       else
   236         return false
   237       end
   238     end
   240     if request.is_404() then
   241       request.set_status("404 Not Found")
   242       if request.get_404_route() then
   243         request.forward(request.get_404_route())
   244       else
   245         error("No 404 page set.")
   246       end
   247     elseif request.get_action() then
   248       trace.request{
   249         module = request.get_module(),
   250         action = request.get_action()
   251       }
   252       if
   253         request.get_404_route() and
   254         not file_exists(
   255           encode.action_file_path{
   256             module = request.get_module(),
   257             action = request.get_action()
   258           }
   259         )
   260       then
   261         request.set_status("404 Not Found")
   262         request.forward(request.get_404_route())
   263       else
   264         if cgi.method ~= "POST" then
   265           request.set_status("405 Method Not Allowed")
   266           cgi.add_header("Allow: POST")
   267           error("Tried to invoke an action with a GET request.")
   268         end
   269         local action_status = execute.filtered_action{
   270           module = request.get_module(),
   271           action = request.get_action(),
   272         }
   273         if not request.is_rerouted() then
   274           local routing_mode, routing_module, routing_view
   275           routing_mode   = cgi.params["_webmcp_routing." .. action_status .. ".mode"]
   276           routing_module = cgi.params["_webmcp_routing." .. action_status .. ".module"]
   277           routing_view   = cgi.params["_webmcp_routing." .. action_status .. ".view"]
   278           routing_anchor = cgi.params["_webmcp_routing." .. action_status .. ".anchor"]
   279           if not (routing_mode or routing_module or routing_view) then
   280             action_status = "default"
   281             routing_mode   = cgi.params["_webmcp_routing.default.mode"]
   282             routing_module = cgi.params["_webmcp_routing.default.module"]
   283             routing_view   = cgi.params["_webmcp_routing.default.view"]
   284             routing_anchor = cgi.params["_webmcp_routing.default.anchor"]
   285           end
   286           assert(routing_module, "Routing information has no module.")
   287           assert(routing_view,   "Routing information has no view.")
   288           if routing_mode == "redirect" then
   289             local routing_params = {}
   290             for key, value in pairs(cgi.params) do
   291               local status, stripped_key = string.match(
   292                 key, "^_webmcp_routing%.([^%.]*)%.params%.(.*)$"
   293               )
   294               if status == action_status then
   295                 routing_params[stripped_key] = value
   296               end
   297             end
   298             request.redirect{
   299               module = routing_module,
   300               view   = routing_view,
   301               id     = cgi.params["_webmcp_routing." .. action_status .. ".id"],
   302               params = routing_params,
   303               anchor = routing_anchor
   304             }
   305           elseif routing_mode == "forward" then
   306             request.forward{ module = routing_module, view = routing_view }
   307           else
   308             error("Missing or unknown routing mode in request parameters.")
   309           end
   310         end
   311       end
   312     else
   313       -- no action
   314       trace.request{
   315         module = request.get_module(),
   316         view   = request.get_view()
   317       }
   318       if
   319         request.get_404_route() and
   320         not file_exists(
   321           encode.view_file_path{
   322             module = request.get_module(),
   323             view   = request.get_view()
   324           }
   325         )
   326       then
   327         request.set_status("404 Not Found")
   328         request.forward(request.get_404_route())
   329       end
   330     end
   332     if not request.get_redirect_data() then
   333       request.process_forward()
   334       local view = request.get_view()
   335       if string.find(view, "^_") then
   336         error("Tried to call a private view (prefixed with underscore).")
   337       end
   338       execute.filtered_view{
   339         module = request.get_module(),
   340         view   = view,
   341       }
   342     end
   344     -- force error due to missing absolute base URL until its too late to display error message
   345     --if request.get_redirect_data() then
   346     --  request.get_absolute_baseurl()
   347     --end
   349   end,
   351   function(errobj)
   352     return {
   353       errobj = errobj,
   354       stacktrace = string.gsub(
   355         debug.traceback('', 2),
   356         "^\r?\n?stack traceback:\r?\n?", ""
   357       )
   358     }
   359   end
   360 )
   362 if not success then trace.error{} end
   364 -- laufzeitermittlung
   365 trace.exectime{ real = extos.monotonic_hires_time(), cpu = os.clock() }
   367 slot.select('trace', trace.render)  -- render trace information
   369 local redirect_data = request.get_redirect_data()
   371 -- log error and switch to error layout, unless success
   372 if not success then
   373   local errobj     = error_info.errobj
   374   local stacktrace = error_info.stacktrace
   375   if not request.get_status() and not request.get_json_request_slots() then
   376     request.set_status("500 Internal Server Error")
   377   end
   378   slot.set_layout('system_error')
   379   slot.select('system_error', function()
   380     if getmetatable(errobj) == mondelefant.errorobject_metatable then
   381       slot.put(
   382         "<p>Database error of class <b>",
   383         encode.html(errobj.code),
   384         "</b> occured:<br/><b>",
   385         encode.html(errobj.message),
   386         "</b></p>"
   387       )
   388     else
   389       slot.put("<p><b>", encode.html(tostring(errobj)), "</b></p>")
   390     end
   391     slot.put("<p>Stack trace follows:<br/>")
   392     slot.put(encode.html_newlines(encode.html(stacktrace)))
   393     slot.put("</p>")
   394   end)
   395 elseif redirect_data then
   396   local redirect_params = {}
   397   for key, value in pairs(redirect_data.params) do
   398     redirect_params[key] = value
   399   end
   400   local slot_dump = slot.dump_all()
   401   if slot_dump ~= "" then
   402     redirect_params.tempstore = tempstore.save(slot_dump)
   403   end
   404   local json_request_slots = request.get_json_request_slots()
   405   if json_request_slots then
   406     redirect_params["_webmcp_json_slots[]"] = json_request_slots  
   407   end
   408   cgi.redirect(
   409     encode.url{
   410       base   = request.get_absolute_baseurl(),
   411       module = redirect_data.module,
   412       view   = redirect_data.view,
   413       id     = redirect_data.id,
   414       params = redirect_params,
   415       anchor = redirect_data.anchor
   416     }
   417   )
   418   cgi.send_data()
   419 end
   421 if not success or not redirect_data then
   423   local http_status = request.get_status()
   424   if http_status then
   425     cgi.set_status(http_status)
   426   end
   428   local json_request_slots = request.get_json_request_slots()
   429   if json_request_slots then
   430     cgi.set_content_type('application/json')
   431     local data = {}
   432     for idx, slot_ident in ipairs(json_request_slots) do
   433       data[slot_ident] = slot.get_content(slot_ident)
   434     end
   435     cgi.send_data(encode.json(data))
   436   else
   437     cgi.set_content_type(slot.get_content_type())
   438     cgi.send_data(slot.render_layout())
   439   end
   440 end
   442 --]]
