From 8c5c425a4f49643d2963ce524e2db7b155d31a78 Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Wed, 13 Sep 2023 13:49:53 -0400 Subject: [PATCH] Added installer and start of central server --- central_server.lua | 101 +++++++++++++++++++++++++ installer.lua | 180 +++++++++++++++++++++++++++++++++++++++++++++ router.lua | 1 + 3 files changed, 282 insertions(+) create mode 100644 central_server.lua create mode 100644 installer.lua diff --git a/central_server.lua b/central_server.lua new file mode 100644 index 0000000..9027ed9 --- /dev/null +++ b/central_server.lua @@ -0,0 +1,101 @@ +--[[ +A central server to coordinate a rail network. This central server keeps a +graph of the entire network, and handles requests to find paths to route +traffic through. +]]-- + +local RECEIVE_CHANNEL = 45453 + +local modem = peripheral.wrap("top") or error("Missing top modem") +modem.open(RECEIVE_CHANNEL) + +local loadGraph() + local g = nil + local f = io.open("network_graph.tbl", "r") + g = textutils.unserialize(f:read("*a")) + f:close() + --return g + return { + nodes = { + { + id = "Junction-HandieVale", + connections = { + {from = "handievale", to = "N1"}, + {from = "N1", to = "handievale"}, + {from = "handievale", to = "W1"}, + {from = "W1", to = "handievale"}, + {from = "N1", to = "W1"}, + {from = "W1", to = "N1"} + } + }, + { + id = "Junction-Middlecross", + connections = { + {from = "W1", to = "W2"}, + {from = "W2", to = "W1"}, + {from = "N2", to = "S1"}, + {from = "S1", to = "N2"} + } + } + }, + edges = { + { + {id = "handievale", length = 16}, + {id = "N1", length = -1}, + {id = "W1", length = 300}, + {id = "N2", length = 600}, + {id = "E1", length = 75}, + {id = "end", length = 60}, + {id = "W2", length = -1}, + {id = "S1", length = -1} + } + } + } +end + +local findNodeById(graph, nodeId) + for _, node in pairs(graph.nodes) do + if node.id == nodeId then return node end + end + return nil +end + +local findEdgeById(graph, edgeId) + for _, edge in pairs(graph.edges) do + if edge.id == edgeId then return edge end + end + return nil +end + +local findNextEdges(graph, edgeId) + local edges = {} + for _, node in pairs(graph.nodes) do + for _, connection in pairs(node.connections) do + if connection.from == edgeId then + table.insert(edges, findEdgeById(connection.to)) + end + end + end + return edges +end + +local findPath(graph, nodeA, nodeB) + +end + +local handleRequest(graph, replyChannel, msg) + if msg.command == "ROUTE" then + + end +end + +local function handleRequests(graph) + while true do + local event, side, channel, replyChannel, msg, dist = os.pullEvent("modem_message") + if channel == RECEIVE_CHANNEL then + handleRequest(graph, replyChannel, msg) + end + end +end + +handleRequests(loadGraph()) diff --git a/installer.lua b/installer.lua new file mode 100644 index 0000000..d7216b2 --- /dev/null +++ b/installer.lua @@ -0,0 +1,180 @@ +--[[ +A general-purpose installation script that can be run on any cc-rail-router +hardware to set it up for its purpose. +]]-- + +local function clearScreen() + if term.isColor() then + term.setTextColor(colors.white) + term.setBackgroundColor(colors.black) + end + term.clear() + term.setCursorPos(1, 1) +end + +local function promptAnyKey() + print("Press any key to continue.") + os.pullEvent("key") +end + +local function readString(prompt, allowEmpty) + if allowEmpty == nil then allowEmpty = true end + local txt = nil + repeat + clearScreen() + print(prompt) + local x, y = term.getCursorPos() + term.setCursorPos(1, y + 2) + term.setCursorBlink(true) + txt = io.read() + term.setCursorBlink(false) + if not allowEmpty and (not txt or #txt == 0) then + term.setCursorPos(1, y + 4) + print("Empty input not allowed.") + os.sleep(2) + end + until (txt ~= nil and #txt > 0) or allowEmpty + return txt +end + +local function readNumber(prompt, minVal, maxVal, defaultVal) + local num = nil + while num == nil or num < minVal or num > maxVal do + local txt = readString(prompt, defaultVal ~= nil) + if not txt or #txt == 0 then return defaultVal end + num = tonumber(txt) + if num == nil or num < minVal or num > maxVal then + print("Invalid number input. Should be between "..minVal.." and "..maxVal..".") + os.sleep(2) + end + end + return num +end + +local function readChoice(prompt, choices, defaultChoice) + while true do + clearScreen() + print(prompt) + for i, choice in pairs(choices) do + print(i..". "..choice) + end + local x, y = term.getCursorPos() + term.setCursorPos(1, y + 2) + local txt = io.read() + if (not txt or #txt == 0) and defaultChoice ~= nil then + return defaultChoice + end + local txtNum = tonumber(txt) + if txtNum then + if txtNum < 1 or txtNum > #choices then + print("Invalid numeric choice. Should be between 1 and "..#choices..".") + os.sleep(2) + else + return choices[txtNum] + end + else + for i, choice in pairs(choices) do + if choice == txt then + return choice + end + end + print("Invalid choice. Please choose one of the options.") + os.sleep(2) + end + end +end + +local function waitForPeripheralAttach(side) + while true do + local event, s = os.pullEvent("peripheral") + if side == nil or s == side then return s end + end +end + +local function waitForPeripheralDetach(side) + while true do + local event, s = os.pullEvent("peripheral_detach") + if side == nil or s == side then return s end + end +end + +local function waitForModemPresent(side, wireless) + while true do + local modem = peripheral.wrap(side) + if modem == nil then + print("Please attach modem to side "..side..".") + promptAnyKey() + elseif not modem.isWireless or modem.isWireless() ~= wireless then + local name = "modem" + if wireless then name = "wireless " .. name end + print("The peripheral on side "..side.." is not a compatible "..name..". Please detach this peripheral and add the correct one now.") + promptAnyKey() + end + end +end + +local function saveTable(filename, table) + local f = io.open(filename, "w") + f:write(textutils.serialize(table)) + f:close() +end + +local function createStartupScript(program) + local sf = io.open("startup.lua", "w") + sf:write("shell.execute(\""..program.."\")\n") + sf:close() +end + +local function installStation() + clearScreen() + print("Installing station beacon software.") + os.sleep(1) + waitForModemPresent("top", true) + local config = {} + config.name = readString("Enter the station's codename.", false) + config.displayName = readString("Enter the station's display name.", false) + config.range = readNumber("Enter the broadcast range for this station, in blocks.", 4, 64) + clearScreen() + saveTable("station_config.tbl", config) + print("Saved station configuration to station_config.tbl.") + if fs.exists("station.lua") then + print("Deleting existing station.lua.") + fs.delete("station.lua") + end + shell.execute("wget", "https://github.com/andrewlalis/cc-rail-router/raw/main/station.lua", "station.lua") + print("Downloaded station.lua.") + createStartupScript("station.lua") +end + +local function installSwitch() + clearScreen() + print("Installing switch controller software.") + os.sleep(1) + waitForModemPresent("top", true) + +end + +local function installRouter() + clearScreen() + print("Installing handheld router software.") + os.sleep(1) + waitForModemPresent("back", true) + +end + +clearScreen() +print("Rail Software Installation Wizard") +os.sleep(2) +local choice = readChoice( + "What type of software would you like to install?", + {"Station Beacon", "Switch Controller", "Handheld Router", "Exit"} +) +if choice == "Station Beacon" then + installStation() +elseif choice == "Switch Controller" then + installSwitch() +elseif choice == "Handheld Router" then + installRouter() +else + print("Exiting.") +end diff --git a/router.lua b/router.lua index 7b9be03..628c2d1 100644 --- a/router.lua +++ b/router.lua @@ -1,6 +1,7 @@ --[[ This program should be installed on a portable computer with a wireless modem, to act as a routing beacon in conjunction with managed switches. +It also serves as the GUI that users of the system interact with. ]]-- local SWITCH_CHANNEL = 45450 local STATION_BROADCAST_CHANNEL = 45451