From c4caf31695d247da5f786709fd3b01d545e953db Mon Sep 17 00:00:00 2001 From: Maxim <74974283+maximka76667@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:56:43 +0100 Subject: [PATCH 01/18] feat: add .gitignore for packet-sender --- packet-sender/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 packet-sender/.gitignore diff --git a/packet-sender/.gitignore b/packet-sender/.gitignore new file mode 100644 index 000000000..6d23150b2 --- /dev/null +++ b/packet-sender/.gitignore @@ -0,0 +1,2 @@ +# Rust target directory +/target/ \ No newline at end of file From 708f32713813ce90732aa0d7c50ed35fca671402 Mon Sep 17 00:00:00 2001 From: Maxim <74974283+maximka76667@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:58:38 +0100 Subject: [PATCH 02/18] feat: add no-sandbox fix for linux --- electron-app/main.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/electron-app/main.js b/electron-app/main.js index ef5841b58..fd7a0a40d 100644 --- a/electron-app/main.js +++ b/electron-app/main.js @@ -15,6 +15,22 @@ import { createWindow } from "./src/windows/mainWindow.js"; const { autoUpdater } = pkg; +// Disable sandbox for Linux +if (process.platform === "linux") { + try { + const userns = fs + .readFileSync("/proc/sys/kernel/unprivileged_userns_clone", "utf8") + .trim(); + if (userns === "0") { + app.commandLine.appendSwitch("no-sandbox"); + } + } catch (e) {} + + if (process.getuid && process.getuid() === 0) { + app.commandLine.appendSwitch("no-sandbox"); + } +} + // Setup IPC handlers for renderer process communication setupIpcHandlers(); From a50bdc2059ccb7e4399260bb9cfd29721e286afe Mon Sep 17 00:00:00 2001 From: Maxim <74974283+maximka76667@users.noreply.github.com> Date: Fri, 20 Feb 2026 08:46:54 +0100 Subject: [PATCH 03/18] feat: some packet-sender tweaks --- backend/cmd/main.go | 2 +- backend/cmd/orchestrator.go | 2 +- backend/cmd/setup_transport.go | 2 +- backend/cmd/setup_vehicle.go | 2 +- backend/internal/pod_data/measurement.go | 2 +- backend/internal/pod_data/pod_data.go | 2 +- backend/{internal => pkg}/adj/adj.go | 0 backend/{internal => pkg}/adj/boards.go | 0 backend/{internal => pkg}/adj/git.go | 0 backend/{internal => pkg}/adj/models.go | 0 electron-app/build.mjs | 106 +++++++++------------ electron-app/src/menu/menu.js | 2 +- electron-app/src/processes/packetSender.js | 16 +++- electron-app/src/utils/paths.js | 7 -- go.work | 1 + packet-sender/.gitignore | 2 - packet-sender/main.go | 14 +-- packet-sender/package.json | 13 +++ 18 files changed, 87 insertions(+), 86 deletions(-) rename backend/{internal => pkg}/adj/adj.go (100%) rename backend/{internal => pkg}/adj/boards.go (100%) rename backend/{internal => pkg}/adj/git.go (100%) rename backend/{internal => pkg}/adj/models.go (100%) delete mode 100644 packet-sender/.gitignore create mode 100644 packet-sender/package.json diff --git a/backend/cmd/main.go b/backend/cmd/main.go index addc5c879..b31a17d63 100644 --- a/backend/cmd/main.go +++ b/backend/cmd/main.go @@ -5,12 +5,12 @@ import ( "os" "os/signal" - adj_module "github.com/HyperloopUPV-H8/h9-backend/internal/adj" "github.com/HyperloopUPV-H8/h9-backend/internal/config" "github.com/HyperloopUPV-H8/h9-backend/internal/flags" "github.com/HyperloopUPV-H8/h9-backend/internal/pod_data" "github.com/HyperloopUPV-H8/h9-backend/internal/update_factory" vehicle_models "github.com/HyperloopUPV-H8/h9-backend/internal/vehicle/models" + adj_module "github.com/HyperloopUPV-H8/h9-backend/pkg/adj" "github.com/HyperloopUPV-H8/h9-backend/pkg/transport" "github.com/HyperloopUPV-H8/h9-backend/pkg/websocket" trace "github.com/rs/zerolog/log" diff --git a/backend/cmd/orchestrator.go b/backend/cmd/orchestrator.go index 180b26c8d..6d34b064a 100644 --- a/backend/cmd/orchestrator.go +++ b/backend/cmd/orchestrator.go @@ -7,11 +7,11 @@ import ( "runtime/pprof" "strings" - adj_module "github.com/HyperloopUPV-H8/h9-backend/internal/adj" "github.com/HyperloopUPV-H8/h9-backend/internal/config" "github.com/HyperloopUPV-H8/h9-backend/internal/flags" "github.com/HyperloopUPV-H8/h9-backend/internal/pod_data" "github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction" + adj_module "github.com/HyperloopUPV-H8/h9-backend/pkg/adj" "github.com/HyperloopUPV-H8/h9-backend/pkg/logger" data_logger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/data" order_logger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/order" diff --git a/backend/cmd/setup_transport.go b/backend/cmd/setup_transport.go index c86f9270e..9c9a5b628 100644 --- a/backend/cmd/setup_transport.go +++ b/backend/cmd/setup_transport.go @@ -7,12 +7,12 @@ import ( "net" "time" - adj_module "github.com/HyperloopUPV-H8/h9-backend/internal/adj" "github.com/HyperloopUPV-H8/h9-backend/internal/common" "github.com/HyperloopUPV-H8/h9-backend/internal/config" "github.com/HyperloopUPV-H8/h9-backend/internal/pod_data" "github.com/HyperloopUPV-H8/h9-backend/internal/utils" "github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction" + adj_module "github.com/HyperloopUPV-H8/h9-backend/pkg/adj" "github.com/HyperloopUPV-H8/h9-backend/pkg/transport" "github.com/HyperloopUPV-H8/h9-backend/pkg/transport/network/tcp" "github.com/HyperloopUPV-H8/h9-backend/pkg/transport/network/udp" diff --git a/backend/cmd/setup_vehicle.go b/backend/cmd/setup_vehicle.go index b8a7b62e0..8fe8999e2 100644 --- a/backend/cmd/setup_vehicle.go +++ b/backend/cmd/setup_vehicle.go @@ -12,12 +12,12 @@ import ( h "github.com/HyperloopUPV-H8/h9-backend/pkg/http" "github.com/HyperloopUPV-H8/h9-backend/pkg/websocket" - adj_module "github.com/HyperloopUPV-H8/h9-backend/internal/adj" "github.com/HyperloopUPV-H8/h9-backend/internal/common" "github.com/HyperloopUPV-H8/h9-backend/internal/config" "github.com/HyperloopUPV-H8/h9-backend/internal/pod_data" "github.com/HyperloopUPV-H8/h9-backend/internal/update_factory" "github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction" + adj_module "github.com/HyperloopUPV-H8/h9-backend/pkg/adj" "github.com/HyperloopUPV-H8/h9-backend/pkg/broker" connection_topic "github.com/HyperloopUPV-H8/h9-backend/pkg/broker/topics/connection" data_topic "github.com/HyperloopUPV-H8/h9-backend/pkg/broker/topics/data" diff --git a/backend/internal/pod_data/measurement.go b/backend/internal/pod_data/measurement.go index 446b88611..b2581c4e3 100644 --- a/backend/internal/pod_data/measurement.go +++ b/backend/internal/pod_data/measurement.go @@ -4,9 +4,9 @@ import ( "fmt" "strings" - "github.com/HyperloopUPV-H8/h9-backend/internal/adj" "github.com/HyperloopUPV-H8/h9-backend/internal/common" "github.com/HyperloopUPV-H8/h9-backend/internal/utils" + "github.com/HyperloopUPV-H8/h9-backend/pkg/adj" ) const EnumType = "enum" diff --git a/backend/internal/pod_data/pod_data.go b/backend/internal/pod_data/pod_data.go index 7cafa1411..3f091aaaa 100644 --- a/backend/internal/pod_data/pod_data.go +++ b/backend/internal/pod_data/pod_data.go @@ -3,8 +3,8 @@ package pod_data import ( "github.com/HyperloopUPV-H8/h9-backend/internal/utils" - "github.com/HyperloopUPV-H8/h9-backend/internal/adj" "github.com/HyperloopUPV-H8/h9-backend/internal/common" + "github.com/HyperloopUPV-H8/h9-backend/pkg/adj" ) func NewPodData(adjBoards map[string]adj.Board, globalUnits map[string]utils.Operations) (PodData, error) { diff --git a/backend/internal/adj/adj.go b/backend/pkg/adj/adj.go similarity index 100% rename from backend/internal/adj/adj.go rename to backend/pkg/adj/adj.go diff --git a/backend/internal/adj/boards.go b/backend/pkg/adj/boards.go similarity index 100% rename from backend/internal/adj/boards.go rename to backend/pkg/adj/boards.go diff --git a/backend/internal/adj/git.go b/backend/pkg/adj/git.go similarity index 100% rename from backend/internal/adj/git.go rename to backend/pkg/adj/git.go diff --git a/backend/internal/adj/models.go b/backend/pkg/adj/models.go similarity index 100% rename from backend/internal/adj/models.go rename to backend/pkg/adj/models.go diff --git a/electron-app/build.mjs b/electron-app/build.mjs index f83964a19..b4dff1753 100644 --- a/electron-app/build.mjs +++ b/electron-app/build.mjs @@ -5,7 +5,7 @@ */ import { execSync } from "child_process"; -import { copyFileSync, cpSync, existsSync, mkdirSync, rmSync } from "fs"; +import { cpSync, existsSync, mkdirSync, rmSync } from "fs"; import { dirname, join } from "path"; import { fileURLToPath } from "url"; import { logger } from "./src/utils/logger.js"; @@ -20,6 +20,7 @@ const CONFIG = { type: "go", path: join(ROOT, "backend"), // Root of backend (where package.json is) output: join(__dirname, "binaries"), + entry: "./cmd", commands: ["pnpm run build:ci"], platforms: [ { @@ -52,18 +53,43 @@ const CONFIG = { }, ], }, - "packet-sender": { - type: "rust", - path: join(ROOT, "packet-sender"), - output: join(__dirname, "binaries"), - commands: ["pnpm run build"], - binaryPath: "target/release/packet-sender", - platforms: [ - { id: "win64", ext: ".exe", tags: ["win", "windows"] }, - { id: "linux64", ext: "", tags: ["linux"] }, - { id: "mac64", ext: "", tags: ["mac", "macos"] }, - ], - }, + // "packet-sender": { + // type: "go", + // path: join(ROOT, "packet-sender"), + // output: join(__dirname, "binaries"), + // entry: ".", + // commands: ["pnpm run build:ci"], + // platforms: [ + // { + // id: "win64", + // goos: "windows", + // goarch: "amd64", + // ext: ".exe", + // tags: ["win", "windows"], + // }, + // { + // id: "linux64", + // goos: "linux", + // goarch: "amd64", + // ext: "", + // tags: ["linux"], + // }, + // { + // id: "mac64", + // goos: "darwin", + // goarch: "amd64", + // ext: "", + // tags: ["mac", "macos"], + // }, + // { + // id: "macArm", + // goos: "darwin", + // goarch: "arm64", + // ext: "", + // tags: ["mac", "macos"], + // }, + // ], + // }, "testing-view": { type: "frontend", path: join(ROOT, "frontend/testing-view"), @@ -98,8 +124,8 @@ const run = (cmd, cwd, env = {}) => { } }; -const buildBackend = (config, requestedPlatforms, extraArgs = "") => { - logger.info("Building Backend (Go)..."); +const buildGo = (name, config, requestedPlatforms, extraArgs = "") => { + logger.info(`Building ${name} (Go)...`); mkdirSync(config.output, { recursive: true }); const targets = config.platforms.filter((p) => { @@ -112,22 +138,15 @@ const buildBackend = (config, requestedPlatforms, extraArgs = "") => { return p.tags.some((tag) => requestedPlatforms.includes(tag)); }); - if (targets.length === 0) { - logger.error( - `No matching platforms found for: ${requestedPlatforms.join(", ")}` - ); - return false; - } - let success = true; for (const p of targets) { - const filename = `backend-${p.goos}-${p.goarch}${p.ext}`; + const filename = `${name}-${p.goos}-${p.goarch}${p.ext}`; logger.step(`Building ${p.goos}/${p.goarch}...`); + const entryPath = config.entry || "."; + for (const cmd of config.commands) { - // cmd is like "pnpm run build:ci --" - // We append the output flag and target directory - const buildCmd = `${cmd} -o "${join(config.output, filename)}" ${extraArgs} ./cmd`; + const buildCmd = `${cmd} -o "${join(config.output, filename)}" ${extraArgs} ${entryPath}`; const result = run(buildCmd, config.path, { GOOS: p.goos, @@ -145,37 +164,6 @@ const buildBackend = (config, requestedPlatforms, extraArgs = "") => { return success; }; -const buildRust = (name, config, requestedPlatforms, extraArgs = "") => { - logger.info(`Building ${name} (Rust)...`); - mkdirSync(config.output, { recursive: true }); - - for (const cmd of config.commands) { - // Only append extra args to build commands - const finalCmd = cmd.includes("build") ? `${cmd} ${extraArgs}` : cmd; - if (!run(finalCmd, config.path)) return false; - } - - const isWin = - process.platform === "win32" || - (requestedPlatforms && requestedPlatforms.includes("win")); - const ext = isWin ? ".exe" : ""; - - // Check for source binary - const sourceBin = join(config.path, config.binaryPath + ext); - const destName = `packet-sender${ext}`; - const destPath = join(config.output, destName); - - logger.step(`Copying binary to ${destPath}...`); - - if (existsSync(sourceBin)) { - copyFileSync(sourceBin, destPath); - return true; - } else { - logger.error(`Rust binary not found at ${sourceBin}`); - return false; - } -}; - const buildFrontend = (name, config, extraArgs = "") => { if (config.optional && !existsSync(join(config.path, "package.json"))) { logger.warning(`Skipping ${name} (not initialized)`); @@ -252,9 +240,7 @@ logger.header("Hyperloop Control Station Build"); let success = true; if (config.type === "go") { - success = buildBackend(config, requestedPlatforms, extraArgs); - } else if (config.type === "rust") { - success = buildRust(key, config, requestedPlatforms, extraArgs); + success = buildGo(key, config, requestedPlatforms, extraArgs); } else if (config.type === "frontend") { success = buildFrontend(key, config, extraArgs); if (success && !config.optional) frontendBuilt = true; diff --git a/electron-app/src/menu/menu.js b/electron-app/src/menu/menu.js index c0436ab79..64f776da9 100644 --- a/electron-app/src/menu/menu.js +++ b/electron-app/src/menu/menu.js @@ -83,7 +83,7 @@ function createMenu(mainWindow) { } const packetSenderProcess = getPacketSenderProcess(); if (!packetSenderProcess || packetSenderProcess.killed) { - startPacketSender(["random"]); + startPacketSender(); } }, }, diff --git a/electron-app/src/processes/packetSender.js b/electron-app/src/processes/packetSender.js index e6efc5cf9..74b653fa1 100644 --- a/electron-app/src/processes/packetSender.js +++ b/electron-app/src/processes/packetSender.js @@ -12,16 +12,18 @@ import { getBinaryPath } from "../utils/paths.js"; // Store the packet sender process instance let packetSenderProcess = null; +// Default arguments for packet sender +const DEFAULT_ARGS = ["1", "1"]; // Send mode, Random type + /** * Starts the packet sender process by spawning the packet-sender binary with optional arguments. * Sets up event handlers for stdout and stderr with appropriate logging. * @param {string[]} [args=[]] - Optional array of command-line arguments to pass to the packet-sender binary. * @returns {import("child_process").ChildProcessWithoutNullStreams | null} The spawned ChildProcess object, or null if the binary is not found. * @example - * const process = startPacketSender(["--port", "8080"]); * startPacketSender(); */ -function startPacketSender(args = []) { +function startPacketSender(args = DEFAULT_ARGS) { // Get the path to the packet-sender binary const packetSenderBin = getBinaryPath("packet-sender"); @@ -44,6 +46,14 @@ function startPacketSender(args = []) { // Log stdout output from packet sender process.stdout.on("data", (data) => { logger.packetSender.info(`${data.toString().trim()}`); + + if (data.toString().includes("1) Send packets")) { + process.stdin.write("1\n"); + } + + if (data.toString().includes("1) Random")) { + process.stdin.write("1\n"); + } }); // Log stderr output as errors @@ -90,7 +100,7 @@ function restartPacketSender() { // Wait before starting new process to ensure cleanup setTimeout(() => { // Start with help arguments - startPacketSender(["random"]); + startPacketSender(); }, 500); } } diff --git a/electron-app/src/utils/paths.js b/electron-app/src/utils/paths.js index f7bf70033..1d44ceb39 100644 --- a/electron-app/src/utils/paths.js +++ b/electron-app/src/utils/paths.js @@ -41,13 +41,6 @@ function getBinaryPath(name) { const arch = process.arch; const ext = platform === "win32" ? ".exe" : ""; - if (name === "packet-sender") { - if (!app.isPackaged) { - return path.join(getAppPath(), "binaries", `${name}${ext}`); - } - return path.join(process.resourcesPath, "binaries", `${name}${ext}`); - } - const goosMap = { win32: "windows", darwin: "darwin", diff --git a/go.work b/go.work index 521811c76..957518330 100644 --- a/go.work +++ b/go.work @@ -2,4 +2,5 @@ go 1.23.1 use ( ./backend + ./packet-sender ) diff --git a/packet-sender/.gitignore b/packet-sender/.gitignore deleted file mode 100644 index 6d23150b2..000000000 --- a/packet-sender/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Rust target directory -/target/ \ No newline at end of file diff --git a/packet-sender/main.go b/packet-sender/main.go index 9a52ccb99..f748519f3 100644 --- a/packet-sender/main.go +++ b/packet-sender/main.go @@ -7,8 +7,6 @@ import ( boardpkg "packet_sender/pkg/board" "packet_sender/pkg/listener" "packet_sender/pkg/sender" - "path" - "path/filepath" "strings" adj_module "github.com/HyperloopUPV-H8/h9-backend/pkg/adj" @@ -66,11 +64,13 @@ func getConn(lip string, lport uint16, rip string, rport uint16) *net.UDPConn { // getADJ loads the same ADJ used by backend directly from backend/cmd/adj. func getADJ() adj_module.ADJ { - adjPath, err := filepath.Abs(path.Join("..", "backend", "cmd", "adj")) - if err != nil { - log.Fatalf("Failed to resolve ADJ path: %v", err) - } - adj_module.RepoPath = adjPath + string(filepath.Separator) + // adjPath, err := filepath.Abs(path.Join("..", "backend", "cmd", "adj")) + // if err != nil { + // log.Fatalf("Failed to resolve ADJ path: %v", err) + // } + // adj_module.RepoPath = adjPath + string(filepath.Separator) + + // Uses the same ADJ RepoPath as the backend by default adj, err := adj_module.NewADJ("") if err != nil { diff --git a/packet-sender/package.json b/packet-sender/package.json new file mode 100644 index 000000000..4842b09d2 --- /dev/null +++ b/packet-sender/package.json @@ -0,0 +1,13 @@ +{ + "name": "packet-sender", + "version": "1.0.0", + "private": true, + "author": "Hyperloop UPV Team", + "license": "MIT", + "scripts": { + "build": "go build -o packet-sender main.go", + "build:ci": "go build", + "dev": "go run main.go", + "test": "go test ./..." + } +} From 715edba7a9f549d49517e8183602479202a8e108 Mon Sep 17 00:00:00 2001 From: Maxim <74974283+maximka76667@users.noreply.github.com> Date: Fri, 20 Feb 2026 13:18:14 +0100 Subject: [PATCH 04/18] feat: add global boards state --- .../settings/MultiCheckboxField.tsx | 36 +++++++++++-------- .../src/components/settings/SettingsForm.tsx | 11 ++++-- frontend/testing-view/src/constants/boards.ts | 10 ------ .../src/constants/settingsSchema.ts | 6 ++-- .../components/FilterCategoryItem.tsx | 4 +-- .../filtering/components/FilterController.tsx | 5 +-- .../filtering/store/filteringSlice.ts | 15 ++++---- .../rightSidebar/sections/CommandsSection.tsx | 26 ++++++++------ .../sections/TelemetrySection.tsx | 28 ++++++++------- .../testing-view/src/hooks/useBoardData.ts | 2 ++ .../src/hooks/useTransformedBoards.ts | 10 +++++- frontend/testing-view/src/lib/utils.ts | 8 ++--- .../src/store/slices/catalogSlice.ts | 6 ++++ packet-sender/package.json | 1 - 14 files changed, 97 insertions(+), 71 deletions(-) delete mode 100644 frontend/testing-view/src/constants/boards.ts diff --git a/frontend/testing-view/src/components/settings/MultiCheckboxField.tsx b/frontend/testing-view/src/components/settings/MultiCheckboxField.tsx index eb3980a2f..8ece18567 100644 --- a/frontend/testing-view/src/components/settings/MultiCheckboxField.tsx +++ b/frontend/testing-view/src/components/settings/MultiCheckboxField.tsx @@ -20,21 +20,27 @@ export const MultiCheckboxField = ({
+ No boards detected. Connect to the backend to see available options. +
+ ) : ( + field.options?.map((opt) => ( ++ The following boards are in your saved filters but not in the + current configuration:{" "} + + {extraCategories.join(", ")} + +
+ +