Files
2026-07-23 09:12:00 +09:00

264 lines
7.2 KiB
Bash
Executable File

#!/usr/bin/env sh
set -eu
INSTALL_DIR="${PLATFORM_AGENT_DIR:-/opt/platform-agent}"
SERVICE_NAME="${PLATFORM_AGENT_SERVICE:-platform-agent}"
CONFIG_PATH="${AGENT_CONFIG:-${INSTALL_DIR}/agent.config.json}"
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
log() {
printf '%s\n' "$*"
}
need_cmd() {
command -v "$1" >/dev/null 2>&1
}
as_root() {
if [ "$(id -u)" -eq 0 ]; then
"$@"
elif need_cmd sudo; then
sudo "$@"
else
log "Root privileges are required: $*"
exit 1
fi
}
prompt_value() {
var_name="$1"
label="$2"
current_value="$3"
secret="${4:-false}"
if [ "$secret" = "true" ]; then
printf '%s [hidden, Enter keeps current]: ' "$label"
stty -echo 2>/dev/null || true
IFS= read -r answer || answer=""
stty echo 2>/dev/null || true
printf '\n'
else
printf '%s [%s]: ' "$label" "$current_value"
IFS= read -r answer || answer=""
fi
if [ -n "$answer" ]; then
eval "$var_name=\"\$answer\""
fi
}
prompt_yes_no() {
label="$1"
default="${2:-no}"
suffix="[y/N]"
[ "$default" = "yes" ] && suffix="[Y/n]"
printf '%s %s ' "$label" "$suffix"
IFS= read -r answer || answer=""
answer="$(printf '%s' "$answer" | tr '[:upper:]' '[:lower:]')"
if [ -z "$answer" ]; then
[ "$default" = "yes" ]
return
fi
[ "$answer" = "y" ] || [ "$answer" = "yes" ]
}
json_get() {
key_path="$1"
fallback="${2:-}"
python3 - "$CONFIG_PATH" "$key_path" "$fallback" <<'PY'
import json
import sys
path, key_path, fallback = sys.argv[1], sys.argv[2], sys.argv[3]
try:
with open(path, "r", encoding="utf-8") as fp:
value = json.load(fp)
except Exception:
print(fallback)
raise SystemExit
for key in key_path.split("."):
if not isinstance(value, dict):
value = None
break
value = value.get(key)
if value is None:
print(fallback)
elif isinstance(value, bool):
print("true" if value else "false")
else:
print(value)
PY
}
service_user() {
if [ -f "$SERVICE_FILE" ]; then
user_line="$(sed -n 's/^User=//p' "$SERVICE_FILE" | head -n 1)"
[ -n "$user_line" ] && {
printf '%s' "$user_line"
return
}
fi
id -un
}
expand_path_for_user() {
path="$1"
run_user="$2"
case "$path" in
"~")
if [ "$run_user" = "root" ]; then printf '/root'; else printf '/home/%s' "$run_user"; fi
;;
"~/"*)
if [ "$run_user" = "root" ]; then printf '/root/%s' "${path#~/}"; else printf '/home/%s/%s' "$run_user" "${path#~/}"; fi
;;
*)
printf '%s' "$path"
;;
esac
}
write_config() {
tmp_file="$(mktemp)"
WORKSPACE_ROOT="$WORKSPACE_ROOT" \
ROBOT_STACK="$ROBOT_STACK" \
ROS_DOMAIN_ID="$ROS_DOMAIN_ID" \
CAMERA_ENABLED="$CAMERA_ENABLED" \
CAMERA_VIDEO_DEVICE="$CAMERA_VIDEO_DEVICE" \
CAMERA_SIGNALING_URL="$CAMERA_SIGNALING_URL" \
KASMVNC_GEOMETRY="$KASMVNC_GEOMETRY" \
AGENT_GATEWAY_TOKEN="$AGENT_GATEWAY_TOKEN" \
python3 - "$CONFIG_PATH" "$tmp_file" <<'PY'
import json
import os
import sys
source, target = sys.argv[1], sys.argv[2]
with open(source, "r", encoding="utf-8") as fp:
cfg = json.load(fp)
cfg.setdefault("workspace", {})
cfg.setdefault("ros", {})
cfg.setdefault("camera", {})
cfg.setdefault("desktop", {})
cfg.setdefault("security", {})
cfg["workspace"]["root"] = os.environ["WORKSPACE_ROOT"]
cfg["ros"]["stack"] = "nav2" if os.environ["ROBOT_STACK"].lower() == "nav2" else "autoware"
cfg["ros"]["domainId"] = os.environ["ROS_DOMAIN_ID"] if os.environ["ROS_DOMAIN_ID"].isdigit() else "0"
cfg["camera"]["enabled"] = os.environ["CAMERA_ENABLED"].lower() in ("true", "1", "yes", "y", "on")
cfg["camera"]["videoDevice"] = os.environ["CAMERA_VIDEO_DEVICE"]
cfg["camera"]["signalingUrl"] = os.environ["CAMERA_SIGNALING_URL"]
cfg["desktop"]["geometry"] = os.environ["KASMVNC_GEOMETRY"]
if os.environ["AGENT_GATEWAY_TOKEN"]:
cfg["security"]["gatewayToken"] = os.environ["AGENT_GATEWAY_TOKEN"]
with open(target, "w", encoding="utf-8") as fp:
json.dump(cfg, fp, ensure_ascii=False, indent=2)
fp.write("\n")
PY
as_root cp "$tmp_file" "$CONFIG_PATH"
rm -f "$tmp_file"
}
restart_service() {
if need_cmd systemctl; then
as_root systemctl restart "$SERVICE_NAME"
elif need_cmd service; then
as_root service "$SERVICE_NAME" restart
else
log "No service manager found. Restart the agent manually."
fi
}
if ! need_cmd python3; then
log "python3 is required to edit ${CONFIG_PATH}."
exit 1
fi
if [ ! -f "$CONFIG_PATH" ]; then
log "Config not found: ${CONFIG_PATH}"
log "Set AGENT_CONFIG=/path/to/agent.config.json or install the agent first."
exit 1
fi
RUN_USER="$(service_user)"
WORKSPACE_ROOT="$(json_get workspace.root '~/autonomy-studio/workspaces')"
ROBOT_STACK="$(json_get ros.stack autoware)"
ROS_DOMAIN_ID="$(json_get ros.domainId 0)"
CAMERA_ENABLED="$(json_get camera.enabled false)"
CAMERA_VIDEO_DEVICE="$(json_get camera.videoDevice /dev/video0)"
CAMERA_SIGNALING_URL="$(json_get camera.signalingUrl ws://127.0.0.1:3000)"
KASMVNC_GEOMETRY="$(json_get desktop.geometry 1600x900)"
AGENT_GATEWAY_TOKEN="$(json_get security.gatewayToken '')"
while :; do
clear
log "Autonomy Studio Platform Agent Settings"
log "======================================="
log "Config : ${CONFIG_PATH}"
log "Service : ${SERVICE_NAME}"
log ""
log "1. Workspace root ${WORKSPACE_ROOT}"
log "2. ROS stack ${ROBOT_STACK}"
log "3. ROS_DOMAIN_ID ${ROS_DOMAIN_ID}"
log "4. Camera enabled ${CAMERA_ENABLED}"
log "5. Camera device ${CAMERA_VIDEO_DEVICE}"
log "6. Camera signaling ${CAMERA_SIGNALING_URL}"
log "7. KasmVNC resolution ${KASMVNC_GEOMETRY}"
log "8. Gateway token $(if [ -n "$AGENT_GATEWAY_TOKEN" ]; then printf 'configured'; else printf 'empty'; fi)"
log ""
log "s. Save and restart"
log "q. Quit"
log ""
printf 'Select: '
IFS= read -r choice || choice=""
case "$choice" in
1)
prompt_value WORKSPACE_ROOT "Workspace root" "$WORKSPACE_ROOT"
;;
2)
prompt_value ROBOT_STACK "ROS stack (autoware/nav2)" "$ROBOT_STACK"
case "$ROBOT_STACK" in
nav2|NAV2) ROBOT_STACK="nav2" ;;
*) ROBOT_STACK="autoware" ;;
esac
;;
3)
prompt_value ROS_DOMAIN_ID "ROS_DOMAIN_ID" "$ROS_DOMAIN_ID"
ROS_DOMAIN_ID="$(printf '%s' "$ROS_DOMAIN_ID" | tr -cd '0-9')"
[ -n "$ROS_DOMAIN_ID" ] || ROS_DOMAIN_ID="0"
;;
4)
prompt_value CAMERA_ENABLED "Camera enabled true/false" "$CAMERA_ENABLED"
;;
5)
prompt_value CAMERA_VIDEO_DEVICE "Camera device" "$CAMERA_VIDEO_DEVICE"
;;
6)
prompt_value CAMERA_SIGNALING_URL "Camera signaling URL" "$CAMERA_SIGNALING_URL"
;;
7)
prompt_value KASMVNC_GEOMETRY "KasmVNC resolution" "$KASMVNC_GEOMETRY"
;;
8)
prompt_value AGENT_GATEWAY_TOKEN "Gateway token" "$AGENT_GATEWAY_TOKEN" true
;;
s|S)
write_config
workspace_path="$(expand_path_for_user "$WORKSPACE_ROOT" "$RUN_USER")"
if prompt_yes_no "Create workspace directory ${workspace_path} if missing?" "yes"; then
as_root mkdir -p "$workspace_path"
as_root chown -R "$RUN_USER":"$RUN_USER" "$workspace_path" || true
fi
restart_service
log ""
log "Settings saved and service restarted."
exit 0
;;
q|Q)
log "Canceled."
exit 0
;;
esac
done