From 48b9a4a8e11670e09535b71c1c097134c6a553ab Mon Sep 17 00:00:00 2001 From: Wouter R Date: Fri, 8 Nov 2013 18:54:57 +0100 Subject: [PATCH] Documentation. Untrack TODO.md. --- TODO.md | 180 ----------------------------------------- src/cmdmain.lua | 2 + src/main.lua | 24 +++++- src/network/signin.lua | 30 +++---- src/util/utils.lua | 43 ++++++++-- 5 files changed, 78 insertions(+), 201 deletions(-) delete mode 100644 TODO.md diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 5ceea42..0000000 --- a/TODO.md +++ /dev/null @@ -1,180 +0,0 @@ -## te doen voor werkend prototype (beta testers) -- (testen) server logging -- (testen/verder implementeren) stopknop -- volgorde chunks (en vaker voorkomen?): elke chunk naar los bestand en op het laatst samenvoegen -- (client) autopreheat wanneer er een printer aanwezig is -- (fw) temp gcode pad veranderen naar device-specifiek (i.e. /tmp/UltiFi/ttyACM?/combined.gc) -- (fw) bij (her)initialisatie printer altijd alle state weggooien (i.e. /dev/UtliFi/ttyACM?) -- client feedback - * voor ontwikkeling: debugoverlay - * vaker op 'print' drukken moet niet kunnen (knop disablen en op basis van polling (isPrinting?) status up-to-date houden) - -> maar! de firmware moet geen nieuwe printopdrachten accepteren wanneer er al een print bezig is - * temperatuurindicatie (alleen wanneer temperatuuruitlezing via api mogelijk is) -> dus ook indicatie van draaiende printserver -- (misschien?) verticale shape aanpassen -- preheaten voor het starten van een print - * (fw) wachten op targettemperatuur - 20 graden (hoe om te gaan met afkoelen?) - * (client) in config bij temperatuurinstelling: opmerking dat de printer gaat printen vanaf lagere temperatuur (bv. -20) - -## te den voor final release -- start/end-codes configureerbaar maken (via los endpoint) (duplicate) -- printerlijst opvragen - * data: per printer: {id, path, type} -- gcode: printer busy rapporteren vanaf moment dat gcode wordt verzameld, niet pas bij begin printen (of gcode verzamelen per remote host?) -- op wiki over openwrt/osx svn checkout veranderen naar git clone -- image met alles erin - * in postinst op kastje: ook wifibox start doen (enable doet dat niet) (ook voor ultifi) - * firewall net wordt nog niet aangemaakt in 'Y'-mode -- nadenken over loggen (procedure voor testers hoe ze problemen kunnen rapporteren zodat wij ze kunnen reproduceren) - * verzamelen+zippen van logread output (of uci system.@system[0].log_file?) + /tmp/wifibox.conf + printserver log -- na /network/disassociate is wifi uitgeschakeld -> kan geen macadres opvragen -> openap bv. 2x nodig om weer goed macadres te vinden -- client: netwerkkeuze toevoegen? -- herstart van uhttpd en reboot uitstellen tot na sturen van response (closure queue in response.lua) -- consistentie REST API -- code documenteren -- codedocs uitwerken naar apidocs -- optie voor loggen toevoegen aan printmanager -- AP en client tegelijk (VAP / multi-ssid?) - * toegang altijd via AP, clientmode alleen voor updaten en internet ook via kastje (dan moet wel de portalmodus uit) - * dns forward: list 'dhcp_option' '6,10.0.0.1,192.168.178.1' () -- auto-update (zowel package als geheel image; <- kijken hoe luci dat doet) -- serieel: - * 115k2? -> Peter zei iets over instabiele connectie op 250k? - * fallback lijkt niet te werken (zelfde probleem als bij poort opnieuw openen?) - * mss helpt arduino reset triggeren om port opnieuw te kunnen openen? - * 3e manier baudrate zetten? -- initscript testen (lijkt vaker dan eens te worden uitgevoerd) -- printerExists: ook nagaan of basispad ultifi bestaat? - - -## OOK MEE BEZIG -- in AP mode, things like 'somewhere.org/asdsfd' still results in 'Not found' -- behalve /dev/ttyACM* kan het voor FTDI dus ook /dev/ttyUSB* zijn -- config API: anders inrichten (misschien toch 1 key per keer instellen zodat response 'fail' kan zijn?) - -- auto-update - - source-url in Makefile aanpassen (type aanpassen naar git en dan direct naar github repo) - - toevoegen aan /etc/opkg.conf via files in image: `src/gz wifibox http://doodle3d.com/static/wifibox-packages` - - of lokaal: `src/gz wifibox file:///tmp/wifibox-packages` - - (info) feed update-script: /extra/create-packages-dir.sh - uitvoeren vanuit pad waar wifibox_packages terecht moet komen (bv. ~/Sites) - - (info) package-url: - - (info) image-url: - - later: printerprofielen - - - API: - api/info/currentVersion - api/info/latestVersion [beta=true] - api/system/update - api/system/flash - * wat als wij een verkeerd package releasen waardoor de API niet meer werkt? - - - (ref) - - (ref) - - (ref) -- waar moeten debugvlaggen etc naartoe? (run_flags.lua?) -- in package postinst: hostname van kastje instellen op wifibox (met mac?) - -- tijdens openwrt make: - '* satisfy_dependencies_for: Cannot satisfy the following dependencies for kmod-ath9k-common: - '* kmod-crypto-hash * -- wiki bijwerken (links, structuur, API) -- ook in wiki, luadoc installeren: - * !! (beter vervangen door?) - * ongeveer volgens , maar! : - * luasocket apart installeren met `sudo luarocks install https://raw.github.com/diegonehab/luasocket/master/luasocket-scm-0.rockspec` -- Code documenteren -- Lua programmeerstijl? (enkele quotes gebruiken behalve voor i18n) -- zoals het nu werkt wordt het lastig om een hiërarchische api te ondersteunen zoals dit: -- uhttpd ondersteunt geen PUT en DELETE, wel status codes. Beschrijving CGI-antwoorden: -- voor captive portal: cgi 'Location' header voor redirect naar goede url? - -- http statuscodes ; met relevante link in antwoord (meer: ) -- proposed status handling in response.lua: - fucntion setStatus(code, ) -> sets http status+dfl msg and optional errmsg in data - -# TODO (new functionality) - - fix init script handling as described here: http://wiki.openwrt.org/doc/devel/packages#packaging.a.service - - implement (automated) test code where possible - * in 'test' dir next to 'src', with API tests under 'test/www/' - * www tests check functionality of the test module - * www tests also provide an interface to run arbitrary get/post requests - * test path splitting as well - - 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 - - define a list of REST error codes to be more descriptive for clients (e.g. errortype=system/missing-arg/generic) - - steps to take regarding versioning/updating - * versioning scheme - * create feed location (e.g. www.doodle3d.com/firmware/packages) (see here: http://wiki.openwrt.org/doc/packages#third.party.packages) - * create opkg (already present in bin/ar71xx/packages as .ipk file) - * create listing info for package list (checksum, size, etc. ...is this inside the .ipk file?) - * find a way to add the feed url to opkg.conf (directly in files during image building?) - * determine how opkg decides what is 'upgradeable' - * at this point manual updating should be possible, now find out how to implement in lua (execve? or write a minimalistic binding to libopkg?) - * expose through info API and/or system API; also provide a way (future) to flash a new image - - generally, for configuration keys, it could be a good idea to use the concept of default values so it's always possible to return to a 'sane default config' - * use a uci wifibox config to store configuration and a uci wifibox-defaults config as fallback-lookup (which contains a complete default configuration) - * specify min/max/type/regex for each config key in separate lua file - * perhaps defaults should be specified together with min/max/type/regex - - dynamic AP name based on partial MAC (present in default config so it can be overridden and reverted again) - - require api functions which change state to be invoked as post request - * can this be modelled like java annotations or c function attributes? - * otherwise maybe pair each function with _attribs = {…}? - - add API functions to test network connectivity in steps (any chance(e.g. ~ap)? ifup? hasip? resolve? ping?) to network or test - - handling requests which need a restart of uhttpd (e.g. network/openap) will probably respond with some kind of 'please check back in a few seconds' response - - 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)} - - - -# Ideas / issues to work out - - add system api module? for check-updates/do-update/etc - - licensing (also for hardware and firmware) + credits for external code and used ideas () - - (this is an old todo item from network:available(), might still be relevant at some point) - extend netconf interface to support function arguments (as tables) so wifihelper functionality can be integrated - but how? idea: pass x_args={arg1="a",arg2="2342"} for component 'x' - or: allow alternative for x="y" --> x={action="y", arg1="a", arg2="2342"} - in any case, arguments should be put in a new table to pass to the function (since order is undefined it must be an assoc array) - - perhaps opkg+safeboot could be useful in the update mechanism? - - add config option to compile sources using luac _or_ add an option to minify the lua code - - -# Bugs - - (captive portal mode) https is not redirected - - (captive portal mode) .local domains are not redirected - - (captive portal mode) any urls with text after the root domain are not redirected - - using iwinfo with interface name 'radio0' yields very little 'info' output while wlan0 works fine. - However, sometimes wlan0 disappears (happened after trying to associate with non-existing network)...why? - - protect dump function against reference loops (see , json also handles this well) - - relocatabilty of package (take root prefix into consideration everywhere) - - disabling all wireless networks breaks the current method of obtaining the mac address, thus openap must be called twice before it is properly set up - - -# Logos - -Check for inspiration. - - - D o o d l e 3 D - -------- ____ .--- v 1.0.1 - | | | | __ | __|.--.| ._| .---..-.-. - | | | ||--|| _| |--|| . || . |\ / - |________||__||__| |__||____||___|/_._\ - - - D o o d l e 3 D - -------- ____ .---- v 1.0.1 - | | | |--.| __|-.| ._|---.-.-. - | | | |--|| _|--|| . | . |_ _/ - |________|__||__||__||____|___|_._\ - - - ....D o o d l e 3 D - ...________ _____ _____ v 1.0.1 - ../ / / |__ / __/ / - /___ __ - ./ ' ' /--// _|-// - | . /v / - /________/__//__/__//____/___/_^_\ diff --git a/src/cmdmain.lua b/src/cmdmain.lua index bd65b84..eaa73e5 100644 --- a/src/cmdmain.lua +++ b/src/cmdmain.lua @@ -8,6 +8,8 @@ local main = require('main') -- The table is created using shell environment variables leaving out only 'DOCUMENT\_ROOT', -- 'SCRIPT\_PATH' and the regular shell variables (e.g., IFS, HOME and PS1). -- +-- See [information on CGI environment variables](http://techpubs.sgi.com/library/dynaweb_docs/0530/SGI_Developer/books/NetscapeSrv_PG/sgi_html/ch01.html). +-- -- Fields present in the 'real' env table but not in this one are: 'HTTP\_VERSION' -- and another table 'headers' which is mostly mirrored by the 'HTTP\_*' fields. -- Note that the 'headers' table may contain extra fields (e.g., 'cache-control'). diff --git a/src/main.lua b/src/main.lua index 31a4238..ce2a413 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,5 +1,8 @@ --- --- Entry code of the REST API. This sets up the environment, processes a REST request and responds appropiately. +-- Entry code of the REST API and secondary functionality. +-- Primarily, this sets up the environment, processes a REST request and responds appropiately. +-- Secondary functions are to auto-switch between access point and client (@{setupAutoWifiMode}) +-- and to signin to [connect.doodle3d.com](http://connect.doodle3d.com/) (@{network.signin}). package.path = package.path .. ';/usr/share/lua/wifibox/?.lua' local confDefaults = require('conf_defaults') @@ -15,6 +18,11 @@ local Signin = require('network.signin') local postData = nil +--- Switches to wifi client mode or to access point mode based on availability of known wifi networks. +-- +-- If the configuration has actively been set to access point mode, that will always be selected. +-- If not, it will be attempted to connect to a known network (in order of recency) and only if +-- that fails, access point mode will be selected as fall-back. local function setupAutoWifiMode() -- expects list with tables containing 'ssid' key as values and returns index key if found or nil if not found local function findSsidInList(list, name) @@ -84,6 +92,11 @@ local function setupAutoWifiMode() return nil, "autowifi: uh oh - bad situation in autowifi function" end +--- Initializes the logging system to use the file and level defined in the system settings. +-- The settings used are `logfile` and `loglevel`. The former may either be a +-- reular file path, or `` or ``. +-- @see util.settings.getSystemKey +-- @treturn bool True on success, false on error. 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 @@ -135,6 +148,9 @@ local function setupLogger() return rv end +--- Initializes the environment. +-- The logger is set up, any POST data is read and several other subsystems are initialized. +-- @tparam table environment The 'shell' environment containing all CGI variables. Note that @{cmdmain} simulates this. local function init(environment) setupLogger() @@ -162,6 +178,9 @@ local function init(environment) return true end +--- Decides what action to take based on shell/CGI parameters. +-- Either executes a REST request, or calls @{setupAutoWifiMode} or @{network.signin}. +-- @tparam table environment The CGI environment table. local function main(environment) local rq = RequestClass.new(environment, postData, confDefaults.DEBUG_API) @@ -210,7 +229,8 @@ local function main(environment) end ---- Firmware entry point. +--- Firmware entry point. Runs @{init} and calls @{main}. +-- -- This is either used by [uhttp-mod-lua](http://wiki.openwrt.org/doc/uci/uhttpd#embedded.lua) -- directly, or by the d3dapi cgi-bin wrapper script which builds the env table -- from the shell environment. The wrapper script also handles command-line invocation. diff --git a/src/network/signin.lua b/src/network/signin.lua index 77a0ae3..0525d5b 100644 --- a/src/network/signin.lua +++ b/src/network/signin.lua @@ -1,3 +1,5 @@ +--- +-- TODO: document local log = require('util.logger') local utils = require('util.utils') local uci = require('uci').cursor() @@ -15,40 +17,40 @@ local IDLE_STATUS = 1 local SIGNING_IN_STATUS = 2 --- Signin to connect.doodle3d.com server --- +-- function M.signin() - + --log:debug("signin:signin"); - + local code, msg = M.getStatus() --log:debug(" status: "..utils.dump(code).." "..utils.dump(msg)); - + -- if we are already signin in, skip - if(code == SIGNING_IN_STATUS) then + if(code == SIGNING_IN_STATUS) then log:debug(" skipping signin") - return + return end - + M.setStatus(SIGNING_IN_STATUS,"signing in") - + local baseurl = "http://connect.doodle3d.com/api/signin.php" - + local localip = wifi.getLocalIP(); if localip == nil then log:error("signin failed no local ip found") M.setStatus(IDLE_STATUS,"idle") return false end - + local wifiboxid = wifi.getSubstitutedSsid(settings.get('network.cl.wifiboxid')) wifiboxid = urlcode.escape(wifiboxid) - + local cmd = "wget -q -T 2 -t 1 -O - "..baseurl.."?wifiboxid="..wifiboxid.."\\&localip="..localip; local output = utils.captureCommandOutput(cmd); log:info("signin: "..output) - + M.setStatus(IDLE_STATUS,"idle") - + return string.len(output) > 0, output end @@ -61,4 +63,4 @@ function M.setStatus(code,msg) status.set(STATUS_FILE,code,msg); end -return M \ No newline at end of file +return M diff --git a/src/util/utils.lua b/src/util/utils.lua index 92210cf..43c16b6 100644 --- a/src/util/utils.lua +++ b/src/util/utils.lua @@ -1,10 +1,16 @@ --- -- The unavoidable collection of utility functions. --- TODO: use macros/type definitions to document rest modules (to auto-match things like 'M._NAME%')? +-- +-- Functions in this file are accompanied by unit tests, please study those +-- to see how utility functions are expected to behave. local M = {} +--- Splits a string on a given divider character. +-- @string[opt=':'] div The divider character to use. +-- @return An array containing the resultant substrings. +-- @usage local str = "a,b,c"; local parts = str:split(',') function string:split(div) local div, pos, arr = div or ':', 0, {} for st,sp in function() return self:find(div, pos, true) end do @@ -15,6 +21,9 @@ function string:split(div) return arr end +--- Returns the size of an open file handle. +-- @param file File handle to report about. +-- @treturn number Size of the file, determined by seeking to the end. function M.fileSize(file) local current = file:seek() local size = file:seek('end') @@ -22,6 +31,11 @@ function M.fileSize(file) return size end +--- Convert an object to boolean. +-- String values which will yield true are (case insensitive): '1', 't' and 'true'. +-- Boolean true and numbers other than 0 also yield true, everything else yields false. +-- @param s The object to convert. +-- @treturn bool The converted value. function M.toboolean(s) if not s then return false end @@ -32,6 +46,10 @@ function M.toboolean(s) return textTrue or boolTrue or numTrue end +--- Stringifies the given object. +-- Note that self-referencing objects will cause an endless loop with the current implementation. +-- @param o The object to convert. +-- @treturn string Stringified version of o. function M.dump(o) if type(o) == 'table' then local s = '{ ' @@ -58,6 +76,10 @@ function M.getUciSectionName(config, type) return sname end +--- Reports whether or not a file exists. This is done by trying to open it. +-- @tparam string file Filename to report about. +-- @treturn bool|nil True if the file exists, false otherwise or nil on invalid argument. +-- @treturn ?string Descriptive message on error. function M.exists(file) if not file or type(file) ~= 'string' or file:len() == 0 then return nil, "file must be a non-empty string" @@ -68,7 +90,10 @@ function M.exists(file) return r ~= nil end ---creates and returns true if not exists, returns false it does, nil+msg on error +--- Creates a file if it does not exist yet. +-- @string file Path and name of the file to create. +-- @treturn bool|nil True if the file has been created, false if it already existed or nil on error +-- @treturn ?string Descriptive message on error function M.create(file) local r,m = M.exists(file) @@ -85,7 +110,12 @@ function M.create(file) return true end ---FIXME: somehow protect this function from running arbitrary commands +--- Create a symlink on the file system. +-- _Note_ that this function contains a potential security leak as it uses os.execute with given parameters. +-- @string from Source path for the symlink. +-- @string to Target path for the symlink. +-- @return The return value from @{os.execute}, or -1 on invalid parameter(s). +-- @fixme: somehow protect this function from running arbitrary commands function M.symlink(from, to) if from == nil or from == '' or to == nil or to == '' then return -1 end local x = 'ln -s ' .. from .. ' ' .. to @@ -102,12 +132,15 @@ function M.readFile(filePath) return res end --- TODO: this function has been duplicated from rest/api/api_system.lua +--- Runs a command and captures its output using @{io.popen}. +-- @string cmd The command to run. +-- @treturn string Output of the command that was run. +-- @todo: this function has been duplicated from rest/api/api_system.lua function M.captureCommandOutput(cmd) local f = assert(io.popen(cmd, 'r')) local output = assert(f:read('*all')) f:close() - return output; + return output end return M