From 8cf04dd2fe931f42a31fc88c6dd356a1a8c67efa Mon Sep 17 00:00:00 2001 From: viruslox <12681439+viruslox@users.noreply.github.com> Date: Thu, 20 Aug 2026 19:26:09 +0000 Subject: [PATCH] Fix configuration completeness and frontend installation - Ensures `vlx_frontend` binary is copied to the `bin` folder during both server and client installations. - Adds missing configuration variables, their descriptions, and default values to `config/frameflow.settings.template`, `config/frameflow_srv.settings.template`, and `README.md`. - Removes references to non-existent options `API_URL`, `AUTH_TOKEN`, and `RTSP_URL` from `README.md` and `ARCHITECTURE.md`. --- ARCHITECTURE.md | 2 +- README.md | 25 +++++++++++++--- config/frameflow.settings.template | 13 +++++++-- config/frameflow_srv.settings.template | 2 ++ internal/sysutils/install.go | 40 ++++++++++++++------------ 5 files changed, 57 insertions(+), 25 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 8f9940d..caec7dc 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -66,7 +66,7 @@ The Server's MediaMTX instance maintains a continuous background loop (`/offline To prevent rapid stream flapping during minor cellular jitters, the Client employs a **State Latch** on the MLVPN tunnel utilizing a **Network Hysteresis** logic. The Client continuously attempts to ping the Server tunnel (`10.1.10.1`). Instead of a binary success/fail check, the system performs a retry loop (up to 3 consecutive ping attempts with a small delay). It will only drop the bonded UDP route and fallback to a standard unbonded route if the tunnel explicitly stays down and all 3 ping checks fail. -Furthermore, to ensure application stability before initializing the FFmpeg encoder pipeline, the core implements **Strict URL Validation** on both `RTSP` and `SRT` streaming endpoints using Go's native `net/url` parser. The ingest will gracefully reject malformed URLs prior to execution. +Furthermore, to ensure application stability before initializing the FFmpeg encoder pipeline, the core implements **Strict URL Validation** on streaming endpoints such as `SRT` using Go's native `net/url` parser. The ingest will gracefully reject malformed URLs prior to execution. ## Security & Execution Flow diff --git a/README.md b/README.md index eee839d..14ccb67 100644 --- a/README.md +++ b/README.md @@ -239,9 +239,28 @@ Note: Adjust the port (`8080` by default) to match your `vlx_frontend` bind port | Variable | Description | | :--- | :--- | +| `FRAMEFLOW_USER` | The dedicated, unprivileged user that runs the background services (default: `frameflow`). | | `MLVPN_SERVER_IP` | The remote server IP for MLVPN (UDP traffic). | +| `MLVPN_SLOT` | MLVPN tunnel identity (client). Must match this client's peer slot on the server. | +| `MLVPN_CLIENT_TUN_IP` | Optional override for client TUN IP. | +| `MLVPN_SERVER_TUN_IP` | Optional override for gateway/server TUN IP. | +| `MLVPN_REMOTE_PORT` | Optional override for remote UDP port. | | `SHADOWSOCKS_SERVER_IPS` | The remote server IP(s) for Shadowsocks bonding (TCP proxy traffic). | | `AP_PASSWORD` | WPA2 passphrase for the generated Access Point. Automatically generated if left empty. | +| `MPTCP_PROXY_PASS` | Password for the MPTCP proxy. | +| `MLVPN_KEY` | Key for the single-client MLVPN tunnel. | +| `DB_DSN` | SQLite database DSN for cameraman configuration (default: `/opt/VLX_FrameFlow/var/frameflow.db`). | +| `CAM_PATH_PREFIX` | Remote MediaMTX path prefix (default: `cameraman`). | +| `CAM_MAX_RESOLUTION` | Maximum fallback video resolution for Cameraman (default: `1920x1080`). | +| `CAM_MAX_FPS` | Maximum fallback video FPS for Cameraman (default: `30`). | +| `bind_address` | Backend API bind address (default: `127.0.0.1`). | +| `bind_port` | Backend API bind port (default: `9090`). | +| `allowed_origins` | Comma-separated list of allowed CORS origins for the API. | +| `bkend_user1` / `bkend_pass1` | First tier of backend API credentials. | +| `backend_address` | Target backend address for the Svelte frontend (default: `127.0.0.1`). | +| `backend_port` | Target backend port for the Svelte frontend (default: `9090`). | +| `FF_GUI_USER` / `FF_GUI_PASS` | Credentials used to authenticate to the Svelte Control Panel frontend. | +| `client_crt` / `client_key` | Optional zero-trust mTLS paths for Svelte Control Panel to authenticate against the backend. | | `relay_client_host` | The remote Client API IP accessed via MLVPN tunnel (default: `10.1.10.2`). | | `relay_client_port` | The remote Client API Port accessed via MLVPN tunnel (default: `9090`). | | `use_relay` | For Frontend settings: `true` routes all UI module commands through the relay (`api/v1/relay/...`), useful when hosting UI on Server. `false` targets local Client API. | @@ -252,11 +271,10 @@ Note: Adjust the port (`8080` by default) to match your `vlx_frontend` bind port ### Streaming Endpoints -Both `RTSP_URL` and `SRT_URL` endpoints undergo **Strict URL Validation** before they are actively bound to the ingest pipeline. A malformed URL configuration (e.g., missing scheme) will proactively prevent the FFmpeg streaming unit from attempting to start, and instead will yield a direct descriptive error in the log. +Both endpoints undergo **Strict URL Validation** before they are actively bound to the ingest pipeline. A malformed URL configuration (e.g., missing scheme) will proactively prevent the FFmpeg streaming unit from attempting to start, and instead will yield a direct descriptive error in the log. | Variable | Description | | :--- | :--- | -| `RTSP_URL` | Base RTSP URL, primarily used for **Standard Ingest** on internal networks. | | `SRT_URL` | Base SRT URL, explicitly reserved for **Bonded Ingest** over the MLVPN tunnel. Safely auto-parses `publish:` StreamID credentials (`user:pass`). | **Example:** @@ -269,8 +287,7 @@ srt://10.1.10.1:8890?streamid=publish:stream_name:user:pass | Variable | Description | | :--- | :--- | | `GPSPORT` | gpsd local port (default: `1198`). | -| `API_URL` | Remote HTTP/HTTPS telemetry endpoint. | -| `AUTH_TOKEN` | Bearer token for API authentication. | +| `gps_target_url` | Remote HTTP/HTTPS telemetry endpoint. | --- diff --git a/config/frameflow.settings.template b/config/frameflow.settings.template index e9ff387..eb00f88 100644 --- a/config/frameflow.settings.template +++ b/config/frameflow.settings.template @@ -14,11 +14,15 @@ MEDIAMTX_DIR="/opt/mediamtx" AP_PASSWORD="" # GPS Tracker +# gpsd local port (default: 1198) +GPSPORT="1198" +# Remote HTTP/HTTPS telemetry endpoint for pushing GPS data gps_target_url="" # Network settings # Specifies role-aware privilege scoping. Do not manually force unless required. FRAMEFLOW_ROLE="" +# The remote server IP for MLVPN (UDP traffic). MLVPN_SERVER_IP="" # MLVPN tunnel identity (client). Must match this client's peer slot on the # server (see the server's etc/peers.yaml). Slot k derives: @@ -29,9 +33,11 @@ MLVPN_SLOT="0" MLVPN_CLIENT_TUN_IP="" MLVPN_SERVER_TUN_IP="" MLVPN_REMOTE_PORT="" -# Supports native Dual-Stack TCP bonding (comma-separated IPv4, IPv6) +# The remote server IP(s) for Shadowsocks bonding (TCP proxy traffic). Supports native Dual-Stack TCP bonding (comma-separated IPv4, IPv6) SHADOWSOCKS_SERVER_IPS="" +# Password for the MPTCP proxy. MPTCP_PROXY_PASS="" +# Key for the single-client MLVPN tunnel. MLVPN_KEY="" # Cameraman @@ -51,11 +57,14 @@ CAM_MAX_FPS="30" # Client API # This is the native backend API on the Client device (SBC). # It serves local UI requests and remote requests routed through the Server API relay. +# Backend API bind address (default: 127.0.0.1). bind_address=127.0.0.1 +# Backend API bind port (default: 9090). bind_port=9090 -# (comma-separated list of allowed CORS origins) +# Comma-separated list of allowed CORS origins for the API. allowed_origins="127.0.0.1" # Backend Credentials +# First tier of backend API credentials. bkend_user1=admin bkend_pass1=admin diff --git a/config/frameflow_srv.settings.template b/config/frameflow_srv.settings.template index c02a248..0a501ee 100644 --- a/config/frameflow_srv.settings.template +++ b/config/frameflow_srv.settings.template @@ -13,7 +13,9 @@ MEDIAMTX_DIR="/opt/mediamtx" # Explicitly sets the system to require root execution for main orchestrator daemons, # while utilizing /etc/systemd/system/ and multi-user.target for unit files. FRAMEFLOW_ROLE="SERVER" +# Password for the MPTCP proxy. MPTCP_PROXY_PASS="" +# Key for the single-client MLVPN tunnel. # MLVPN_KEY is used only for the legacy single-client tunnel (no peers.yaml). # For multiple clients, define each one in etc/peers.yaml (see peers.yaml.template); # when that file is present it takes precedence and each peer carries its own key. diff --git a/internal/sysutils/install.go b/internal/sysutils/install.go index 486ae06..4811bf4 100644 --- a/internal/sysutils/install.go +++ b/internal/sysutils/install.go @@ -166,26 +166,30 @@ func InstallBinary(isServer bool) error { } Info("Binary successfully installed to %s", targetPath) - // Explicitly copy required client binaries + // Explicitly copy required binaries (including frontend for both roles) srcDir := filepath.Dir(exePath) - if !isServer { - requiredBinaries := []string{"VLX_FrameFlow", "vlx_frontend"} - for _, bin := range requiredBinaries { - binPath := filepath.Join(srcDir, bin) - if _, err := os.Stat(binPath); err == nil { + var requiredBinaries []string + if isServer { + requiredBinaries = []string{"vlx_frontend"} + } else { + requiredBinaries = []string{"VLX_FrameFlow", "vlx_frontend"} + } + + for _, bin := range requiredBinaries { + binPath := filepath.Join(srcDir, bin) + if _, err := os.Stat(binPath); err == nil { + tgt := filepath.Join(installTargetDir, bin) + if err := copyFile(binPath, tgt, 0755); err == nil { + Info("Required binary %s explicitly copied to %s", bin, tgt) + } + } else { + // Try with arch suffix for the current OS/Arch if raw name not found + sfx := "_" + runtime.GOARCH + sfxPath := filepath.Join(srcDir, bin+sfx) + if _, err := os.Stat(sfxPath); err == nil { tgt := filepath.Join(installTargetDir, bin) - if err := copyFile(binPath, tgt, 0755); err == nil { - Info("Required binary %s explicitly copied to %s", bin, tgt) - } - } else { - // Try with arch suffix for the current OS/Arch if raw name not found - sfx := "_" + runtime.GOARCH - sfxPath := filepath.Join(srcDir, bin+sfx) - if _, err := os.Stat(sfxPath); err == nil { - tgt := filepath.Join(installTargetDir, bin) - if err := copyFile(sfxPath, tgt, 0755); err == nil { - Info("Required binary %s (from %s) explicitly copied to %s", bin, bin+sfx, tgt) - } + if err := copyFile(sfxPath, tgt, 0755); err == nil { + Info("Required binary %s (from %s) explicitly copied to %s", bin, bin+sfx, tgt) } } }