--libAutoUpdater.lua v0.7 ---@class LibAutoUpdaterConfig ---@field repo string ---@field branch string ---@field debug boolean ---@field autorun boolean ---@field doRestart boolean ---@field forceUpdate boolean local config = ... local json = require("main.json") ---@class AutoUpdater local AutoUpdater = { hasFailed = false, currentStep = 0, ---@type string gitHash = nil, ---@type string latestHash = nil, ---@type string artifactId = nil, ---@type string downloadUrl = nil, ---@type boolean isSilent = false, } -- ---@type {[integer]: {text: string, method: function}} -- local steps = { -- [1] = { -- text = "Getting current version...", -- method = function() -- AutoUpdater.getCurrentVersion() -- end, -- }, -- [2] = { -- text = "Getting latest build artifact...", -- method = function() -- AutoUpdater.getArtifactInfo() -- end, -- }, -- [3] = { -- text = "Getting version info...", -- method = function() -- AutoUpdater.getCommitInfo() -- end, -- }, -- [4] = { -- text = "Requesting download URL...", -- method = function() -- AutoUpdater.getDownloadUrl() -- end, -- }, -- [5] = { -- text = "Downloading latest build artifact...", -- method = function() -- AutoUpdater.downloadArtifact() -- end, -- }, -- [6] = { -- text = "Unzipping latest build artifact...", -- method = function() -- AutoUpdater.unzipArtifact() -- end, -- }, -- [7] = { -- text = "Moving files...", -- method = function() -- AutoUpdater.moveFiles() -- end, -- }, -- [8] = { -- text = "Cleaning up...", -- method = function() -- AutoUpdater.cleanup() -- end, -- }, -- } ---@param silent boolean? function AutoUpdater.run(silent) -- AutoUpdater.isSilent = silent or false AutoUpdater.print( "This version of AutoUpdater is no longer maintained! Please use the version bundled with JPXS instead." ) AutoUpdater.print("You can find it here: https://assets.jpxs.io/plugins/jpxs/jpxs.lua") hook.once("JPXSLoaded", function() if table.find(jpxs.config:get("plugins"), "autoupdater") then AutoUpdater.print("AutoUpdater is enabled! Removing this plugin...") for id, plugin in pairs(hook.plugins) do if plugin.name == "AutoUpdater" and plugin.author == "gart" then os.remove("plugins/" .. plugin.fullFileName) AutoUpdater.print("Removed AutoUpdater. Thank you!") end end end end) end -- function AutoUpdater.nextStep() -- if AutoUpdater.hasFailed then -- return -- end -- AutoUpdater.currentStep = AutoUpdater.currentStep + 1 -- if steps[AutoUpdater.currentStep] then -- AutoUpdater.debug(steps[AutoUpdater.currentStep].text) -- steps[AutoUpdater.currentStep].method() -- else -- if config.doRestart then -- AutoUpdater.print("Update complete. Restarting server...") -- os.exit() -- else -- AutoUpdater.print("Update complete.") -- AutoUpdater.print("Please restart the server to apply changes.") -- end -- end -- end -- ---@param reason string -- function AutoUpdater.fail(reason) -- AutoUpdater.print("Update failed: " .. reason) -- AutoUpdater.hasFailed = true -- end function AutoUpdater.print(text) if AutoUpdater.isSilent then return end print("\27[30;1m[" .. os.date("%X") .. "]\27[0m \27[38;5;219m[AutoUpdater]\27[0m " .. text) end -- function AutoUpdater.debug(text) -- if config.debug and not AutoUpdater.isSilent then -- AutoUpdater.print(text) -- end -- end -- ---Searches for a string in a binary file. -- ---@param filePath string The path to the file. -- ---@param value string The string to search for. -- ---@return integer The position of the string in the file, or -1 if not found. -- function AutoUpdater.BinaryStringSearch(filePath, value) -- local f = io.open(filePath, "r") -- if f then -- ---@type string -- local content = f:read("*all") -- f:close() -- local pos = content:find(value, 1, true) -- if pos then -- return pos -- end -- end -- return -1 -- end -- function AutoUpdater.getCurrentVersion() -- local pos = AutoUpdater.BinaryStringSearch("./librosaserver.so", "git version:") -- if pos == -1 then -- AutoUpdater.print("Failed to find git hash, updating...") -- AutoUpdater.nextStep() -- return -- end -- AutoUpdater.debug(string.format("Found git hash at position 0x%X", pos)) -- local f = io.open("./librosaserver.so", "r") -- if f then -- f:seek("set", pos + 12) -- AutoUpdater.gitHash = f:read(40) -- f:close() -- local gitHashShort = AutoUpdater.gitHash:sub(1, 7) -- AutoUpdater.debug("Current version: " .. gitHashShort) -- else -- AutoUpdater.fail("Failed to open librosaserver.so") -- end -- AutoUpdater.nextStep() -- end -- function AutoUpdater.getArtifactInfo() -- http.get("https://api.github.com", "/repos/" .. config.repo .. "/actions/artifacts", { -- ["Accept"] = "application/vnd.github.v3+json", -- }, function(res) -- if res and res.status == 200 then -- local data = json.decode(res.body) -- local latestArtifact = nil -- for _, artifact in pairs(data.artifacts) do -- if artifact.workflow_run.head_branch == config.branch then -- if not latestArtifact or artifact.created_at > latestArtifact.created_at then -- latestArtifact = artifact -- AutoUpdater.debug("Found artifact: " .. artifact.id) -- end -- end -- end -- if latestArtifact then -- local artifactId = latestArtifact.id -- local artifactName = latestArtifact.name -- local artifactSize = latestArtifact.size_in_bytes -- local headSha = latestArtifact.workflow_run.head_sha -- AutoUpdater.debug( -- string.format( -- "Latest artifact: %s - %s (%s)", -- artifactName, -- artifactId, -- AutoUpdater.formatDataSize(artifactSize) -- ) -- ) -- if headSha == AutoUpdater.gitHash or config.forceUpdate then -- AutoUpdater.print("Already up to date.") -- AutoUpdater.hasFailed = true -- return -- end -- AutoUpdater.debug("Latest version: " .. headSha:sub(1, 7)) -- AutoUpdater.latestHash = headSha -- AutoUpdater.artifactId = artifactId -- else -- AutoUpdater.fail("Failed to get latest artifact: No artifacts found") -- end -- else -- AutoUpdater.fail("Failed to get latest artifact: " .. (res and res.status or "500")) -- end -- AutoUpdater.nextStep() -- end) -- end -- function AutoUpdater.getCommitInfo() -- http.get("https://api.github.com", "/repos/" .. config.repo .. "/commits/" .. AutoUpdater.latestHash, { -- ["Accept"] = "application/vnd.github.v3+json", -- }, function(res) -- if res and res.status == 200 then -- local data = json.decode(res.body) -- local latestCommit = data.sha -- local commitInfo = data.commit.committer -- local commitDate = commitInfo.date -- local commitAuthor = commitInfo.name -- local commitMessage = data.commit.message -- if latestCommit ~= AutoUpdater.gitHash and not config.forceUpdate then -- AutoUpdater.latestHash = latestCommit -- AutoUpdater.debug("Latest commit: " .. commitDate .. " by " .. commitAuthor .. " - " .. commitMessage) -- else -- AutoUpdater.print( -- "Already up to date, current commit: " -- .. commitDate -- .. " by " -- .. commitAuthor -- .. " - " -- .. commitMessage -- ) -- AutoUpdater.hasFailed = true -- end -- else -- AutoUpdater.fail("Failed to get latest version: " .. (res and res.status or "500")) -- end -- AutoUpdater.nextStep() -- end) -- end -- function AutoUpdater.getDownloadUrl() -- http.get("https://jpxs.io", "/api/install/artifact/RosaServer/" .. AutoUpdater.artifactId .. "/zip", { -- ["Accept"] = "application/json", -- }, function(res) -- if res and res.status == 200 then -- local data = json.decode(res.body) -- local downloadUrl = data.location -- AutoUpdater.downloadUrl = downloadUrl -- AutoUpdater.debug("Download URL: " .. downloadUrl) -- AutoUpdater.nextStep() -- else -- AutoUpdater.fail("Failed to download artifact: " .. (res and res.status or "500")) -- AutoUpdater.nextStep() -- end -- end) -- end -- function AutoUpdater.downloadArtifact() -- local host = AutoUpdater.downloadUrl:match("(https?://[^/]+)") -- local path = AutoUpdater.downloadUrl:gsub(host, "") -- print("Downloading latest build artifact from: " .. AutoUpdater.downloadUrl) -- http.get(host, path, { -- -- ["Accept"] = "application/zip", -- }, function(res) -- if res and res.status == 200 then -- if os.createDirectory(AutoUpdater.latestHash) then -- AutoUpdater.debug("Created directory for new version.") -- end -- local f = io.open(AutoUpdater.latestHash .. "/update.zip", "w") -- if f then -- f:write(res.body) -- f:close() -- AutoUpdater.print("Download complete.") -- AutoUpdater.nextStep() -- else -- AutoUpdater.fail("Failed to write to file. Please check permissions.") -- end -- else -- AutoUpdater.fail("Failed to download artifact: " .. (res and res.status or "500")) -- print(inspect(res)) -- end -- end) -- end -- function AutoUpdater.unzipArtifact() -- local command = string.format("unzip -o %s/update.zip -d %s", AutoUpdater.latestHash, AutoUpdater.latestHash) -- os.execute(command) -- AutoUpdater.print("Unzipped latest build artifact.") -- AutoUpdater.nextStep() -- end -- function AutoUpdater.moveFiles() -- local baseDir = AutoUpdater.latestHash .. "/" -- os.execute("mv " .. baseDir .. "librosaserver.so ./librosaserver.so") -- os.execute("mv " .. baseDir .. "rosaserversatellite ./rosaserversatellite") -- os.execute("mv " .. baseDir .. "libluajit.so ./libluajit.so") -- AutoUpdater.print("Moved files.") -- AutoUpdater.nextStep() -- end -- function AutoUpdater.cleanup() -- os.execute("rm -rf " .. AutoUpdater.latestHash) -- AutoUpdater.print("Cleaned up.") -- AutoUpdater.nextStep() -- end -- function AutoUpdater.formatDataSize(size) -- local units = { "B", "KB", "MB", "GB", "TB" } -- local unit = 1 -- while size > 1024 do -- size = size / 1024 -- unit = unit + 1 -- end -- return string.format("%.2f %s", size, units[unit]) -- end return AutoUpdater