|
| 1 | + |
| 2 | +local filesystem = require("filesystem") |
| 3 | +local serialization = require("serialization") |
| 4 | +local component = require("component") |
| 5 | +local thread = require("thread") |
| 6 | +local event = require("event") |
| 7 | +local os = require("os") |
| 8 | +local term = require("term") |
| 9 | + |
| 10 | +local parser = require("nuke_manager.parser") |
| 11 | +local utils = require("nuke_manager.utils") |
| 12 | +local items = require("nuke_manager.items") |
| 13 | +local reactor_manager = require("nuke_manager.reactor_manager") |
| 14 | +local logging = require("nuke_manager.logging") |
| 15 | + |
| 16 | +local nuke_manager = { |
| 17 | + logger = nil, |
| 18 | + settings = {}, |
| 19 | + reactor_config = {}, |
| 20 | + threads = {} |
| 21 | +} |
| 22 | + |
| 23 | +local function load_config() |
| 24 | + if not filesystem.exists("/etc/nuke-manager") then |
| 25 | + filesystem.makeDirectory("/etc/nuke-manager") |
| 26 | + end |
| 27 | + |
| 28 | + if not component.isAvailable("database") then |
| 29 | + print("error: an unrecoverable error has occurred:") |
| 30 | + print("error: a database upgrade is required for this program to work.") |
| 31 | + print("error: install one into an adapter and ensure the adapter is connected to the computer network.") |
| 32 | + error("a database upgrade is required") |
| 33 | + end |
| 34 | + |
| 35 | + nuke_manager.settings = utils.load("/etc/nuke-manager/settings.cfg") or {} |
| 36 | + |
| 37 | + if nuke_manager.settings.code == nil or nuke_manager.settings.code == "" then |
| 38 | + error("reactor planner code is not set: please run config.lua and set it") |
| 39 | + end |
| 40 | + |
| 41 | + local reactors = utils.load("/etc/nuke-manager/reactors.cfg") |
| 42 | + |
| 43 | + if reactors == nil then |
| 44 | + error("/etc/nuke-manager/reactors.cfg has not been initialized: please run config.lua") |
| 45 | + end |
| 46 | + |
| 47 | + nuke_manager.settings.database = nuke_manager.settings.database or component.database.address |
| 48 | + nuke_manager.settings.reactors = reactors |
| 49 | + |
| 50 | + nuke_manager.reactor_config = parser.load_config(nuke_manager.settings.code) |
| 51 | + |
| 52 | + nuke_manager.logger = logging({ |
| 53 | + app_name = "nuke_manager", |
| 54 | + debug = nuke_manager.settings.debug_logs, |
| 55 | + max_level = nuke_manager.settings.max_log_level, |
| 56 | + }) |
| 57 | + |
| 58 | + for _, reactor in pairs(nuke_manager.settings.reactors) do |
| 59 | + local config_error = reactor_manager.validate_config(nuke_manager.reactor_config, reactor) |
| 60 | + |
| 61 | + if config_error ~= nil then |
| 62 | + error(config_error) |
| 63 | + end |
| 64 | + end |
| 65 | + |
| 66 | +end |
| 67 | + |
| 68 | +local function start() |
| 69 | + load_config() |
| 70 | + |
| 71 | + local next_slot = 1 |
| 72 | + |
| 73 | + for _, reactor in pairs(nuke_manager.settings.reactors) do |
| 74 | + local t = reactor_manager.start(nuke_manager.settings, nuke_manager.reactor_config, reactor, next_slot, nuke_manager.logger) |
| 75 | + |
| 76 | + t:detach() |
| 77 | + |
| 78 | + nuke_manager.threads[#nuke_manager.threads + 1] = { |
| 79 | + t = t, |
| 80 | + reactor = reactor |
| 81 | + } |
| 82 | + |
| 83 | + next_slot = next_slot + 1 |
| 84 | + end |
| 85 | +end |
| 86 | + |
| 87 | +local function stop() |
| 88 | + for _, t in pairs(nuke_manager.threads) do |
| 89 | + nuke_manager.logger.info("Stopping reactor " .. t.reactor.reactor_address) |
| 90 | + event.push("reactor_stop", t.reactor.reactor_address) |
| 91 | + end |
| 92 | + |
| 93 | + for _, t in pairs(nuke_manager.threads) do |
| 94 | + nuke_manager.logger.info("Waiting for worker thread to stop for reactor " .. t.reactor.reactor_address) |
| 95 | + t.t:join() |
| 96 | + end |
| 97 | + |
| 98 | + threads = {} |
| 99 | +end |
| 100 | + |
| 101 | +local function run() |
| 102 | + term.clear() |
| 103 | + |
| 104 | + print("Starting nuke_manager in 5 seconds, press Ctrl+C to cancel") |
| 105 | + |
| 106 | + if event.pull(5, "interrupted") then |
| 107 | + nuke_manager.logger.info("Exiting.") |
| 108 | + return |
| 109 | + end |
| 110 | + |
| 111 | + local state = { running = true } |
| 112 | + |
| 113 | + local function interrupt() |
| 114 | + nuke_manager.logger.info("Interrupted") |
| 115 | + state.running = false |
| 116 | + end |
| 117 | + |
| 118 | + event.listen("interrupted", interrupt) |
| 119 | + |
| 120 | + if not state.running then |
| 121 | + return |
| 122 | + end |
| 123 | + |
| 124 | + start() |
| 125 | + |
| 126 | + while state.running do |
| 127 | + if nuke_manager.settings.coolant_interface then |
| 128 | + local iface |
| 129 | + |
| 130 | + if nuke_manager.settings.coolant_interface == "any" then |
| 131 | + if component.isAvailable("me_interface") then |
| 132 | + iface = component.me_interface |
| 133 | + end |
| 134 | + else |
| 135 | + iface = component.proxy(nuke_manager.settings.coolant_interface) |
| 136 | + end |
| 137 | + |
| 138 | + if iface == nil then |
| 139 | + nuke_manager.logger.warn("Could not find me_interface to check coolant levels") |
| 140 | + event.push("reactor_pause") |
| 141 | + goto continue |
| 142 | + end |
| 143 | + |
| 144 | + local hot_coolant = 0 |
| 145 | + local coolant = 0 |
| 146 | + |
| 147 | + for _, fluid in pairs(iface.getFluidsInNetwork()) do |
| 148 | + if fluid.name == "ic2hotcoolant" then |
| 149 | + hot_coolant = fluid.amount |
| 150 | + elseif fluid.name == "ic2coolant" then |
| 151 | + coolant = fluid.amount |
| 152 | + end |
| 153 | + end |
| 154 | + |
| 155 | + local needs_hot_coolant = nuke_manager.settings.hot_coolant_max == nil or hot_coolant < nuke_manager.settings.hot_coolant_max |
| 156 | + local has_coolant = coolant > (nuke_manager.settings.cool_coolant_min or 0) |
| 157 | + |
| 158 | + if not has_coolant then |
| 159 | + nuke_manager.logger.warn("Not enough coolant: needs " .. utils.format_int(nuke_manager.settings.cool_coolant_min or 0) .. " but has " .. utils.format_int(coolant)) |
| 160 | + end |
| 161 | + |
| 162 | + if has_coolant and needs_hot_coolant then |
| 163 | + event.push("reactor_continue") |
| 164 | + else |
| 165 | + event.push("reactor_pause") |
| 166 | + end |
| 167 | + end |
| 168 | + |
| 169 | + ::continue:: |
| 170 | + |
| 171 | + os.sleep(5) |
| 172 | + end |
| 173 | + |
| 174 | + event.ignore("interrupted", interrupt) |
| 175 | + |
| 176 | + stop() |
| 177 | +end |
| 178 | + |
| 179 | +function catch(fn, logger) |
| 180 | + local success, ret = pcall(fn) |
| 181 | + |
| 182 | + if not success then |
| 183 | + logger.error(tostring(ret)) |
| 184 | + else |
| 185 | + return ret |
| 186 | + end |
| 187 | +end |
| 188 | + |
| 189 | +-- thread.create(function() catch(run, nuke_manager.logger) end):join() |
| 190 | +run() |
0 commit comments