Added working installer workflow
This commit is contained in:
parent
d9a4ec31c4
commit
637dee747d
|
@ -2,7 +2,7 @@ package nl.andrewl.railsignalapi.rest.dto.link_token;
|
|||
|
||||
import nl.andrewl.railsignalapi.model.LinkToken;
|
||||
import nl.andrewl.railsignalapi.model.component.Component;
|
||||
import nl.andrewl.railsignalapi.rest.dto.component.out.SimpleComponentResponse;
|
||||
import nl.andrewl.railsignalapi.rest.dto.component.out.ComponentResponse;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
@ -19,7 +19,7 @@ import java.util.List;
|
|||
public record StandaloneLinkTokenResponse (
|
||||
long id,
|
||||
String label,
|
||||
List<SimpleComponentResponse> components,
|
||||
List<ComponentResponse> components,
|
||||
long rsId,
|
||||
String rsName
|
||||
) {
|
||||
|
@ -29,7 +29,7 @@ public record StandaloneLinkTokenResponse (
|
|||
token.getLabel(),
|
||||
token.getComponents().stream()
|
||||
.sorted(Comparator.comparing(Component::getName))
|
||||
.map(SimpleComponentResponse::new).toList(),
|
||||
.map(ComponentResponse::of).toList(),
|
||||
token.getRailSystem().getId(),
|
||||
token.getRailSystem().getName()
|
||||
);
|
||||
|
|
|
@ -59,6 +59,7 @@ public class LinkTokenService {
|
|||
|
||||
@Transactional(readOnly = true)
|
||||
public Optional<LinkToken> validateToken(String rawToken) {
|
||||
if (rawToken.length() < LinkToken.PREFIX_SIZE) return Optional.empty();
|
||||
for (var token : tokenRepository.findAllByTokenPrefix(rawToken.substring(0, LinkToken.PREFIX_SIZE))) {
|
||||
if (passwordEncoder.matches(rawToken, token.getTokenHash())) {
|
||||
return Optional.of(token);
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
-- Rail Signal CC:Tweaked Driver
|
||||
local VERSION = "1.0.0"
|
||||
|
||||
local args = {...}
|
||||
|
||||
-- Global config. Will be loaded at start of script.
|
||||
local config = {}
|
||||
-- Global websocket reference
|
||||
local ws = nil
|
||||
|
||||
local function loadConfig()
|
||||
local configFile = io.open("rs_config.tbl", "r")
|
||||
-- Loads config from a given filename and returns the table with data.
|
||||
local function loadConfig(filename)
|
||||
local configFile = io.open(filename, "r")
|
||||
if not configFile then
|
||||
return nil
|
||||
end
|
||||
|
@ -17,6 +20,7 @@ local function loadConfig()
|
|||
return cfg
|
||||
end
|
||||
|
||||
-- Fetches JSON data from the given endpoint, using the config's API url.
|
||||
local function fetchJson(endpoint)
|
||||
local response, msg, r = http.get({
|
||||
url = config.apiUrl .. endpoint,
|
||||
|
@ -207,9 +211,20 @@ local function initApiData()
|
|||
end
|
||||
|
||||
-- MAIN SCRIPT
|
||||
term.clear()
|
||||
print("Rail Signal Device Driver " .. VERSION .. " for CC:Tweaked computers")
|
||||
print(" By Andrew Lalis <andrewlalisofficial@gmail.com>")
|
||||
config = loadConfig()
|
||||
print("-------------------------------------------------")
|
||||
if #args < 1 then
|
||||
print("Missing required config filename argument.")
|
||||
return
|
||||
end
|
||||
local configFilename = args[1]
|
||||
config = loadConfig(configFilename)
|
||||
if config == nil then
|
||||
print("Error: Could not load config from file.")
|
||||
return
|
||||
end
|
||||
print("Loaded config.")
|
||||
|
||||
if initApiData() then
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
local function tableLength(t)
|
||||
local c = 0
|
||||
for _ in pairs(t) do
|
||||
c = c + 1
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
local function startsWith(str, s)
|
||||
return str:find(s, 1, true) == 1
|
||||
end
|
||||
|
||||
local function readNum(validationFunction)
|
||||
local func = validationFunction or function (n)
|
||||
return n ~= nil, "Please enter a valid number."
|
||||
end
|
||||
local num = nil
|
||||
while true do
|
||||
local s = io.read()
|
||||
if s ~= nil then num = tonumber(s) end
|
||||
local valid, msg = func(num)
|
||||
if valid then return num else print(msg) end
|
||||
end
|
||||
end
|
||||
|
||||
local function readNumInRange(s, e)
|
||||
return readNum(function (n)
|
||||
return n ~= nil and n >= s and n <= e, "Please enter a number between " .. s .. " and " .. e .. "."
|
||||
end)
|
||||
end
|
||||
|
||||
local function readStr(validationFunction)
|
||||
local func = validationFunction or function (s)
|
||||
return s ~= nil and string.len(s) > 0, "Please enter a non-empty string."
|
||||
end
|
||||
while true do
|
||||
local str = io.read()
|
||||
local valid, msg = func(str)
|
||||
if valid then return str else print(msg) end
|
||||
end
|
||||
end
|
||||
|
||||
local function readUrl()
|
||||
return readStr(function (s)
|
||||
return s ~= nil and (startsWith(s, "http://") or startsWith(s, "https://")), "Please enter a valid URL."
|
||||
end)
|
||||
end
|
||||
|
||||
local function choice(options, required)
|
||||
local req = required or false
|
||||
local maxChoices = tableLength(options)
|
||||
for i = 1, maxChoices do
|
||||
local text = options[i].text or options[i]
|
||||
print("[" .. i .. "] " .. text)
|
||||
end
|
||||
|
||||
if not req then
|
||||
maxChoices = maxChoices + 1
|
||||
print("[" .. maxChoices .. "] None")
|
||||
end
|
||||
local c = readNumInRange(1, maxChoices)
|
||||
if not req and c == maxChoices then
|
||||
return nil
|
||||
else
|
||||
local value = options[c].value or options[c]
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
local function chooseBoolean()
|
||||
return choice({"true", "false"}, true) == "true"
|
||||
end
|
||||
|
||||
local function fetchJson(url)
|
||||
local response = http.get(url)
|
||||
if response then
|
||||
local text = response.readAll()
|
||||
response.close()
|
||||
return textutils.unserialiseJSON(text)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function chooseRsSide()
|
||||
return choice({"front", "back", "left", "right", "top", "bottom"}, true)
|
||||
end
|
||||
|
||||
local function choosePeripheral(prefix, blacklist)
|
||||
local ps = peripheral.getNames()
|
||||
local choices = {}
|
||||
for _, name in pairs(ps) do
|
||||
if startsWith(name, prefix) then
|
||||
local isBanned = false
|
||||
for _, bannedName in pairs(blacklist) do
|
||||
if name == bannedName then
|
||||
isBanned = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not isBanned then table.insert(choices, name) end
|
||||
end
|
||||
end
|
||||
if tableLength(choices) < 1 then
|
||||
return nil
|
||||
end
|
||||
return choice(choices, true)
|
||||
end
|
||||
|
||||
local function configSegmentBoundary(data, sb)
|
||||
print("What side is the redstone input for this segment boundary?")
|
||||
data.rsSide = chooseRsSide()
|
||||
print("Select the detector augment that this segment boundary will use.")
|
||||
data.augmentId = choosePeripheral("ir_augment_detector", {})
|
||||
data.segments = {}
|
||||
for _, segment in pairs(sb.segments) do
|
||||
local segmentData = {id = segment.id}
|
||||
print("In what direction would a train travel towards the segment \"" .. segment.name .. "\"?")
|
||||
segmentData.direction = string.upper(choice({"North", "South", "East", "West"}, true))
|
||||
table.insert(data.segments, segmentData)
|
||||
end
|
||||
end
|
||||
|
||||
local function configSignal(data, signal)
|
||||
print("Select the monitor that this signal will use.")
|
||||
local monitorId = choosePeripheral("monitor", {})
|
||||
data.segment = {
|
||||
id = signal.segment.id,
|
||||
monitorId = monitorId
|
||||
}
|
||||
end
|
||||
|
||||
local function configSwitch(data, switch)
|
||||
print("What side is the redstone input/output for this switch?")
|
||||
data.rsSide = chooseRsSide()
|
||||
data.possibleConfigurations = {}
|
||||
for _, cfg in pairs(switch.possibleConfigurations) do
|
||||
local cfgData = {id = cfg.id}
|
||||
local names = {}
|
||||
for _, node in pairs(cfg.nodes) do table.insert(names, node.name) end
|
||||
local routeName = table.concat(names, ", ")
|
||||
print("What is the redstone output to configure the switch to send traffic via " .. routeName)
|
||||
cfgData.rsOutput = chooseBoolean()
|
||||
table.insert(data.possibleConfigurations, cfgData)
|
||||
end
|
||||
end
|
||||
|
||||
-- SCRIPT START
|
||||
|
||||
local config = {}
|
||||
print("Rail Signal Driver Installer for CC:Tweaked")
|
||||
print("-------------------------------------------")
|
||||
print("Please enter the base URL for your Rail System site.")
|
||||
print(" For example: http://localhost:8080")
|
||||
local baseUrl = readUrl()
|
||||
config.apiUrl = baseUrl .. "/api"
|
||||
if startsWith(baseUrl, "https") then
|
||||
config.wsUrl = "wss" .. string.sub(baseUrl, 6) .. "/api/ws/component"
|
||||
else
|
||||
config.wsUrl = "ws" .. string.sub(baseUrl, 5) .. "/api/ws/component"
|
||||
end
|
||||
print("Please enter this device's link token.")
|
||||
config.linkToken = readStr()
|
||||
local tokenData = fetchJson(config.apiUrl .. "/lt/" .. config.linkToken)
|
||||
if tokenData == nil then
|
||||
print("Error: Could not fetch data for this token. Please make sure your token and URL is correct.")
|
||||
return
|
||||
end
|
||||
print("The token you entered is for the \"" .. tokenData.rsName .. "\" rail system, and controls " .. tableLength(tokenData.components) .. " components:")
|
||||
for _, component in pairs(tokenData.components) do
|
||||
print("\t" .. component.name .. "\n\t\tID: " .. component.id .. ", Type: " .. component.type)
|
||||
end
|
||||
print("Are you sure you want to continue?\n[1] Continue\n[2] Exit and try again")
|
||||
local c = readNumInRange(1, 2)
|
||||
if c == 2 then
|
||||
return
|
||||
end
|
||||
|
||||
config.components = {}
|
||||
for _, component in pairs(tokenData.components) do
|
||||
print("Configuring component " .. component.name .. ":")
|
||||
print("-----------------------------------------------")
|
||||
local componentData = {
|
||||
id = component.id,
|
||||
type = component.type
|
||||
}
|
||||
if component.type == "SEGMENT_BOUNDARY" then
|
||||
configSegmentBoundary(componentData, component)
|
||||
elseif component.type == "SIGNAL" then
|
||||
configSignal(componentData, component)
|
||||
elseif component.type == "SWITCH" then
|
||||
configSwitch(componentData, component)
|
||||
end
|
||||
table.insert(config.components, componentData)
|
||||
end
|
||||
|
||||
print("How often should segment boundaries perform train scans? Give an interval between 0.1 and 3 seconds.")
|
||||
config.trainScanInterval = readNumInRange(0.1, 3)
|
||||
|
||||
print("Configuration complete!")
|
||||
local configFile = io.open("__rs_config.tbl", "w")
|
||||
configFile:write(textutils.serialize(config))
|
||||
configFile:close()
|
||||
print("Saved config.")
|
||||
|
||||
print("Downloading driver...")
|
||||
local resp = http.get(baseUrl .. "/driver/cc/driver.lua")
|
||||
local driverScript = resp.readAll()
|
||||
resp.close()
|
||||
local driverFile = io.open("rs_driver.lua", "w")
|
||||
driverFile:write(driverScript)
|
||||
driverFile:close()
|
||||
print("Downloaded driver file.")
|
||||
|
||||
local startupFile = io.open("startup.lua", "w")
|
||||
startupFile:write("shell.execute(\"rs_driver.lua\", \"__rs_config.tbl\")")
|
||||
startupFile:close()
|
||||
print("Created startup file.")
|
||||
|
||||
print("Rebooting to start the device...")
|
||||
os.sleep(1)
|
||||
os.reboot()
|
Loading…
Reference in New Issue