feat(config): externalize runtime paths and script settings for local setup
This commit is contained in:
@@ -104,6 +104,7 @@ public class ProcessManagerService {
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(python, script);
|
||||
pb.redirectErrorStream(true);
|
||||
configureMqttSimulatorEnvironment(pb);
|
||||
|
||||
pythonProcess = processLauncher.launch(pb);
|
||||
|
||||
@@ -176,6 +177,8 @@ public class ProcessManagerService {
|
||||
unrealPsScript
|
||||
);
|
||||
|
||||
configureUnrealScriptEnvironment(pb);
|
||||
|
||||
unrealProcess = processLauncher.launch(pb);
|
||||
|
||||
//pb.directory(new File(exe).getParentFile());
|
||||
@@ -311,4 +314,69 @@ public class ProcessManagerService {
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes optional simulator settings from app config to the Python process environment.
|
||||
*
|
||||
* @param processBuilder simulator process builder
|
||||
*/
|
||||
private void configureMqttSimulatorEnvironment(ProcessBuilder processBuilder) {
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.broker", "MQTT_SIM_BROKER");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.port", "MQTT_SIM_PORT");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.topic", "MQTT_SIM_TOPIC");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.username", "MQTT_SIM_USERNAME");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.password", "MQTT_SIM_PASSWORD");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.qos", "MQTT_SIM_QOS");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.interval_seconds", "MQTT_SIM_INTERVAL_SECONDS");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.start_id", "MQTT_SIM_START_ID");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.client_id", "MQTT_SIM_CLIENT_ID");
|
||||
putEnvFromConfig(processBuilder, "mqtt_sim.log_file", "MQTT_SIM_LOG_FILE");
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes optional Unreal launcher settings from app config to the PowerShell process environment.
|
||||
*
|
||||
* @param processBuilder Unreal process builder
|
||||
*/
|
||||
private void configureUnrealScriptEnvironment(ProcessBuilder processBuilder) {
|
||||
putEnvFromConfig(processBuilder, "unreal.target.executable", "VGA_UE_EXE");
|
||||
putEnvFromConfig(processBuilder, "unreal.target.args", "VGA_UE_ARGS");
|
||||
putEnvFromConfig(processBuilder, "unreal.target.working_dir", "VGA_UE_WORKDIR");
|
||||
putEnvFromConfig(processBuilder, "unreal.signalling_server.script", "VGA_SIGNALLING_BAT");
|
||||
putEnvFromConfig(processBuilder, "unreal.startup.delay.seconds", "VGA_SIGNALLING_DELAY");
|
||||
|
||||
String pidDir = cleanConfigValue(config.getProperty("unreal.pid.dir"));
|
||||
if (pidDir == null || pidDir.isBlank()) {
|
||||
try {
|
||||
Path parent = Path.of(unrealPidFile).getParent();
|
||||
if (parent != null) {
|
||||
pidDir = parent.toString();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
pidDir = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (pidDir != null && !pidDir.isBlank()) {
|
||||
processBuilder.environment().put("VGA_PID_DIR", pidDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a config value to process environment when present.
|
||||
*
|
||||
* @param processBuilder target process builder
|
||||
* @param configKey application properties key
|
||||
* @param envName environment variable name
|
||||
*/
|
||||
private void putEnvFromConfig(
|
||||
ProcessBuilder processBuilder,
|
||||
String configKey,
|
||||
String envName
|
||||
) {
|
||||
String value = cleanConfigValue(config.getProperty(configKey));
|
||||
if (value != null && !value.isBlank()) {
|
||||
processBuilder.environment().put(envName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,16 @@ mqtt.topic=PREDICTION
|
||||
# ===== MQTT SIMULATOR =====
|
||||
mqtt_sim.enabled=false
|
||||
mqtt_sim.script=src/main/resources/scripts/mqtt_simulator.py
|
||||
mqtt_sim.broker=localhost
|
||||
mqtt_sim.port=1883
|
||||
mqtt_sim.topic=PREDICTION
|
||||
mqtt_sim.qos=0
|
||||
mqtt_sim.interval_seconds=5
|
||||
# mqtt_sim.username=
|
||||
# mqtt_sim.password=
|
||||
# mqtt_sim.start_id=1
|
||||
# mqtt_sim.client_id=mqtt-simulator
|
||||
# mqtt_sim.log_file=logs/mqtt_simulator.log
|
||||
|
||||
# ===== ANIMATION =====
|
||||
animation.output.path=data/animation.json
|
||||
@@ -25,3 +35,8 @@ unreal.executable=C:\\Users\\Student\\Documents\\Dannick\\avatar\\start_avatar.p
|
||||
unreal.signalling_server.script=C:\\Users\\Student\\Documents\\Dannick\\avatar\\Windows\\Prototyp1\\Samples\\PixelStreaming\\WebServers\\SignallingWebServer\\platform_scripts\\cmd\\start_with_stun.bat
|
||||
unreal.pid.file=C:\\Users\\Student\\Documents\\Dannick\\avatar\\unreal.pid
|
||||
unreal.signalling.pid.file=C:\\Users\\Student\\Documents\\Dannick\\avatar\\signalling.pid
|
||||
# unreal.pid.dir=C:\\Users\\Student\\Documents\\Dannick\\avatar
|
||||
# unreal.target.executable=C:\\Users\\Student\\Documents\\Dannick\\avatar\\Windows\\Prototyp1.exe
|
||||
# unreal.target.args=-PixelStreamingURL=ws://127.0.0.1 -RenderOffscreen -PixelStreamingWebRTCDisableTransmitAudio
|
||||
# unreal.target.working_dir=C:\\Users\\Student\\Documents\\Dannick\\avatar\\Windows
|
||||
# unreal.startup.delay.seconds=5
|
||||
|
||||
@@ -1,85 +1,151 @@
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
import sys
|
||||
import random
|
||||
import time
|
||||
import logging
|
||||
|
||||
# ===== KONFIGURATION =====
|
||||
BROKER = "141.75.223.13"
|
||||
PORT = 1883
|
||||
TOPIC = "PREDICTION"
|
||||
USERNAME = None
|
||||
PASSWORD = None
|
||||
QOS = 0
|
||||
INTERVAL_SECONDS = 5
|
||||
# ==========================
|
||||
|
||||
# Logging konfigurieren (Console + Datei)
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - %(levelname)s - %(message)s",
|
||||
handlers=[
|
||||
logging.FileHandler("logs/mqtt_simulator.log"),
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
DEFAULT_BROKER = "141.75.223.13"
|
||||
DEFAULT_PORT = 1883
|
||||
DEFAULT_TOPIC = "PREDICTION"
|
||||
DEFAULT_QOS = 0
|
||||
DEFAULT_INTERVAL_SECONDS = 5.0
|
||||
DEFAULT_START_ID = 1
|
||||
DEFAULT_CLIENT_ID = "mqtt-simulator"
|
||||
DEFAULT_LOG_FILE = "logs/mqtt_simulator.log"
|
||||
|
||||
|
||||
def env_int(name, default):
|
||||
value = os.getenv(name)
|
||||
if value is None or value.strip() == "":
|
||||
return default
|
||||
|
||||
try:
|
||||
return int(value)
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
|
||||
def env_float(name, default):
|
||||
value = os.getenv(name)
|
||||
if value is None or value.strip() == "":
|
||||
return default
|
||||
|
||||
try:
|
||||
return float(value)
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
|
||||
def build_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="MQTT simulator for binary prediction events."
|
||||
)
|
||||
|
||||
parser.add_argument("--broker", default=os.getenv("MQTT_SIM_BROKER", DEFAULT_BROKER))
|
||||
parser.add_argument("--port", type=int, default=env_int("MQTT_SIM_PORT", DEFAULT_PORT))
|
||||
parser.add_argument("--topic", default=os.getenv("MQTT_SIM_TOPIC", DEFAULT_TOPIC))
|
||||
parser.add_argument("--username", default=os.getenv("MQTT_SIM_USERNAME"))
|
||||
parser.add_argument("--password", default=os.getenv("MQTT_SIM_PASSWORD"))
|
||||
parser.add_argument("--qos", type=int, choices=[0, 1, 2], default=env_int("MQTT_SIM_QOS", DEFAULT_QOS))
|
||||
parser.add_argument(
|
||||
"--interval-seconds",
|
||||
type=float,
|
||||
default=env_float("MQTT_SIM_INTERVAL_SECONDS", DEFAULT_INTERVAL_SECONDS),
|
||||
)
|
||||
parser.add_argument("--start-id", type=int, default=env_int("MQTT_SIM_START_ID", DEFAULT_START_ID))
|
||||
parser.add_argument("--client-id", default=os.getenv("MQTT_SIM_CLIENT_ID", DEFAULT_CLIENT_ID))
|
||||
parser.add_argument("--log-file", default=os.getenv("MQTT_SIM_LOG_FILE", DEFAULT_LOG_FILE))
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def configure_logging(log_file):
|
||||
log_dir = os.path.dirname(log_file)
|
||||
if log_dir:
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - %(levelname)s - %(message)s",
|
||||
handlers=[
|
||||
logging.FileHandler(log_file),
|
||||
logging.StreamHandler(sys.stdout),
|
||||
],
|
||||
force=True,
|
||||
)
|
||||
|
||||
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
if rc == 0:
|
||||
logging.info("Erfolgreich mit Broker verbunden")
|
||||
else:
|
||||
logging.error(f"Verbindung fehlgeschlagen mit Code {rc}")
|
||||
logging.error("Verbindung fehlgeschlagen mit Code %s", rc)
|
||||
|
||||
|
||||
def main():
|
||||
args = build_args()
|
||||
configure_logging(args.log_file)
|
||||
|
||||
logging.info("Python script gestartet")
|
||||
logging.info(
|
||||
"Konfiguration: broker=%s port=%s topic=%s qos=%s interval=%s",
|
||||
args.broker,
|
||||
args.port,
|
||||
args.topic,
|
||||
args.qos,
|
||||
args.interval_seconds,
|
||||
)
|
||||
|
||||
client = mqtt.Client()
|
||||
client = mqtt.Client(client_id=args.client_id)
|
||||
|
||||
if USERNAME and PASSWORD:
|
||||
client.username_pw_set(USERNAME, PASSWORD)
|
||||
if args.username:
|
||||
client.username_pw_set(args.username, args.password)
|
||||
|
||||
client.on_connect = on_connect
|
||||
|
||||
try:
|
||||
logging.info(f"Verbinde mit Broker {BROKER}:{PORT}")
|
||||
client.connect(BROKER, PORT, 60)
|
||||
logging.info("Verbinde mit Broker %s:%s", args.broker, args.port)
|
||||
client.connect(args.broker, args.port, 60)
|
||||
client.loop_start()
|
||||
|
||||
logging.info("Starte kontinuierliches Senden...")
|
||||
|
||||
current_id = 1
|
||||
current_id = args.start_id
|
||||
|
||||
while True:
|
||||
payload = {
|
||||
"valid": True,
|
||||
"_id": current_id,
|
||||
"prediction": random.randint(0, 1)
|
||||
"prediction": random.randint(0, 1),
|
||||
}
|
||||
|
||||
json_payload = json.dumps(payload)
|
||||
|
||||
client.publish(TOPIC, json_payload, qos=QOS)
|
||||
logging.info(f"Gesendet an '{TOPIC}': {json_payload}")
|
||||
client.publish(args.topic, json_payload, qos=args.qos)
|
||||
logging.info("Gesendet an '%s': %s", args.topic, json_payload)
|
||||
|
||||
current_id += 1
|
||||
|
||||
time.sleep(INTERVAL_SECONDS)
|
||||
time.sleep(args.interval_seconds)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Publisher manuell beendet")
|
||||
|
||||
client.loop_stop()
|
||||
client.disconnect()
|
||||
sys.exit(0)
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logging.exception("Unerwarteter Fehler")
|
||||
sys.exit(1)
|
||||
|
||||
finally:
|
||||
try:
|
||||
client.loop_stop()
|
||||
client.disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -1,22 +1,64 @@
|
||||
$pidDir = "C:\Users\Student\Documents\Dannick\avatar"
|
||||
param(
|
||||
[string]$PidDir = $env:VGA_PID_DIR,
|
||||
[string]$UeExe = $env:VGA_UE_EXE,
|
||||
[string]$UeArgs = $env:VGA_UE_ARGS,
|
||||
[string]$SignallingBat = $env:VGA_SIGNALLING_BAT,
|
||||
[string]$UeWorkingDir = $env:VGA_UE_WORKDIR,
|
||||
[int]$SignallingStartupDelaySeconds = $(if ($env:VGA_SIGNALLING_DELAY) { [int]$env:VGA_SIGNALLING_DELAY } else { 5 }),
|
||||
[switch]$ShowSignallingWindow
|
||||
)
|
||||
|
||||
$ueExe = "C:\Users\Student\Documents\Dannick\avatar\Windows\Prototyp1.exe"
|
||||
$ueArgs = "-PixelStreamingURL=ws://127.0.0.1 -RenderOffscreen -PixelStreamingWebRTCDisableTransmitAudio"
|
||||
if (-not $PidDir) {
|
||||
$PidDir = "C:\Users\Student\Documents\Dannick\avatar"
|
||||
}
|
||||
|
||||
$signallingBat = "C:\Users\Student\Documents\Dannick\avatar\Windows\Prototyp1\Samples\PixelStreaming\WebServers\SignallingWebServer\platform_scripts\cmd\start_with_stun.bat"
|
||||
if (-not $UeExe) {
|
||||
$UeExe = "C:\Users\Student\Documents\Dannick\avatar\Windows\Prototyp1.exe"
|
||||
}
|
||||
|
||||
$ueWorkingDir = "C:\Users\Student\Documents\Dannick\avatar\Windows"
|
||||
if (-not $UeArgs) {
|
||||
$UeArgs = "-PixelStreamingURL=ws://127.0.0.1 -RenderOffscreen -PixelStreamingWebRTCDisableTransmitAudio"
|
||||
}
|
||||
|
||||
$signalling = Start-Process -FilePath $signallingBat -PassThru -WindowStyle Hidden
|
||||
if (-not $SignallingBat) {
|
||||
$SignallingBat = "C:\Users\Student\Documents\Dannick\avatar\Windows\Prototyp1\Samples\PixelStreaming\WebServers\SignallingWebServer\platform_scripts\cmd\start_with_stun.bat"
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds 5
|
||||
if (-not $UeWorkingDir) {
|
||||
$UeWorkingDir = Split-Path -Path $UeExe -Parent
|
||||
}
|
||||
|
||||
$ue = Start-Process `
|
||||
-FilePath $ueExe `
|
||||
-ArgumentList $ueArgs `
|
||||
-WorkingDirectory $ueWorkingDir `
|
||||
-PassThru
|
||||
if (-not (Test-Path -LiteralPath $SignallingBat)) {
|
||||
throw "Signalling script not found: $SignallingBat"
|
||||
}
|
||||
|
||||
$ue.Id | Out-File "$pidDir\unreal.pid" -Encoding ascii
|
||||
$signalling.Id | Out-File "$pidDir\signalling.pid" -Encoding ascii
|
||||
if (-not (Test-Path -LiteralPath $UeExe)) {
|
||||
throw "Unreal executable not found: $UeExe"
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $UeWorkingDir)) {
|
||||
throw "Unreal working directory not found: $UeWorkingDir"
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $PidDir -Force | Out-Null
|
||||
|
||||
$signallingWindowStyle = if ($ShowSignallingWindow.IsPresent) { "Normal" } else { "Hidden" }
|
||||
$signalling = Start-Process -FilePath $SignallingBat -PassThru -WindowStyle $signallingWindowStyle
|
||||
|
||||
Start-Sleep -Seconds $SignallingStartupDelaySeconds
|
||||
|
||||
$ueStartParams = @{
|
||||
FilePath = $UeExe
|
||||
WorkingDirectory = $UeWorkingDir
|
||||
PassThru = $true
|
||||
}
|
||||
|
||||
if ($UeArgs) {
|
||||
$ueStartParams["ArgumentList"] = $UeArgs
|
||||
}
|
||||
|
||||
$ue = Start-Process @ueStartParams
|
||||
|
||||
$ue.Id | Out-File (Join-Path $PidDir "unreal.pid") -Encoding ascii
|
||||
$signalling.Id | Out-File (Join-Path $PidDir "signalling.pid") -Encoding ascii
|
||||
|
||||
|
||||
Reference in New Issue
Block a user