From 109cf803518c0cf5f883ca32e92eb40e9acfc1bf Mon Sep 17 00:00:00 2001 From: Openarl Date: Tue, 17 May 2016 23:46:39 +1000 Subject: [PATCH] Update mechanism mostly done --- Launch.lua | 89 ++++++++++++++++++++++++++++++++--------------- LaunchInstall.lua | 34 ++++++++++++++---- Modules/Main.lua | 14 +++++++- Update.lua | 54 +++++++++++++++++----------- manifest.xml | 12 +++---- 5 files changed, 141 insertions(+), 62 deletions(-) diff --git a/Launch.lua b/Launch.lua index 5e9c81b9..0f3a78da 100644 --- a/Launch.lua +++ b/Launch.lua @@ -9,33 +9,17 @@ SetWindowTitle("PathOfBuilding") ConExecute("set vid_mode 1") ConExecute("set vid_resizable 3") -local opFile = io.open("Update/opFile.txt", "r") -if opFile then - -- Update is pending, apply it - opFile:close() - LoadModule("Update") -end - local launch = { } SetMainObject(launch) -function launch:ApplyUpdate(mode) - if mode == "basic" then - -- Need to revert to the basic environment to apply the update - os.execute("PathOfBuilding Update.lua") - Exit() - elseif mode == "normal" then - -- Update can be applied while normal environment is running - Restart() - end -end - function launch:OnInit() ConPrintf("Loading main script...") local mainFile = io.open("Modules/Main.lua") if mainFile then mainFile:close() else + ConClear() + ConPrintf("Please wait while we complete installation...\n") local updateMode = LoadModule("Update", "CHECK") if not updateMode or updateMode == "none" then Exit("Failed to install.") @@ -56,6 +40,7 @@ function launch:OnInit() self:ShowErrMsg("In 'Init': %s", errMsg) end end + self:CheckForUpdate(true) end function launch:OnExit() @@ -76,20 +61,24 @@ function launch:OnFrame() if self.promptMsg then local r, g, b = unpack(self.promptCol) self:DrawPopup(r, g, b, "^0%s", self.promptMsg) + elseif self.updateChecking then + self:DrawPopup(0, 0.5, 0, "^0%s", self.updateMsg) end - if self.doReload then + if self.doRestart then local screenW, screenH = GetScreenSize() SetDrawColor(0, 0, 0, 0.75) DrawImage(nil, 0, 0, screenW, screenH) SetDrawColor(1, 1, 1) - DrawString(0, screenH/2, "CENTER", 24, "FIXED", "Reloading...") + DrawString(0, screenH/2, "CENTER", 24, "FIXED", "Restarting...") Restart() end end function launch:OnKeyDown(key, doubleClick) if key == "F5" then - self.doReload = true + self.doRestart = true + elseif key == "u" and IsKeyDown("CTRL") then + self:CheckForUpdate() elseif self.promptMsg then local errMsg, ret = PCall(self.promptFunc, key) if errMsg then @@ -97,7 +86,7 @@ function launch:OnKeyDown(key, doubleClick) elseif ret then self.promptMsg = nil end - else + elseif not self.updateChecking then if self.main and self.main.OnKeyDown then local errMsg = PCall(self.main.OnKeyDown, self.main, key, doubleClick) if errMsg then @@ -108,7 +97,7 @@ function launch:OnKeyDown(key, doubleClick) end function launch:OnKeyUp(key) - if not self.promptMsg then + if not self.promptMsg and not self.updateChecking then if self.main and self.main.OnKeyUp then local errMsg = PCall(self.main.OnKeyUp, self.main, key) if errMsg then @@ -126,7 +115,7 @@ function launch:OnChar(key) elseif ret then self.promptMsg = nil end - else + elseif not self.updateChecking then if self.main and self.main.OnChar then local errMsg = PCall(self.main.OnChar, self.main, key) if errMsg then @@ -136,6 +125,52 @@ function launch:OnChar(key) end end +function launch:OnSubCall(func, ...) + if func == "ConPrintf" then + self.updateMsg = string.format(...) + end + if _G[func] then + return _G[func](...) + end +end + +function launch:OnSubFinished(ret) + self.updateAvailable = ret + if not ret then + self:ShowPrompt(1, 0, 0, self.updateMsg .. "\n\nEnter/Escape to dismiss") + elseif self.updateChecking then + if ret == "none" then + self:ShowPrompt(0, 0, 0, "No update available.", function(key) return true end) + else + self:ShowPrompt(0.2, 0.8, 0.2, "An update has been downloaded.\n\nClick 'Apply Update' at the top right when you are ready.", function(key) return true end) + end + self.updateChecking = false + end +end + +function launch:ApplyUpdate(mode) + if mode == "basic" then + -- Need to revert to the basic environment to apply the update + os.execute("start PathOfBuilding Update.lua") + Exit() + elseif mode == "normal" then + -- Update can be applied while normal environment is running + LoadModule("Update") + Restart() + self.doRestart = true -- Will show "Restarting" message if main window is showing + end +end + +function launch:CheckForUpdate(inBackground) + if not IsSubScriptRunning() then + self.updateChecking = not inBackground + self.updateMsg = "" + local update = io.open("Update.lua", "r") + LaunchSubScript(update:read("*a"), "MakeDir", "ConPrintf", "CHECK") + update:close() + end +end + function launch:ShowPrompt(r, g, b, str, func) if self.promptMsg then return @@ -150,11 +185,7 @@ function launch:ShowPrompt(r, g, b, str, func) end function launch:ShowErrMsg(fmt, ...) - self:ShowPrompt(1, 0, 0, "^1Error:\n\n^0" .. string.format(fmt, ...) .. "\n\nEnter/Escape to Dismiss, F5 to reload scripts", function(key) - if key == "RETURN" or key == "ESCAPE" then - return true - end - end) + self:ShowPrompt(1, 0, 0, "^1Error:\n\n^0" .. string.format(fmt, ...) .. "\n\nEnter/Escape to Dismiss, F5 to reload scripts") end function launch:DrawPopup(r, g, b, fmt, ...) diff --git a/LaunchInstall.lua b/LaunchInstall.lua index 301a2522..94e8596f 100644 --- a/LaunchInstall.lua +++ b/LaunchInstall.lua @@ -5,18 +5,40 @@ -- Installation bootstrap -- -local basicFiles = { - ["Launch.lua"] = "https://raw.githubusercontent.com/Openarl/PathOfBuilding/master/Launch.lua", - ["Update.lua"] = "https://raw.githubusercontent.com/Openarl/PathOfBuilding/master/Update.lua", -} +local basicFiles = { "Launch.lua", "Update.lua" } + +local xml = require("xml") local curl = require("lcurl") -for name, url in pairs(basicFiles) do + +local localSource +local localManXML = xml.LoadXMLFile("manifest.xml") +if localManXML and localManXML[1].elem == "PoBVersion" then + for _, node in ipairs(localManXML[1]) do + if type(node) == "table" then + if node.elem == "Source" then + if node.attrib.part == "program" then + localSource = node.attrib.url + end + end + end + end +end +if not localSource then + Exit("Install failed. (Missing or invalid manifest)") + return +end +for _, name in pairs(basicFiles) do local outFile = io.open(name, "wb") local easy = curl.easy() - easy:setopt_url(url) + easy:setopt_url(localSource..name) easy:setopt_writefunction(outFile) easy:perform() + local size = easy:getinfo(curl.INFO_SIZE_DOWNLOAD) easy:close() outFile:close() + if size == 0 then + Exit("Install failed. (Couldn't download program files)") + return + end end Restart() \ No newline at end of file diff --git a/Modules/Main.lua b/Modules/Main.lua index b561dbf1..c08e62b7 100644 --- a/Modules/Main.lua +++ b/Modules/Main.lua @@ -32,6 +32,11 @@ function main:Init() self.tree = common.New("PassiveTree") + self.controls = { } + self.controls.applyUpdate = common.New("ButtonControl", 0, 4, 100, 20, "^x50E050Apply Update", function() + launch:ApplyUpdate(launch.updateAvailable) + end) + self.inputEvents = { } self.tooltipLines = { } @@ -59,10 +64,17 @@ function main:OnFrame() self.modeArgs = self.newModeArgs self.newMode = nil self:CallMode("Init", unpack(self.modeArgs)) - end + end + + self.controls.applyUpdate.x = self.screenW - 104 + self.controls.applyUpdate.hidden = not launch.updateAvailable or launch.updateAvailable == "none" + + common.controlsInput(self, self.inputEvents) self:CallMode("OnFrame", self.inputEvents) + common.controlsDraw(self) + wipeTable(self.inputEvents) end diff --git a/Update.lua b/Update.lua index d5f9cc15..31d8f156 100644 --- a/Update.lua +++ b/Update.lua @@ -12,16 +12,34 @@ local function downloadFile(curl, url, outName) easy:setopt_url(url) easy:setopt_writefunction(outFile) easy:perform() - local code = easy:getinfo(curl.INFO_RESPONSE_CODE) + local size = easy:getinfo(curl.INFO_SIZE_DOWNLOAD) easy:close() outFile:close() - if code ~= 200 then - ConPrintf("Download failed (code %d)", code) + if size == 0 then + ConPrintf("Download failed") os.remove(outName) return true end end +local function downloadFileText(curl, url) + local text = "" + local easy = curl.easy() + easy:setopt_url(url) + easy:setopt_writefunction(function(data) + text = text..data + return true + end) + easy:perform() + local size = easy:getinfo(curl.INFO_SIZE_DOWNLOAD) + easy:close() + if size == 0 then + ConPrintf("Download failed") + return nil + end + return text +end + if mode == "CHECK" then ConPrintf("Checking for update...") @@ -53,23 +71,19 @@ if mode == "CHECK" then end end if not localVer or not localSource or not next(localFiles) then - ConPrintf("Update failed: invalid local manifest") + ConPrintf("Update check failed: invalid local manifest") return end -- Download and process remote manifest local remoteVer local remoteFiles = { } - local remoteManText = "" local remoteSources = { } - local easy = curl.easy() - easy:setopt_url(localSource.."manifest.xml") - easy:setopt_writefunction(function(data) - remoteManText = remoteManText..data - return true - end) - easy:perform() - easy:close() + local remoteManText = downloadFileText(curl, localSource.."manifest.xml") + if not remoteManText then + ConPrintf("Update check failed: couldn't download version manifest") + return + end local remoteManXML = xml.ParseXML(remoteManText) if remoteManXML and remoteManXML[1].elem == "PoBVersion" then for _, node in ipairs(remoteManXML[1]) do @@ -90,7 +104,7 @@ if mode == "CHECK" then end end if not remoteVer or not next(remoteSources) or not next(remoteFiles) then - ConPrintf("Update failed: invalid remote manifest") + ConPrintf("Update check failed: invalid remote manifest") return end @@ -154,7 +168,7 @@ if mode == "CHECK" then local file = io.open(fileName, "wb") file:write(zippedFile:Read("*a")) file:close() - zippedFile:close() + zippedFile:Close() else ConPrintf("Couldn't extract '%s' from '%s' (extract failed)", data.name, zipName) failedFile = true @@ -175,10 +189,10 @@ if mode == "CHECK" then end for name, zip in pairs(zipFiles) do zip:Close() - os.remove(name) + os.remove("Update/"..name) end if failedFile then - ConPrintf("Update failed: failed to get all required files") + ConPrintf("Update failed: one or more files couldn't be downloaded") return end @@ -229,6 +243,7 @@ if mode == "CHECK" then opFile:write(table.concat(ops, "\n")) opFile:close() + ConPrintf("Update is ready.") return coreUpdate and "basic" or "normal" end @@ -239,7 +254,7 @@ if not opFile then end local launch = false for line in opFile:lines() do - local op, args = line:match("(%a+) ?(.+)") + local op, args = line:match("(%a+) ?(.*)") if op == "wait" then local name = args:match('"(.*)"') local file @@ -268,6 +283,5 @@ end opFile:close() os.remove("Update/opFile.txt") if launch then - os.execute("PathOfBuilding") + os.execute("start PathOfBuilding") end - diff --git a/manifest.xml b/manifest.xml index 0aac7239..65939dc4 100644 --- a/manifest.xml +++ b/manifest.xml @@ -2,9 +2,9 @@ - - - + + + @@ -22,7 +22,7 @@ - + @@ -49,10 +49,10 @@ - + - +