webmcp

annotate framework/bin/mcp.lua @ 311:9fef75a02542

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

Impressum / About Us