diff --git a/src/main.lua b/src/main.lua index 0a6ce60..f872e78 100644 --- a/src/main.lua +++ b/src/main.lua @@ -20,20 +20,20 @@ local function setupAutoWifiMode() end return nil end - + local wifiState = wifi.getDeviceState() local netName, netMode = wifiState.ssid, wifiState.mode - + local apSsid = wifi.getSubstitutedSsid(settings.get('network.ap.ssid')) local apMode = (apSsid == netName) and netMode == 'ap' - + local scanList,msg = wifi.getScanInfo() local knownSsids = wifi.getConfigs() - + if not scanList then return nil, "autowifi: could not scan wifi networks (" .. msg .. ")" end - + log:info("current wifi name/mode: " .. (netName or "") .. "/" .. netMode .. ", ssid of self: " .. apSsid) local visNet, knownNet = {}, {} for _,sn in ipairs(scanList) do @@ -44,12 +44,12 @@ local function setupAutoWifiMode() end log:info("visible networks: " .. table.concat(visNet, ", ")) log:info("known networks: " .. table.concat(knownNet, ", ")) - + -- if the currently active network is client mode and is also visible, do nothing since it will connect automatically further along the boot process if netMode == 'sta' and netName ~= nil and netName ~= "" and findSsidInList(scanList, netName) then return true, "autowifi: no action - existing configuration found for currently wifi visible network (" .. netName .. ")" end - + -- try to find a known network which is also visible (ordered by known network definitions) local connectWith = nil for _,kn in ipairs(knownSsids) do @@ -58,7 +58,7 @@ local function setupAutoWifiMode() break end end - + if connectWith then local rv,msg = netconf.associateSsid(connectWith) if rv then @@ -76,18 +76,18 @@ local function setupAutoWifiMode() else return true, "autowifi: no action - no known networks found, already in access point mode" end - + return nil, "autowifi: uh oh - bad situation in autowifi function" end local function setupLogger() local logStream = io.stderr -- use stderr as hard-coded default target local logLevel = log.LEVEL.debug -- use debug logging as hard-coded default level - + local logTargetSetting = settings.getSystemKey('logfile') local logLevelSetting = settings.getSystemKey('loglevel') local logTargetError, logLevelError = nil, nil - + if type(logTargetSetting) == 'string' then local specialTarget = logTargetSetting:match('^<(.*)>$') if specialTarget then @@ -96,13 +96,13 @@ local function setupLogger() end elseif logTargetSetting:sub(1, 1) == '/' then local f,msg = io.open(logTargetSetting, 'a+') - + if f then logStream = f else logTargetError = msg end end end - + if type(logLevelSetting) == 'string' and logLevelSetting:len() > 0 then local valid = false for idx,lvl in ipairs(log.LEVEL) do @@ -113,59 +113,59 @@ local function setupLogger() end if not valid then logLevelError = true end end - + log:init(logLevel) log:setStream(logStream) - + local rv = true if logTargetError then log:error("could not open logfile '" .. logTargetSetting .. "', using stderr as fallback (" .. logTargetError .. ")") rv = false end - + if logLevelError then log:error("uci config specifies invalid log level '" .. logLevelSetting .. "', using debug level as fallback") rv = false end - + return rv end local function init(environment) setupLogger() - + local dbgText = "" if confDefaults.DEBUG_API and confDefaults.DEBUG_PCALLS then dbgText = "pcall and api" elseif confDefaults.DEBUG_API then dbgText = "api" elseif confDefaults.DEBUG_PCALL then dbgText = "pcall" end - + if dbgText ~= "" then dbgText = " (" .. dbgText .. " debugging enabled)" end - + log:info("Wifibox CGI handler started" .. dbgText) - + if (environment['REQUEST_METHOD'] == 'POST') then local n = tonumber(environment['CONTENT_LENGTH']) postData = io.read(n) end - + local s, msg s, msg = wifi.init() if not s then return s, msg end - + s, msg = netconf.init(wifi, true) if not s then return s, msg end - + return true end local function main(environment) local rq = RequestClass.new(environment, postData, confDefaults.DEBUG_API) - + if rq:getRequestMethod() == 'CMDLINE' and rq:get('autowifi') ~= nil then log:info("running in autowifi mode") local rv,msg = setupAutoWifiMode() - + if rv then log:info("autowifi setup done (" .. msg .. ")") else @@ -180,11 +180,19 @@ end log:info("remote IP/port: " .. rq:getRemoteHost() .. "/" .. rq:getRemotePort()) log:debug("user agent: " .. rq:getUserAgent()) end - + local response, err = rq:handle() - + + + local utils = require('util.utils') + local log = require('util.logger') + log:info("Main (request handled") + log:info(" response.postResponseQueue: "..utils.dump(response.postResponseQueue)) + if err ~= nil then log:error(err) end response:send() + + response:executePostResponseQueue() else log:info("Nothing to do...bye.\n") end @@ -199,15 +207,15 @@ end -- @treturn number A Z+ return value suitable to return from wrapper script. Note that this value is ignored by uhttpd-mod-lua. function handle_request(env) local s, msg = init(env) - + if s == false then local resp = ResponseClass.new() local errSuffix = msg and " (" .. msg .. ")" or "" - + resp:setError("initialization failed" .. errSuffix) resp:send() log:error("initialization failed" .. errSuffix) --NOTE: this assumes the logger has been initialized properly, despite init() having failed - + return 1 else main(env) diff --git a/src/network/netconfig.lua b/src/network/netconfig.lua index 5591a64..df015ff 100644 --- a/src/network/netconfig.lua +++ b/src/network/netconfig.lua @@ -43,7 +43,7 @@ end -- and additionally: wifiiface/add, network/reload function M.switchConfiguration(components) local dirtyList = {} -- laundry list, add config/script name as key with value c (commit), r (reload) or b (both) - + for k,v in pairs(components) do local fname = k .. '_' .. v if type(reconf[fname]) == 'function' then @@ -53,7 +53,7 @@ function M.switchConfiguration(components) log:warn("unknown component or action '" .. fname .. "' skipped") end end - + -- first run all commits, then perform reloads for k,v in pairs(dirtyList) do if v == 'c' or v == 'b' then M.commitComponent(k) end @@ -105,7 +105,7 @@ function reconf.apnet_add(dirtyList, noReload) if s.ssid == ourSsid then sname = s['.name']; return false end end) if sname == nil then sname = uci:add('wireless', 'wifi-iface') end - + M.uciTableSet('wireless', sname, { network = wifi.NET, ssid = ourSsid, @@ -113,7 +113,7 @@ function reconf.apnet_add(dirtyList, noReload) device = 'radio0', mode = 'ap', }) - + commitBit(dirtyList, 'wireless') if noReload == nil or noReload == false then reloadBit(dirtyList, 'network') end end @@ -189,14 +189,14 @@ function reconf.dnsredir_add(dirtyList) local sname = utils.getUciSectionName('dhcp', 'dnsmasq') if sname == nil then return log:error("dhcp config does not contain a dnsmasq section") end if uci:get('dhcp', sname, 'address') ~= nil then return log:debug("DNS address redirection already in place, not re-adding", false) end - + uci:set('dhcp', sname, 'address', {redirText}) commitBit(dirtyList, 'dhcp'); reloadBit(dirtyList, 'dnsmasq') end function reconf.dnsredir_rm(dirtyList) local sname = utils.getUciSectionName('dhcp', 'dnsmasq') if sname == nil then return log:error("dhcp config does not contain a dnsmasq section") end - + uci:delete('dhcp', sname, 'address') commitBit(dirtyList, 'dhcp'); reloadBit(dirtyList, 'dnsmasq') end @@ -254,7 +254,7 @@ function M.setupAccessPoint(ssid) -- NOTE: dnsmasq must be reloaded after network or it will be unable to serve IP addresses M.switchConfiguration{ wifiiface="add", network="reload", staticaddr="add", dhcppool="add_noreload", wwwredir="add", dnsredir="add" } M.switchConfiguration{dhcp="reload"} - + return true end @@ -274,7 +274,7 @@ function M.associateSsid(ssid, passphrase, recreate) break end end - + -- if not, or if newly created configuration is requested, create a new configuration if cfg == nil or recreate ~= nil then local scanResult = wifi.getScanInfo(ssid) @@ -285,18 +285,18 @@ function M.associateSsid(ssid, passphrase, recreate) return nil,"no wireless network with requested SSID is available" end end - + -- try to associate with the network wifi.activateConfig(ssid) --M.switchConfiguration{ wifiiface="add", apnet="rm", staticaddr="rm", dhcppool="rm", wwwredir="rm", dnsredir="rm", wwwcaptive="rm", wireless="reload" } M.switchConfiguration{ wifiiface="add", apnet="rm", staticaddr="rm", dhcppool="rm", wwwredir="rm", dnsredir="rm", wireless="reload" } - + -- check if we are actually associated - local status = wifi.getDeviceState() + local status = wifi.getDeviceState() if not status.ssid or status.ssid ~= ssid then return nil,"could not associate with network (incorrect passphrase?)" end - + return true end diff --git a/src/rest/api/api_network.lua b/src/rest/api/api_network.lua index 0d63a70..132f27b 100644 --- a/src/rest/api/api_network.lua +++ b/src/rest/api/api_network.lua @@ -20,14 +20,14 @@ function M.scan(request, response) local withRaw = utils.toboolean(request:get("with_raw")) local sr = wifi.getScanInfo() local si, se - + if sr and #sr > 0 then response:setSuccess("") local netInfoList = {} for _, se in ipairs(sr) do if noFilter or se.mode ~= "ap" and se.ssid ~= wifi.getSubstitutedSsid(settings.get('network.ap.ssid')) then local netInfo = {} - + netInfo["ssid"] = se.ssid netInfo["bssid"] = se.bssid netInfo["channel"] = se.channel @@ -37,7 +37,7 @@ function M.scan(request, response) netInfo["quality"] = se.quality netInfo["quality_max"] = se.quality_max if withRaw then netInfo["_raw"] = utils.dump(se) end - + table.insert(netInfoList, netInfo) end end @@ -53,7 +53,7 @@ end function M.known(request, response) local noFilter = utils.toboolean(request:get("nofilter")) local withRaw = utils.toboolean(request:get("with_raw")) - + response:setSuccess() local netInfoList = {} for _, net in ipairs(wifi.getConfigs()) do @@ -75,7 +75,7 @@ end function M.status(request, response) local withRaw = utils.toboolean(request:get("with_raw")) local ds = wifi.getDeviceState() - + response:setSuccess() response:addData("ssid", ds.ssid or "") response:addData("bssid", ds.bssid or "") @@ -92,23 +92,43 @@ end --requires ssid(string), accepts phrase(string), recreate(bool) function M.associate_POST(request, response) + local utils = require('util.utils') + local log = require('util.logger') + log:info("API:Network:associate") + local argSsid = request:get("ssid") local argPhrase = request:get("phrase") local argRecreate = request:get("recreate") - + if argSsid == nil or argSsid == "" then response:setError("missing ssid argument") return end - local rv,msg = netconf.associateSsid(argSsid, argPhrase, argRecreate) - - response:addData("ssid", argSsid) + local associate = function() + local rv,msg = netconf.associateSsid(argSsid, argPhrase, argRecreate) + end + --response:addPostResponseFunction(associate) + + local helloA = function() + local log = require('util.logger') + log:info("HELLO A") + end + response:addPostResponseFunction(helloA) + + local helloB = function() + local log = require('util.logger') + log:info("HELLO B") + end + response:addPostResponseFunction(helloB) + + --[[response:addData("ssid", argSsid) if rv then response:setSuccess("wlan associated") else response:setFail(msg) - end + end]]-- + response:setSuccess("wlan is trying to associate") end function M.disassociate_POST(request, response) @@ -121,7 +141,7 @@ end function M.openap_POST(request, response) local ssid = wifi.getSubstitutedSsid(settings.get('network.ap.ssid')) local rv,msg = netconf.setupAccessPoint(ssid) - + response:addData("ssid", ssid) if rv then response:setSuccess("switched to Access Point mode") @@ -134,12 +154,12 @@ end --requires ssid(string) function M.remove_POST(request, response) local argSsid = request:get("ssid") - + if argSsid == nil or argSsid == "" then response:setError("missing ssid argument") return end - + if wifi.removeConfig(argSsid) then response:setSuccess("removed wireless network with requested SSID") response:addData("ssid", argSsid) diff --git a/src/rest/response.lua b/src/rest/response.lua index 0a0f23b..27fbd67 100644 --- a/src/rest/response.lua +++ b/src/rest/response.lua @@ -24,22 +24,25 @@ setmetatable(M, { --requestObject should always be passed (except on init failure, when it is not yet available) function M.new(requestObject) local self = setmetatable({}, M) - self.body = { status = nil, data = {} } self:setHttpStatus(200, 'OK') self:setContentType('text/plain;charset=UTF-8') --self:setContentType('application/json;charset=UTF-8') - + + -- a queue for functions to be executed when the response has bin given + -- needed for api calls like network/associate, which requires a restart of the webserver + self.postResponseQueue = {} + if requestObject ~= nil then local rqId = requestObject:get(REQUEST_ID_ARGUMENT) if rqId ~= nil then self.body[REQUEST_ID_ARGUMENT] = rqId end - + if settings.API_INCLUDE_ENDPOINT_INFO == true then self.body['module'] = requestObject:getRequestedApiModule() self.body['function'] = requestObject:getRealApiFunctionName() or '' end end - + return self end @@ -65,7 +68,7 @@ end function M:setError(msg) self.body.status = 'error' if msg ~= '' then self.body.msg = msg end - + self:addData('more_info', 'http://' .. defaults.API_BASE_URL_PATH .. '/wiki/wiki/communication-api') end @@ -76,6 +79,22 @@ function M:addData(k, v) self.binaryData = nil end +function M:addPostResponseFunction(fn) + local utils = require('util.utils') + local log = require('util.logger') + log:info("Response:addPostResponseFunction: " .. utils.dump(fn)) + table.insert(self.postResponseQueue, fn) + log:info(" self.postResponseQueue: " .. utils.dump(self.postResponseQueue)) +end + +function M:executePostResponseQueue() + local utils = require('util.utils') + local log = require('util.logger') + log:info("Response:executePostResponseQueue: " .. utils.dump(self.postResponseQueue)) + + for i,fn in ipairs(self.postResponseQueue) do fn() end +end + function M:apiURL(mod, func) if not mod then return nil end if func then func = '/' .. func else func = "" end @@ -103,17 +122,17 @@ end function M:setBinaryFileData(rFile, saveName, contentType) if type(rFile) ~= 'string' or rFile:len() == 0 then return false end - + local f,msg = io.open(rFile, "rb") - + if not f then return nil,msg end - + self.binaryData = f:read("*all") f:close() - + self.binarySavename = saveName self:setContentType(contentType) - + return true end