Files
Inventory-Manager-CC/startup/client.lua
MayaTheShy 173a0a9f95 Persist config files across Opus package updates
The Opus package manager deletes the entire package directory on
update (fs.delete(packageDir)) before re-downloading files. This
wiped all config files (.manager_config, .client_config, etc.) that
were stored inside packages/inventory-manager/.

Fix: add _configPath() helper to every program that resolves config
file paths to usr/config/inventory-manager/ when running under Opus,
which lives outside the package directory and survives updates.
Falls back to the local _path() for standalone (non-Opus) use.

Updated files:
- inventoryManager.lua, manager/config.lua, inventoryClient.lua,
  inventoryWebBridge.lua, dropperController.lua, craftingTurtle.lua
- .package install script: saves configs to usr/config/inventory-manager/
- autorun/startup.lua: checks both persistent and package dirs
- startup/client.lua: uses persistent dir for .client_setup/.dropper_config
- web/server/Dockerfile: switch health check to wget (from prior fix)
2026-03-22 20:51:31 -04:00

204 lines
5.9 KiB
Lua

-- 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))