0
0
mirror of https://github.com/Doodle3D/doodle3d-firmware.git synced 2024-12-22 11:03:48 +01:00

Fix response sending when init() fails; create config.lua to contain global configuration; improve API function resolution; improve API code structure.

This commit is contained in:
Wouter R 2013-07-10 00:32:43 +02:00
parent 6caa7d244e
commit 1ac3f130ff
7 changed files with 216 additions and 197 deletions

20
TODO.md
View File

@ -1,10 +1,16 @@
# TODO (new functionality) # TODO (new functionality)
- save requested mod+func in request, as well as resolved function/pretty print version/function pointer (or subset…); then fix endpoint function name (when called with blank argument) in response objects to show pretty print name
- fix init script handling as described here: http://wiki.openwrt.org/doc/devel/packages#packaging.a.service - fix init script handling as described here: http://wiki.openwrt.org/doc/devel/packages#packaging.a.service
- write a simple client script to autotest as much of the api as possible - implement (automated) test code where possible
extend the client script to run arbitrary post/get requests * in 'test' dir next to 'src', with API tests under 'test/www/'
- document REST API (mention rq IDs and endpoint information, list endpoints+args+CRUD type, unknown values are empty fields) * www tests check functionality of the test module
(describe fail/error difference: fail is valid rq..could not comply, while error is invalid rq _or_ system error) * www tests also provide an interface to run arbitrary get/post requests
- document REST API
* fail/error difference: fail is a valid rq aka 'could not comply', while error is invalid rq _or_ system error
* modules/functions prefixed with '_' are for internal use
* rq IDs and endpoint information can be supplied (but it's probably not useful after all)
* list endpoints+args+CRUD type
* success/fail/error statuses are justified by drupal api
* unknown values (e.g. in network info) are either empty or unmentioned fields
- use a slightly more descriptive success/error definition (e.g. errortype=system/missing-arg/generic) - use a slightly more descriptive success/error definition (e.g. errortype=system/missing-arg/generic)
- steps to take regarding versioning/updating - steps to take regarding versioning/updating
* versioning scheme * versioning scheme
@ -17,7 +23,9 @@
* expose through info API and/or system API; also provide a way (future) to flash a new image * expose through info API and/or system API; also provide a way (future) to flash a new image
- dynamic AP name based on partial MAC (set once on installation and then only upon explicit request? (e.g. api/config/wifiname/default)) - dynamic AP name based on partial MAC (set once on installation and then only upon explicit request? (e.g. api/config/wifiname/default))
- require api functions which change state to be invoked as post request - require api functions which change state to be invoked as post request
- add API functions to test network connectivity in steps (ifup? hasip? resolve? ping?) to network or test * can this be modelled like java annotations or c function attributes?
* otherwise maybe pair each function with <func>_attribs = {…}?
- add API functions to test network connectivity in steps (any chance(e.g. ~ap)? ifup? hasip? resolve? ping?) to network or test
- add more config options to package, which should act as defaults for a config file on the system; candidates: - add more config options to package, which should act as defaults for a config file on the system; candidates:
reconf.WWW_RENAME_NAME, wifihelper.{AP_ADDRESS, AP_NETMASK, (NET)} reconf.WWW_RENAME_NAME, wifihelper.{AP_ADDRESS, AP_NETMASK, (NET)}
<https://github.com/2ion/ini.lua> <https://github.com/2ion/ini.lua>

10
src/config.lua Normal file
View File

@ -0,0 +1,10 @@
local M = {}
--NOTE: pcall protects from invocation exceptions, which is what we need except
--during debugging. This flag replaces them with a normal call so we can inspect stack traces.
M.DEBUG_PCALLS = true
--REST responses will contain 'module' and 'function' keys describing what was requested
M.API_INCLUDE_ENDPOINT_INFO = true
return M

View File

@ -3,12 +3,7 @@ local RequestClass = require("rest.request")
local ResponseClass = require("rest.response") local ResponseClass = require("rest.response")
local wifi = require("network.wlanconfig") local wifi = require("network.wlanconfig")
local netconf = require("network.netconfig") local netconf = require("network.netconfig")
local config = require("config")
--NOTE: pcall protects from invocation exceptions, which is what we need except
--during debugging. This flag replaces them with a normal call so we can inspect stack traces.
local DEBUG_PCALLS = true
local postData = nil local postData = nil
@ -21,7 +16,7 @@ local function init()
l:init(l.LEVEL.debug) l:init(l.LEVEL.debug)
l:setStream(io.stderr) l:setStream(io.stderr)
if DEBUG_PCALLS then l:info("Wifibox CGI handler started (pcall debugging enabled)") if config.DEBUG_PCALLS then l:info("Wifibox CGI handler started (pcall debugging enabled)")
else l:info("Wifibox CGI handler started") else l:info("Wifibox CGI handler started")
end end
@ -41,7 +36,7 @@ local function init()
end end
local function main() local function main()
local rq = RequestClass.new(postData, DEBUG_PCALLS) -- initializes itself using various environment variables and the arg array local rq = RequestClass.new(postData, config.DEBUG_PCALLS)
l:info("received request of type " .. rq:getRequestMethod() .. " with arguments: " .. l:dump(rq:getAll())) l:info("received request of type " .. rq:getRequestMethod() .. " with arguments: " .. l:dump(rq:getAll()))
if rq:getRequestMethod() ~= "CMDLINE" then if rq:getRequestMethod() ~= "CMDLINE" then
@ -49,7 +44,7 @@ end
l:debug("user agent: " .. rq:getUserAgent()) l:debug("user agent: " .. rq:getUserAgent())
end end
if (not DEBUG_PCALLS and rq:getRequestMethod() == "CMDLINE") then if (not config.DEBUG_PCALLS and rq:getRequestMethod() == "CMDLINE") then
if rq:get("autowifi") ~= nil then if rq:get("autowifi") ~= nil then
setupAutoWifiMode() setupAutoWifiMode()
else else
@ -65,12 +60,17 @@ end
end end
end end
---'entry point'---
local s, msg = init() local s, msg = init()
if s == false then if s == false then
local resp = ResponseClass.new() local resp = ResponseClass.new()
resp:setError("initialization failed (" .. msg .. ")") local errSuffix = msg and " (" .. msg .. ")" or ""
resp:send() --FIXME: this message does not seem to be sent
l:error("initialization failed (" .. msg .. ")") --NOTE: this assumes the logger has been inited properly, despite init() having failed resp:setError("initialization failed" .. errSuffix)
io.write ("Content-type: text/plain\r\n\r\n")
resp:send()
l:error("initialization failed" .. errSuffix) --NOTE: this assumes the logger has been inited properly, despite init() having failed
os.exit(1) os.exit(1)
else else
main() main()

View File

@ -8,21 +8,20 @@ local M = {}
M.isApi = true M.isApi = true
function M._global(d) function M._global(request, response)
local r = ResponseClass.new(d) response:setError("not implemented")
r:setError("not implemented")
return r
end end
--accepts API argument 'nofilter'(bool) to disable filtering of APs and 'self' --accepts API argument 'nofilter'(bool) to disable filtering of APs and 'self'
function M.available(d) --accepts with_raw(bool) to include raw table dump
local r = ResponseClass.new(d) function M.available(request, response)
local noFilter = u.toboolean(d:get("nofilter")) local noFilter = u.toboolean(request:get("nofilter"))
local withRaw = u.toboolean(request:get("with_raw"))
local sr = wifi.getScanInfo() local sr = wifi.getScanInfo()
local si, se local si, se
if sr and #sr > 0 then if sr and #sr > 0 then
r:setSuccess("") response:setSuccess("")
local netInfoList = {} local netInfoList = {}
for _, se in ipairs(sr) do for _, se in ipairs(sr) do
if noFilter or se.mode ~= "ap" and se.ssid ~= wifi.AP_SSID then if noFilter or se.mode ~= "ap" and se.ssid ~= wifi.AP_SSID then
@ -36,26 +35,25 @@ function M.available(d)
netInfo["signal"] = se.signal netInfo["signal"] = se.signal
netInfo["quality"] = se.quality netInfo["quality"] = se.quality
netInfo["quality_max"] = se.quality_max netInfo["quality_max"] = se.quality_max
--netInfo["raw"] = l:dump(se) --TEMP for debugging only if withRaw then netInfo["_raw"] = l:dump(se) end
table.insert(netInfoList, netInfo) table.insert(netInfoList, netInfo)
end end
end end
r:addData("count", #netInfoList) response:addData("count", #netInfoList)
r:addData("networks", netInfoList) response:addData("networks", netInfoList)
else else
r:setFail("No scan results or scanning not possible") response:setFail("No scan results or scanning not possible")
end end
return r
end end
--accepts API argument 'nofilter'(bool) to disable filtering of APs and 'self' --accepts API argument 'nofilter'(bool) to disable filtering of APs and 'self'
function M.known(d) --accepts with_raw(bool) to include raw table dump
local r = ResponseClass.new(d) function M.known(request, response)
local noFilter = u.toboolean(d:get("nofilter")) local noFilter = u.toboolean(request:get("nofilter"))
local withRaw = u.toboolean(request:get("with_raw"))
r:setSuccess() response:setSuccess()
local netInfoList = {} local netInfoList = {}
for _, net in ipairs(wifi.getConfigs()) do for _, net in ipairs(wifi.getConfigs()) do
if noFilter or net.mode == "sta" then if noFilter or net.mode == "sta" then
@ -64,47 +62,43 @@ function M.known(d)
netInfo["bssid"] = net.bssid or "" netInfo["bssid"] = net.bssid or ""
netInfo["channel"] = net.channel or "" netInfo["channel"] = net.channel or ""
netInfo["encryption"] = net.encryption netInfo["encryption"] = net.encryption
--netInfo["raw"] = l:dump(net) --TEMP for debugging only if withRaw then netInfo["_raw"] = l:dump(net) end
table.insert(netInfoList, netInfo) table.insert(netInfoList, netInfo)
end end
end end
r:addData("count", #netInfoList) response:addData("count", #netInfoList)
r:addData("networks", netInfoList) response:addData("networks", netInfoList)
return r
end end
function M.state(d) --accepts with_raw(bool) to include raw table dump
local r = ResponseClass.new(d) function M.state(request, response)
local withRaw = u.toboolean(request:get("with_raw"))
local ds = wifi.getDeviceState() local ds = wifi.getDeviceState()
r:setSuccess() response:setSuccess()
r:addData("ssid", ds.ssid or "") response:addData("ssid", ds.ssid or "")
r:addData("bssid", ds.bssid or "") response:addData("bssid", ds.bssid or "")
r:addData("channel", ds.channel or "") response:addData("channel", ds.channel or "")
r:addData("mode", ds.mode) response:addData("mode", ds.mode)
r:addData("encryption", ds.encryption) response:addData("encryption", ds.encryption)
r:addData("quality", ds.quality) response:addData("quality", ds.quality)
r:addData("quality_max", ds.quality_max) response:addData("quality_max", ds.quality_max)
r:addData("txpower", ds.txpower) response:addData("txpower", ds.txpower)
r:addData("signal", ds.signal) response:addData("signal", ds.signal)
r:addData("noise", ds.noise) response:addData("noise", ds.noise)
--r:addData("raw", l:dump(ds)) --TEMP for debugging only if withRaw then response:addData("_raw", l:dump(ds)) end
return r
end end
--UNTESTED --UNTESTED
--requires ssid(string), accepts phrase(string), recreate(bool) --requires ssid(string), accepts phrase(string), recreate(bool)
function M.assoc(d) function M.assoc(request, response)
local r = ResponseClass.new(d) local argSsid = request:get("ssid")
local argSsid = d:get("ssid") local argPhrase = request:get("phrase")
local argPhrase = d:get("phrase") local argRecreate = request:get("recreate")
local argRecreate = d:get("recreate")
if argSsid == nil or argSsid == "" then if argSsid == nil or argSsid == "" then
r:setError("missing ssid argument") response:setError("missing ssid argument")
return r return
end end
local cfg = nil local cfg = nil
@ -121,65 +115,53 @@ function M.assoc(d)
wifi.createConfigFromScanInfo(scanResult, argPhrase) wifi.createConfigFromScanInfo(scanResult, argPhrase)
else else
--check for error --check for error
r:setFail("no wireless network with requested SSID is available") response:setFail("no wireless network with requested SSID is available")
r:addData("ssid", argSsid) response:addData("ssid", argSsid)
return
end end
end end
wifi.activateConfig(argSsid) wifi.activateConfig(argSsid)
netconf.switchConfiguration{ wifiiface="add", apnet="rm", staticaddr="rm", dhcppool="rm", wwwredir="rm", dnsredir="rm", wwwcaptive="rm", wireless="reload" } netconf.switchConfiguration{ wifiiface="add", apnet="rm", staticaddr="rm", dhcppool="rm", wwwredir="rm", dnsredir="rm", wwwcaptive="rm", wireless="reload" }
r:setSuccess("wlan associated") response:setSuccess("wlan associated")
r:addData("ssid", argSsid) response:addData("ssid", argSsid)
return r
end end
--UNTESTED --UNTESTED
function M.disassoc(d) function M.disassoc(request, response)
local r = ResponseClass.new(d)
wifi.activateConfig() wifi.activateConfig()
local rv = wifi.restart() local rv = wifi.restart()
r:setSuccess("all wireless networks deactivated") response:setSuccess("all wireless networks deactivated")
r:addData("wifi_restart_result", rv) response:addData("wifi_restart_result", rv)
return r
end end
--UNTESTED --UNTESTED
function M.openap(d) function M.openap(request, response)
local r = ResponseClass.new(d)
--add AP net, activate it, deactivate all others, reload network/wireless config, add all dhcp and captive settings and reload as needed --add AP net, activate it, deactivate all others, reload network/wireless config, add all dhcp and captive settings and reload as needed
netconf.switchConfiguration{apnet="add_noreload"} netconf.switchConfiguration{apnet="add_noreload"}
wifi.activateConfig(wifi.AP_SSID) wifi.activateConfig(wifi.AP_SSID)
netconf.switchConfiguration{ wifiiface="add", network="reload", staticaddr="add", dhcppool="add", wwwredir="add", dnsredir="add", wwwcaptive="add" } netconf.switchConfiguration{ wifiiface="add", network="reload", staticaddr="add", dhcppool="add", wwwredir="add", dnsredir="add", wwwcaptive="add" }
r:setSuccess("switched to Access Point mode") response:setSuccess("switched to Access Point mode")
r:addData("ssid", wifi.AP_SSID) response:addData("ssid", wifi.AP_SSID)
return r
end end
--UNTESTED --UNTESTED
--requires ssid(string) --requires ssid(string)
function M.rm(d) function M.rm(request, response)
local r = ResponseClass.new(d) local argSsid = request:get("ssid")
local argSsid = d:get("ssid")
if argSsid == nil or argSsid == "" then if argSsid == nil or argSsid == "" then
r:setError("missing ssid argument") response:setError("missing ssid argument")
return r return
end end
if wifi.removeConfig(argSsid) then if wifi.removeConfig(argSsid) then
r:setSuccess("removed wireless network with requested SSID") response:setSuccess("removed wireless network with requested SSID")
r:addData("ssid", argSsid) response:addData("ssid", argSsid)
else else
r:setFail("no wireless network with requested SSID") --this used to be a warning instead of an error... response:setFail("no wireless network with requested SSID") --this used to be a warning instead of an error...
r:addData("ssid", argSsid) response:addData("ssid", argSsid)
end end
return r
end end
return M return M

View File

@ -5,42 +5,31 @@ local M = {}
M.isApi = true M.isApi = true
function M._global(d) function M._global(request, response)
local r = ResponseClass.new(d) local ba = request:getBlankArgument()
local ba = d:getBlankArgument()
r:setSuccess("REST test API - default function called with blank argument: '" .. (ba or "<nil>") .. "'") response:setSuccess("REST test API - default function called with blank argument: '" .. (ba or "<nil>") .. "'")
if ba ~= nil then r:addData("blank_argument", ba) end if ba ~= nil then response:addData("blank_argument", ba) end
return r
end end
function M.success(d) function M.success(request, response)
local r = ResponseClass.new(d) response:setSuccess("this successful response has been generated on purpose")
r:setSuccess("this successful response has been generated on purpose") response:addData("url", "http://xkcd.com/349/")
r:addData("url", "http://xkcd.com/349/")
return r
end end
function M.fail(d) function M.fail(request, response)
local r = ResponseClass.new(d) response:setFail("this failure has been generated on purpose")
r:setFail("this failure has been generated on purpose") response:addData("url", "http://xkcd.com/336/")
r:addData("url", "http://xkcd.com/336/")
return r
end end
function M.error(d) function M.error(request, response)
local r = ResponseClass.new(d) response:setError("this error has been generated on purpose")
r:setError("this error has been generated on purpose") response:addData("url", "http://xkcd.com/1024/")
r:addData("url", "http://xkcd.com/1024/")
return r
end end
function M.echo(d) function M.echo(request, response)
local r = ResponseClass.new(d) response:setSuccess("request echo")
r:setSuccess("request echo") response:addData("request_data", request)
r:addData("request_data", d)
return r
end end
return M return M

View File

@ -1,4 +1,5 @@
local urlcode = require("util.urlcode") local urlcode = require("util.urlcode")
local config = require("config")
local ResponseClass = require("rest.response") local ResponseClass = require("rest.response")
local M = {} local M = {}
@ -6,12 +7,24 @@ M.__index = M
local GLOBAL_API_FUNCTION_NAME = "_global" local GLOBAL_API_FUNCTION_NAME = "_global"
--NOTE: requestedApi* contain what was extracted from the request data
-- regarding the other variables: either both resolvedApiFunction and realApiFunctionName
-- are nil and resolutionError is not, or exactly the other way around
M.requestedApiModule = nil
M.requestedApiFunction = nil
M.resolvedApiFunction = nil --will contain function address, or nil
M.realApiFunctionName = nil --will contain requested name, or global name, or nil
M.resolutionError = nil --non-nil means function could not be resolved
local function kvTableFromUrlEncodedString(encodedText) local function kvTableFromUrlEncodedString(encodedText)
local args = {} local args = {}
if (encodedText ~= nil) then if (encodedText ~= nil) then
urlcode.parsequery(encodedText, args) urlcode.parsequery(encodedText, args)
end end
return args return args
end end
local function kvTableFromArray(argArray) local function kvTableFromArray(argArray)
@ -30,12 +43,53 @@ local function kvTableFromArray(argArray)
end end
--returns either a module object, or nil+errmsg
local function resolveApiModule(modname)
if modname == nil then return nil, "missing module name" end
if string.find(modname, "_") == 1 then return nil, "module names starting with '_' are preserved for internal use" end
local reqModName = "rest.api.api_" .. modname
local ok, modObj
if config.DEBUG_PCALLS then ok, modObj = true, require(reqModName)
else ok, modObj = pcall(require, reqModName)
end
if ok == false then return nil, "API module does not exist" end
if modObj == nil then return nil, "API module could not be found" end
if modObj.isApi ~= true then return nil, "module is not part of the CGI API" end
return modObj
end
--returns funcobj+nil (usual), funcobj+number (global func with blank arg), or nil+errmsg (unresolvable or inaccessible)
local function resolveApiFunction(modname, funcname)
if funcname and string.find(funcname, "_") == 1 then return nil, "function names starting with '_' are preserved for internal use" end
local mod, msg = resolveApiModule(modname)
if (funcname == nil or funcname == '') then funcname = GLOBAL_API_FUNCTION_NAME end --treat empty function name as nil
local f = mod[funcname]
local funcNumber = tonumber(funcname)
if (type(f) == "function") then
return f
elseif funcNumber ~= nil then
return mod[GLOBAL_API_FUNCTION_NAME], funcNumber
else
return nil, ("function '" .. funcname .. "' does not exist in API module '" .. modname .. "'")
end
end
setmetatable(M, { setmetatable(M, {
__call = function(cls, ...) __call = function(cls, ...)
return cls.new(...) return cls.new(...)
end end
}) })
--This function initializes itself using various environment variables, the arg array and the given postData
--NOTE: if debugging is enabled, commandline arguments 'm' and 'f' override requested module and function
function M.new(postData, debug) function M.new(postData, debug)
local self = setmetatable({}, M) local self = setmetatable({}, M)
@ -54,30 +108,54 @@ function M.new(postData, debug)
self.postArgs = kvTableFromUrlEncodedString(postData) self.postArgs = kvTableFromUrlEncodedString(postData)
--TEMP: until these can be extracted from the url path itself --TEMP: until these can be extracted from the url path itself
self.apiModule = self.getArgs["m"] self.requestedApiModule = self.getArgs["m"]
self.apiFunction = self.getArgs["f"] self.requestedApiFunction = self.getArgs["f"]
if debug then if debug then
self.apiModule = self.cmdLineArgs["m"] or self.apiModule self.requestedApiModule = self.cmdLineArgs["m"] or self.requestedApiModule
self.apiFunction = self.cmdLineArgs["f"] or self.apiFunction self.requestedApiFunction = self.cmdLineArgs["f"] or self.requestedApiFunction
end
if self.requestedApiModule == "" then self.requestedApiModule = nil end
if self.requestedApiFunction == "" then self.requestedApiFunction = nil end
-- Perform module/function resolution
--TODO: improve naming and perhaps argument passing
local sfunc, sres = resolveApiFunction(self:getRequestedApiModule(), self:getRequestedApiFunction())
if sfunc ~= nil then --function (possibly the global one) could be resolved
self.resolvedApiFunction = sfunc
if sres ~= nil then --apparently it was the global one, and we received a 'blank argument'
self:setBlankArgument(sres)
self.realApiFunctionName = GLOBAL_API_FUNCTION_NAME
else --resolved without blank argument but still potentially the global function, hence the _or_ construction
self.realApiFunctionName = self:getRequestedApiFunction() or GLOBAL_API_FUNCTION_NAME
end
else
--instead of throwing an error, save the message for handle() which is expected to return a response anyway
self.resolutionError = sres
end end
if self.apiModule == "" then self.apiModule = nil end
if self.apiFunction == "" then self.apiFunction = nil end
return self return self
end end
--GET/POST/CMDLINE
function M:getRequestMethod() function M:getRequestMethod()
return self.requestMethod return self.requestMethod
end end
function M:getApiModule() function M:getRequestedApiModule()
return self.apiModule return self.requestedApiModule
end end
function M:getApiFunction() function M:getRequestedApiFunction()
return self.apiFunction return self.requestedApiFunction
end
function M:getRealApiFunctionName()
return self.realApiFunctionName
end end
function M:getBlankArgument() function M:getBlankArgument()
@ -116,72 +194,29 @@ function M:getAll()
end end
end end
--returns either a module object, or nil+errmsg
local function resolveApiModule(modname)
if modname == nil then return nil, "missing module name" end
if string.find(modname, "_") == 1 then return nil, "module names starting with '_' are preserved for internal use" end
local reqModName = "rest.api.api_" .. modname
local ok, modObj
--TODO: create config.lua which contains DEBUG_PCALLS (nothing else for the moment)
if DEBUG_PCALLS then ok, modObj = true, require(reqModName)
else ok, modObj = pcall(require, reqModName)
end
if ok == false then return nil, "API module does not exist" end
if modObj == nil then return nil, "API module could not be found" end
if modObj.isApi ~= true then return nil, "module is not part of the CGI API" end
return modObj
end
--returns funcobj+nil (usual), funcobj+number (global func with blank arg), or nil+errmsg (unresolvable or inaccessible)
local function resolveApiFunction(modname, funcname)
if funcname and string.find(funcname, "_") == 1 then return nil, "function names starting with '_' are preserved for internal use" end
local mod, msg = resolveApiModule(modname)
if (funcname == nil or funcname == '') then funcname = GLOBAL_API_FUNCTION_NAME end --treat empty function name as nil
local f = mod[funcname]
local funcNumber = tonumber(funcname)
if (type(f) == "function") then
return f
elseif funcNumber ~= nil then
return mod[GLOBAL_API_FUNCTION_NAME], funcNumber
else
return nil, ("function '" .. funcname .. "' does not exist in API module '" .. modname .. "'")
end
end
--returns either a response object+nil, or response object+errmsg --returns either a response object+nil, or response object+errmsg
function M:handle() function M:handle()
local modname = self:getRequestedApiModule()
--TEMP: should be moved to init local resp = ResponseClass.new(self)
local mod = self:getApiModule()
local func = self:getApiFunction()
local sf, sr = resolveApiFunction(mod, func)
local resp = ResponseClass.new(rq) --TEMP: do not do this before resolving. after resolving has been moved to init that will be automatically true if (self.resolvedApiFunction ~= nil) then --we found a function (possible the global function)
--invoke the function
if (sf ~= nil) then
if (sr ~= nil) then self:setBlankArgument(sr) end
local ok, r local ok, r
if DEBUG_PCALLS then ok, r = true, sf(self) if config.DEBUG_PCALLS then ok, r = true, self.resolvedApiFunction(self, resp)
else ok, r = pcall(sf, self) else ok, r = pcall(self.resolvedApiFunction, self, resp)
end end
--handle the result
if ok == true then if ok == true then
return r, nil return resp, nil
else else
resp:setError("call to function '" .. mod .. "/" .. sr .. "' failed") resp:setError("call to function '" .. modname .. "/" .. self.realApiFunctionName .. "' failed")
return resp, ("calling function '" .. func .. "' in API module '" .. mod .. "' somehow failed ('" .. r .. "')") return resp, ("calling function '" .. self.realApiFunctionName .. "' in API module '" .. modname .. "' somehow failed ('" .. r .. "')")
end end
else else
resp:setError("function unknown '" .. (mod or "<empty>") .. "/" .. (func or "<global>") .. "'") resp:setError("function unknown '" .. (modname or "<empty>") .. "/" .. (self:getRequestedApiFunction() or "<empty>") .. "'")
return resp, ("could not resolve requested API function ('" .. sr .. "')") return resp, ("could not resolve requested API function ('" .. self.resolutionError .. "')")
end end
return resp return resp

View File

@ -1,10 +1,10 @@
local JSON = (loadfile "util/JSON.lua")() local JSON = (loadfile "util/JSON.lua")()
local config = require("config")
local M = {} local M = {}
M.__index = M M.__index = M
local REQUEST_ID_ARGUMENT = "rq_id" local REQUEST_ID_ARGUMENT = "rq_id"
local INCLUDE_ENDPOINT_INFO = false
setmetatable(M, { setmetatable(M, {
__call = function(cls, ...) __call = function(cls, ...)
@ -22,20 +22,15 @@ function M.new(requestObject)
local rqId = requestObject:get(REQUEST_ID_ARGUMENT) local rqId = requestObject:get(REQUEST_ID_ARGUMENT)
if rqId ~= nil then self.body[REQUEST_ID_ARGUMENT] = rqId end if rqId ~= nil then self.body[REQUEST_ID_ARGUMENT] = rqId end
if INCLUDE_ENDPOINT_INFO == true then if config.API_INCLUDE_ENDPOINT_INFO == true then
self.body["module"] = requestObject:getApiModule() self.body["module"] = requestObject:getRequestedApiModule()
self.body["function"] = requestObject:getApiFunction() or "" self.body["function"] = requestObject:getRealApiFunctionName() or ""
end end
end end
return self return self
end end
--use set{Success|Fail|Error}()
--function M:setStatus(s)
-- self.body.status = s
--end
function M:setSuccess(msg) function M:setSuccess(msg)
self.body.status = "success" self.body.status = "success"
if msg ~= "" then self.body.msg = msg end if msg ~= "" then self.body.msg = msg end