-- startup.lua for Inventory Client computer -- Auto-updates from git then launches inventoryClient + dropperController in parallel local REPO_RAW = "https://git.spatulaa.com/MayaTheShy/Inventory-Manager-CC/raw/branch/main" -- Persistent config directory (survives Opus package updates) local PERSIST_DIR = "usr/config/inventory-manager" if not fs.isDir(PERSIST_DIR) then fs.makeDir(PERSIST_DIR) end local SETUP_FILE = fs.combine(PERSIST_DIR, ".client_setup") local DROPPER_CONFIG = fs.combine(PERSIST_DIR, ".dropper_config") -- Files to download (destination -> repo path) local FILES = { ["inventoryClient.lua"] = "inventoryClient.lua", ["dropperController.lua"] = "dropperController.lua", ["lib/log.lua"] = "lib/log.lua", ["lib/ui.lua"] = "lib/ui.lua", } ------------------------------------------------- local function ensureDir(filePath) local dir = filePath:match("^(.+)/") if dir and not fs.isDir(dir) then fs.makeDir(dir) end end local function download(remotePath, localPath) local url = REPO_RAW .. "/" .. remotePath local response = http.get(url) if response then ensureDir(localPath) local f = fs.open(localPath, "w") f.write(response.readAll()) f.close() response.close() return true end return false end ------------------------------------------------- term.clear() term.setCursorPos(1, 1) print("==================================") print(" Inventory Client - Startup") print(" Computer ID: " .. os.getComputerID()) print("==================================") print("") -- Update files local updated, failed = 0, 0 for localPath, remotePath in pairs(FILES) do write(" " .. localPath .. " ... ") if download(remotePath, localPath) then print("OK") updated = updated + 1 else print("FAIL") failed = failed + 1 end end print("") if failed > 0 then print(string.format("Updated %d files, %d failed.", updated, failed)) print("Continuing with existing files...") else print(string.format("All %d files up to date.", updated)) end ------------------------------------------------- -- First-run setup ------------------------------------------------- local VALID_SIDES = { "top", "bottom", "left", "right", "front", "back" } local function isValidSide(s) for _, v in ipairs(VALID_SIDES) do if v == s then return true end end return false end local function firstRunSetup() if fs.exists(SETUP_FILE) then return end print("") print("========== First-Run Setup ==========") print("") write("Is there a dropper next to this computer? (y/n): ") local answer = read():lower():sub(1, 1) if answer == "y" then -- Ask which side the dropper is on local side while true do print("") print("Valid sides: top, bottom, left, right, front, back") write("Which side is the dropper on? ") side = read():lower():gsub("%s+", "") if isValidSide(side) then break end print("Invalid side. Please try again.") end -- Ask which side to pulse redstone from (defaults to same side) print("") write("Redstone output side [" .. side .. "]: ") local rsSide = read():lower():gsub("%s+", "") if rsSide == "" then rsSide = side end if not isValidSide(rsSide) then print("Invalid side, defaulting to " .. side) rsSide = side end -- Save dropper config local cfg = textutils.serialiseJSON({ dropperSide = side, redstoneSide = rsSide, enabled = true, }) local f = fs.open(DROPPER_CONFIG, "w") f.write(cfg) f.close() print("") print("Dropper configured: peripheral=" .. side .. ", redstone=" .. rsSide) else -- No dropper - save config with enabled=false local f = fs.open(DROPPER_CONFIG, "w") f.write(textutils.serialiseJSON({ enabled = false })) f.close() print("No dropper configured.") end -- Mark setup as complete local f = fs.open(SETUP_FILE, "w") f.write("done") f.close() print("") print("Setup complete!") print("(Delete " .. SETUP_FILE .. " to re-run setup)") sleep(2) end firstRunSetup() ------------------------------------------------- -- Determine if dropper controller should run ------------------------------------------------- local dropperEnabled = false if fs.exists(DROPPER_CONFIG) then local f = fs.open(DROPPER_CONFIG, "r") local ok, cfg = pcall(textutils.unserialiseJSON, f.readAll()) f.close() if ok and cfg and cfg.enabled then dropperEnabled = true end end print("") if dropperEnabled then print("Starting inventoryClient + dropperController...") else print("Starting inventoryClient (no dropper)...") end sleep(1) -- Reboot listener: reboots this computer on remote command local SYSTEM_CHANNEL = 4205 local ROLE = "client" local function rebootListener() local m = peripheral.find("modem") if not m then return end m.open(SYSTEM_CHANNEL) while true do local _, _, channel, _, message = os.pullEvent("modem_message") if channel == SYSTEM_CHANNEL and type(message) == "table" and message.type == "reboot" then local target = message.target or "all" if target == "all" or target == ROLE or target == tostring(os.getComputerID()) then print("[SYSTEM] Reboot command received. Rebooting...") sleep(0.5) os.reboot() end end end end local tasks = { function() shell.run("inventoryClient.lua") end, rebootListener, } if dropperEnabled then table.insert(tasks, function() shell.run("dropperController.lua") end) end parallel.waitForAny(table.unpack(tasks))