-- ============================================================ -- startup.lua - Auto-updater pour repo Gitea privé -- ============================================================ -- ============================================================ -- Chargement de la configuration -- ============================================================ local function loadConfig(path) if not fs.exists(path) then error("[Config] Fichier '" .. path .. "' introuvable !") end local config = {} local f = fs.open(path, "r") local line = f.readLine() while line do -- Ignorer les lignes vides et les commentaires (#) if line ~= "" and not line:match("^%s*#") then local key, value = line:match("^([^=]+)=(.+)$") if key and value then config[trim(key)] = trim(value) end end line = f.readLine() end f.close() return config end local function validateConfig(cfg) local required = { "gitea_base", "user", "repo", "branch", "program", "remote_ver", "check_interval" } for _, key in ipairs(required) do if not cfg[key] then error("[Config] Clé manquante dans config.cfg : '" .. key .. "'") end end cfg.check_interval = tonumber(cfg.check_interval) if not cfg.check_interval then error("[Config] 'check_interval' doit être un nombre.") end end -- ============================================================ -- Utilitaires fichiers -- ============================================================ local function readFile(path) if not fs.exists(path) then return nil end local f = fs.open(path, "r") local content = f.readAll() f.close() return content end local function writeFile(path, content) local f = fs.open(path, "w") f.write(content) f.close() end function trim(s) return s:gsub("%s+", "") end -- ============================================================ -- Gestion du token -- ============================================================ local function loadToken(path) local token = readFile(path or ".token") if not token then error("[Updater] Fichier '.token' introuvable !\n" .. "Crée-le avec : echo 'ton_token' > .token") end return trim(token) end -- ============================================================ -- HTTP avec auth Gitea -- ============================================================ local function buildRawUrl(cfg, filepath) return cfg.gitea_base .. "/" .. cfg.user .. "/" .. cfg.repo .. "/raw/branch/" .. cfg.branch .. "/" .. filepath end local function fetchWithToken(url, token) local ok, res = pcall(function() return http.get(url, { ["Authorization"] = "token " .. token, ["Accept"] = "application/json", }) end) if not ok or not res then return nil, "Requête échouée vers : " .. url end local code = res.getResponseCode() if code == 401 then res.close() return nil, "Token invalide ou expiré (401)" elseif code == 404 then res.close() return nil, "Fichier introuvable sur le repo (404)" elseif code ~= 200 then res.close() return nil, "Erreur HTTP " .. code end local content = res.readAll() res.close() return content, nil end -- ============================================================ -- Logique de mise à jour -- ============================================================ local function checkAndUpdate(cfg, token) print("[Updater] Vérification des mises à jour...") local remoteVersion, err = fetchWithToken(buildRawUrl(cfg, cfg.remote_ver), token) if not remoteVersion then print("[Updater] " .. err) return false end remoteVersion = trim(remoteVersion) local localVersion = readFile(".version") if localVersion then localVersion = trim(localVersion) end if remoteVersion == localVersion then print("[Updater] Déjà à jour (v" .. remoteVersion .. ").") return false end local prevVersion = localVersion or "aucune" print("[Updater] Mise à jour : v" .. prevVersion .. " → v" .. remoteVersion) local newProgram, dlErr = fetchWithToken(buildRawUrl(cfg, cfg.program), token) if not newProgram then print("[Updater] Échec du téléchargement : " .. dlErr) return false end writeFile(cfg.program, newProgram) writeFile(".version", remoteVersion) print("[Updater] Mise à jour appliquée (v" .. remoteVersion .. ").") return true end -- ============================================================ -- Programme principal -- ============================================================ local function runProgram(cfg) print("[Updater] Lancement de " .. cfg.program .. "...") shell.run(cfg.program) print("[Updater] Le programme s'est arrêté.") end local function watcherLoop(cfg, token) while true do sleep(cfg.check_interval) local updated = checkAndUpdate(cfg, token) if updated then print("[Updater] Redémarrage dans 2 secondes...") sleep(2) return end end end local function main() print("=== Auto-updater Gitea ===") local cfg = loadConfig("config.cfg") validateConfig(cfg) print("[Config] Configuration chargée.") local token = loadToken(".token") print("[Updater] Token chargé.") checkAndUpdate(cfg, token) if not fs.exists(cfg.program) then print("[Updater] Aucun programme disponible. Abandon.") return end parallel.waitForAny( function() runProgram(cfg) end, function() watcherLoop(cfg, token) end ) print("[Updater] Redémarrage du système...") sleep(1) os.reboot() end main()