webmcp

annotate framework/bin/mcp.lua @ 300:d1d21ae9acdb

Fixed typo in trace._render_sub_tree(...)
author jbe
date Sun Mar 22 19:26:51 2015 +0100 (2015-03-22)
parents 0a6378afc6da
children 4e69ce9a6365
rev   line source
jbe@203 1 #!/usr/bin/env moonbridge
jbe/bsw@0 2
jbe@294 3 --[[--
jbe@294 4 WEBMCP_VERSION
jbe@294 5
jbe@294 6 A string containing the WebMCP version, e.g. "2.0.0"
jbe@294 7 --]]--
jbe@278 8 WEBMCP_VERSION = "2.0.0"
jbe@294 9 --//--
jbe@64 10
jbe@231 11 -- allow control of global environment
jbe@231 12 local _G = _G
jbe@237 13 local allowed_globals = {}
jbe@231 14 local global_metatable = {
jbe@231 15 __index = _G,
jbe@231 16 __newindex = function(self, key, value)
jbe@231 17 _G[key] = value
jbe@231 18 end
jbe@231 19 }
jbe@231 20 _ENV = setmetatable({}, global_metatable)
jbe@231 21
jbe@294 22 --[[--
jbe@294 23 WEBMCP_MODE
jbe@294 24
jbe@294 25 A constant set to "listen" in case of a network request, or set to "interactive" in case of interactive mode.
jbe@294 26 --]]--
jbe@203 27 -- check if interactive mode
jbe@203 28 if listen then -- defined by moonbridge
jbe@203 29 WEBMCP_MODE = "listen"
jbe@203 30 else
jbe@203 31 WEBMCP_MODE = "interactive"
jbe@64 32 end
jbe@294 33 --//--
jbe@203 34
jbe@294 35 --[[--
jbe@294 36 WEBMCP_CONFIG_NAMES
jbe@294 37
jbe@294 38 A list of the selected configuration names.
jbe@294 39 --]]--
jbe@294 40 -- configuration names are provided as 4th, 5th, etc. command line argument
jbe@206 41 WEBMCP_CONFIG_NAMES = {select(4, ...)}
jbe@294 42 --//--
jbe@294 43
jbe@294 44 --[[--
jbe@294 45 WEBMCP_FRAMEWORK_PATH
jbe@294 46
jbe@294 47 Directory of the WebMCP framework (always includes a trailing slash).
jbe@294 48 --]]--
jbe@294 49 -- set in mcp.lua
jbe@294 50 --//--
jbe@294 51
jbe@294 52 --[[--
jbe@294 53 WEBMCP_BASE_PATH
jbe@294 54
jbe@294 55 Base directory of the application (always includes a trailing slash).
jbe@294 56 --]]--
jbe@294 57 -- set in mcp.lua
jbe@294 58 --//--
jbe@294 59
jbe@294 60 --[[--
jbe@294 61 WEBMCP_APP_NAME
jbe@294 62
jbe@294 63 Application name (usually "main"). May be nil in case of interactive mode.
jbe@294 64 --]]--
jbe@294 65 -- set in mcp.lua
jbe@294 66 --//--
jbe@203 67
jbe@203 68 -- determine framework and bath path from command line arguments
jbe@203 69 -- or print usage synopsis (if applicable)
jbe@68 70 do
jbe@206 71 local arg1, arg2, arg3 = ...
jbe@203 72 local helpout
jbe@203 73 if
jbe@203 74 arg1 == "-h" or arg1 == "--help" or
jbe@206 75 arg2 == "-h" or arg2 == "--help" -- if first arg is provided by wrapper
jbe@203 76 then
jbe@203 77 helpout = io.stdout
jbe@203 78 elseif
jbe@217 79 #WEBMCP_CONFIG_NAMES < 1 or
jbe@206 80 (WEBMCP_MODE == "interactive") ~= (arg3 == "INTERACTIVE")
jbe@203 81 then
jbe@203 82 helpout = io.stderr
jbe@203 83 end
jbe@203 84 if helpout then
jbe@217 85 helpout:write("Usage: moonbridge -- <framework path>/bin/mcp.lua <framework path> <app base path> <app name> <config name> [<config name> ...]\n")
jbe@217 86 helpout:write(" or: lua -i <framework path>/bin/mcp.lua <framework path> <app base path> INTERACTIVE <config name> [<config name> ...]\n")
jbe@203 87 if helpout == io.stderr then
jbe@203 88 return 1
jbe@68 89 else
jbe@203 90 return 0
jbe@68 91 end
jbe@68 92 end
jbe@203 93 local function append_trailing_slash(str)
jbe@217 94 return string.gsub(str, "([^/])$", function(last) return last .. "/" end)
jbe@203 95 end
jbe@203 96 WEBMCP_FRAMEWORK_PATH = append_trailing_slash(arg1)
jbe@203 97 WEBMCP_BASE_PATH = append_trailing_slash(arg2)
jbe@206 98 if WEBMCP_MODE == "listen" then
jbe@206 99 WEBMCP_APP_NAME = arg3
jbe@206 100 end
jbe@68 101 end
jbe@1 102
jbe@203 103 -- setup search paths for libraries
jbe/bsw@0 104 do
jbe@217 105 if string.match(package.path, "^[^;]") then
jbe@217 106 package.path = ";" .. package.path
jbe@217 107 end
jbe@217 108 package.path = WEBMCP_FRAMEWORK_PATH .. "lib/?.lua" .. package.path
jbe/bsw@0 109 -- find out which file name extension shared libraries have
jbe/bsw@0 110 local slib_exts = {}
jbe/bsw@0 111 for ext in string.gmatch(package.cpath, "%?%.([A-Za-z0-9_-]+)") do
jbe@217 112 if not slib_exts[ext] then
jbe@217 113 slib_exts[#slib_exts+1] = ext
jbe@217 114 slib_exts[ext] = true
jbe@217 115 end
jbe/bsw@0 116 end
jbe/bsw@0 117 local paths = {}
jbe@217 118 for i, ext in ipairs(slib_exts) do
jbe@203 119 paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "accelerator/?." .. ext
jbe/bsw@0 120 end
jbe@217 121 for i, ext in ipairs(slib_exts) do
jbe@203 122 paths[#paths+1] = WEBMCP_FRAMEWORK_PATH .. "lib/?." .. ext
jbe/bsw@0 123 end
jbe/bsw@0 124 paths[#paths+1] = package.cpath
jbe/bsw@0 125 package.cpath = table.concat(paths, ";")
jbe/bsw@0 126 end
jbe/bsw@0 127
jbe@203 128 -- autoloader system for WebMCP environment "$WEBMCP_FRAMEWORK_PATH/env/",
jbe@203 129 -- application environment extensions "$WEBMCP_BASE_PATH/env/"
jbe@203 130 -- and models "$WEBMCP_BASE_PATH/model/"
jbe/bsw@0 131 do
jbe/bsw@0 132 local weakkey_mt = { __mode = "k" }
jbe/bsw@0 133 local autoloader_category = setmetatable({}, weakkey_mt)
jbe/bsw@0 134 local autoloader_path = setmetatable({}, weakkey_mt)
jbe/bsw@0 135 local autoloader_mt = {}
jbe@219 136 local function install_autoloader(self, category, path_fragment)
jbe/bsw@0 137 autoloader_category[self] = category
jbe@219 138 autoloader_path[self] = path_fragment
jbe/bsw@0 139 setmetatable(self, autoloader_mt)
jbe/bsw@0 140 end
jbe/bsw@0 141 local function try_exec(filename)
jbe/bsw@0 142 local file = io.open(filename, "r")
jbe/bsw@0 143 if file then
jbe/bsw@0 144 local filedata = file:read("*a")
jbe/bsw@0 145 io.close(file)
jbe@232 146 local func, errmsg = load(filedata, "=" .. filename, nil, _ENV)
jbe/bsw@0 147 if func then
jbe/bsw@0 148 func()
jbe/bsw@0 149 return true
jbe/bsw@0 150 else
jbe/bsw@0 151 error(errmsg, 0)
jbe/bsw@0 152 end
jbe/bsw@0 153 else
jbe/bsw@0 154 return false
jbe/bsw@0 155 end
jbe/bsw@0 156 end
jbe/bsw@0 157 function autoloader_mt.__index(self, key)
jbe/bsw@0 158 local category, base_path, merge_base_path, file_key
jbe/bsw@0 159 local merge = false
jbe/bsw@0 160 if
jbe/bsw@0 161 string.find(key, "^[a-z_][A-Za-z0-9_]*$") and
jbe/bsw@0 162 not string.find(key, "^__")
jbe/bsw@0 163 then
jbe/bsw@0 164 category = "env"
jbe@203 165 base_path = WEBMCP_FRAMEWORK_PATH .. "env/"
jbe/bsw@0 166 merge = true
jbe@203 167 merge_base_path = WEBMCP_BASE_PATH .. "env/"
jbe/bsw@0 168 file_key = key
jbe/bsw@0 169 elseif string.find(key, "^[A-Z][A-Za-z0-9]*$") then
jbe/bsw@0 170 category = "model"
jbe@203 171 base_path = WEBMCP_BASE_PATH .. "model/"
jbe/bsw@0 172 local first = true
jbe/bsw@0 173 file_key = string.gsub(key, "[A-Z]",
jbe/bsw@0 174 function(c)
jbe/bsw@0 175 if first then
jbe/bsw@0 176 first = false
jbe/bsw@0 177 return string.lower(c)
jbe/bsw@0 178 else
jbe/bsw@0 179 return "_" .. string.lower(c)
jbe/bsw@0 180 end
jbe/bsw@0 181 end
jbe/bsw@0 182 )
jbe/bsw@0 183 else
jbe/bsw@0 184 return
jbe/bsw@0 185 end
jbe/bsw@0 186 local required_category = autoloader_category[self]
jbe/bsw@0 187 if required_category and required_category ~= category then return end
jbe@219 188 local path_fragment = autoloader_path[self]
jbe@219 189 local path = base_path .. path_fragment .. file_key
jbe@219 190 local merge_path
jbe/bsw@0 191 if merge then
jbe@219 192 merge_path = merge_base_path .. path_fragment .. file_key
jbe/bsw@0 193 end
jbe/bsw@0 194 local function try_dir(dirname)
jbe/bsw@0 195 local dir = io.open(dirname)
jbe/bsw@0 196 if dir then
jbe/bsw@0 197 io.close(dir)
jbe/bsw@0 198 local obj = {}
jbe@219 199 install_autoloader(obj, category, path_fragment .. file_key .. "/")
jbe/bsw@0 200 rawset(self, key, obj)
jbe@219 201 try_exec(path .. "/__init.lua")
jbe@219 202 if merge then try_exec(merge_path .. "/__init.lua") end
jbe/bsw@0 203 return true
jbe/bsw@0 204 else
jbe/bsw@0 205 return false
jbe/bsw@0 206 end
jbe/bsw@0 207 end
jbe@238 208 if self == _G then
jbe@237 209 allowed_globals[key] = true
jbe@233 210 end
jbe@219 211 if merge and try_exec(merge_path .. ".lua") then
jbe@219 212 elseif merge and try_dir(merge_path .. "/") then
jbe@219 213 elseif try_exec(path .. ".lua") then
jbe@219 214 elseif try_dir(path .. "/") then
jbe/bsw@0 215 else end
jbe@238 216 if self == _G then
jbe@237 217 allowed_globals[key] = nil
jbe@233 218 end
jbe@237 219 return rawget(self, key)
jbe/bsw@0 220 end
jbe@219 221 install_autoloader(_G, nil, "")
jbe@203 222 try_exec(WEBMCP_FRAMEWORK_PATH .. "env/__init.lua")
jbe@203 223 try_exec(WEBMCP_BASE_PATH .. "env/__init.lua")
jbe/bsw@0 224 end
jbe/bsw@0 225
jbe@214 226 -- replace Moonbridge listen function
jbe@214 227 local moonbridge_listen = listen
jbe@225 228 local listeners = {}
jbe@214 229 function listen(args)
jbe@214 230 listeners[#listeners+1] = args
jbe@214 231 end
jbe@214 232
jbe@203 233 -- prohibit (unintended) definition of new global variables
jbe@237 234 function global_metatable.__newindex(self, key, value)
jbe@237 235 if not allowed_globals[key] then
jbe@237 236 error("Setting of global variable prohibited", 2)
jbe@237 237 end
jbe@239 238 _G[key] = value
jbe@231 239 end
jbe@203 240
jbe@220 241 -- execute configurations and pre-fork initializers
jbe@206 242 for i, config_name in ipairs(WEBMCP_CONFIG_NAMES) do
jbe@206 243 execute.config(config_name)
jbe@206 244 end
jbe@220 245 execute.prefork_initializers()
jbe@206 246
jbe@286 247 -- define post-fork initialization function (including loading of "multirand" library)
jbe@286 248 local function postfork_init()
jbe@286 249 _G.multirand = require "multirand"
jbe@286 250 execute.postfork_initializers()
jbe@286 251 end
jbe@286 252
jbe/bsw@0 253 -- interactive console mode
jbe@203 254 if WEBMCP_MODE == "interactive" then
jbe@286 255 postfork_init()
jbe@289 256 trace.disable() -- avoids memory leakage
jbe/bsw@0 257 end
jbe/bsw@0 258
jbe@204 259 -- invoke moonbridge
jbe@206 260 if WEBMCP_MODE == "listen" then
jbe@264 261 local http_options = request.get_http_options()
jbe@288 262 local min_requests_per_fork = http_options.min_requests_per_fork or 50
jbe@288 263 local max_requests_per_fork = http_options.max_requests_per_fork or 100
jbe@207 264 local http = require("moonbridge_http")
jbe@211 265 for i, listener in ipairs(listeners) do
jbe@264 266 local request_count = 0
jbe@266 267 local function inner_handler(http_request)
jbe@264 268 request_count = request_count + 1
jbe@288 269 request.handler(http_request, request_count >= max_requests_per_fork)
jbe@264 270 end
jbe@264 271 local outer_handler = http.generate_handler(inner_handler, http_options)
jbe@286 272 listener.prepare = postfork_init
jbe@264 273 listener.connect = function(socket)
jbe@264 274 outer_handler(socket)
jbe@288 275 return request_count < min_requests_per_fork
jbe@264 276 end
jbe@211 277 listener.finish = execute.finalizers
jbe@211 278 moonbridge_listen(listener)
jbe@204 279 end
jbe@204 280 end
jbe@204 281

Impressum / About Us