-- -- This file is part of the Doodle3D project (http://doodle3d.com). -- -- @copyright 2013, Doodle3D -- @license This software is licensed under the terms of the GNU GPL v2 or later. -- See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details. local wifi = require('network.wlanconfig') local netconf = require('network.netconfig') local settings = require('util.settings') -- NOTE: the updater module 'detects' command-line invocation by existence of 'arg', so we have to make sure it is not defined. argStash = arg arg = nil local updater = require('script.d3d-updater') arg = argStash local log = require('util.logger') local utils = require('util.utils') local accessManager = require('util.access') local printerAPI = require('rest.api.api_printer') local M = { isApi = true } -- TODO: this function is also defined in 2 other places, combine them (and avoid require loops) local function operationsAccessOrFail(request, response) if not accessManager.hasControl(request.remoteAddress) then response:setFail("No control access") return false end local rv, printerState = printerAPI.state(request, response, true) -- NOTE: rv being false means a printer device exists but no server is running for it, so it cannot be 'busy' if rv == false then return true end if printerState == 'buffering' or printerState == 'printing' or printerState == 'stopping' then response:setFail("Printer is busy, please wait") return false end return true end function M.status(request, response) updater.setLogger(log) updater.setUseCache(false) local includeBetas = settings.get('doodle3d.betas') local success,status,msg = updater.getStatus(includeBetas) response:addData('current_version', updater.formatVersion(status.currentVersion)) response:addData('state_code', status.stateCode) response:addData('state_text', status.stateText) if not success then response:setFail(msg) return end local canUpdate = updater.compareVersions(status.newestVersion, status.currentVersion, status.newestReleaseTimestamp, status.currentReleaseTimestamp) > 0 response:addData('newest_version', updater.formatVersion(status.newestVersion)) if status.currentReleaseTimestamp then response:addData('current_release_date', updater.formatDate(status.currentReleaseTimestamp)) end if status.newestReleaseTimestamp then response:addData('newest_release_date', updater.formatDate(status.newestReleaseTimestamp)) end response:addData('can_update', canUpdate) if status.progress then response:addData('progress', status.progress) end if status.imageSize then response:addData('image_size', status.imageSize) end response:setSuccess() end -- accepts: version(string) (major.minor.patch) -- accepts: clear_gcode(bool, defaults to true) (this is to lower the chance on out-of-memory crashes, but still allows overriding this behaviour) -- accepts: clear_images(bool, defaults to true) (same rationale as with clear_gcode) -- note: call this with a long timeout - downloading may take a while (e.g. ~3.3MB with slow internet...) function M.download_POST(request, response) local argVersion = request:get("version") local argClearGcode = utils.toboolean(request:get("clear_gcode")) local argClearImages = utils.toboolean(request:get("clear_images")) if argClearGcode == nil then argClearGcode = true end if argClearImages == nil then argClearImages = true end -- block access to prevent potential issues with printing (e.g. out of memory) if not operationsAccessOrFail(request, response) then return end updater.setLogger(log) updater.setState(updater.STATE.DOWNLOADING,"") local vEnt, rv, msg if not argVersion then local includeBetas = settings.get('doodle3d.betas') local success,status,msg = updater.getStatus(includeBetas) if not success then updater.setState(updater.STATE.DOWNLOAD_FAILED, msg) response:setFail(msg) return else argVersion = updater.formatVersion(status.newestVersion) end end if argClearImages then rv,msg = updater.clear() if not rv then updater.setState(updater.STATE.DOWNLOAD_FAILED, msg) response:setFail(msg) return end end if argClearGcode then response:addData('gcode_clear',true) local rv,msg = printer:clearGcode() if not rv then updater.setState(updater.STATE.DOWNLOAD_FAILED, msg) response:setError(msg) return end end vEnt,msg = updater.findVersion(argVersion) if vEnt == nil then updater.setState(updater.STATE.DOWNLOAD_FAILED, "error searching version index (" .. msg .. ")") response:setFail("error searching version index (" .. msg .. ")") return elseif vEnt == false then updater.setState(updater.STATE.DOWNLOAD_FAILED, "no such version") response:setFail("no such version") return end rv,msg = updater.downloadImageFile(vEnt) if not rv then updater.setState(updater.STATE.DOWNLOAD_FAILED, msg) response:setFail(msg) return end response:setSuccess() end -- if successful, this call won't return since the device will flash its memory and reboot -- accepts: version (string, will try to use most recent if not specified) -- accepts: no_retain (bool, device will be completely cleaned if true (aka '-n' flag to sysupgrade)) function M.install_POST(request, response) local argVersion = request:get("version") local argNoRetain = request:get("no_retain") log:info("API:update/install (noRetain: "..utils.dump(argNoRetain)..")") local noRetain = argNoRetain == 'true' if not operationsAccessOrFail(request, response) then return end updater.setLogger(log) updater.setState(updater.STATE.INSTALLING,"") --local ssid = wifi.getSubstitutedSsid(settings.get('network.ap.ssid')) --local rv,msg = netconf.enableAccessPoint(ssid) if not argVersion then local includeBetas = settings.get('doodle3d.betas') local success,status,msg = updater.getStatus(includeBetas) if not success then updater.setState(updater.STATE.INSTALL_FAILED, msg) response:setFail(msg) return else argVersion = updater.formatVersion(status.newestVersion) end end vEnt,msg = updater.findVersion(argVersion) if vEnt == nil then updater.setState(updater.STATE.INSTALL_FAILED, "error searching version index (" .. msg .. ")") response:setFail("error searching version index (" .. msg .. ")") return elseif vEnt == false then updater.setState(updater.STATE.INSTALL_FAILED, "no such version") response:setFail("no such version") return end local rv,msg = updater.flashImageVersion(vEnt, noRetain) if not rv then updater.setState(updater.STATE.INSTALL_FAILED, "installation failed (" .. msg .. ")") response:setFail("installation failed (" .. msg .. ")") else response:setSuccess() end end function M.clear_POST(request, response) updater.setLogger(log) local rv,msg = updater.clear() if rv then response:setSuccess() else response:setFail(msg) end end return M