release: bump version to 0.57.0
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
release / images (push) Has been cancelled
ci / delivery (push) Has been cancelled

This commit is contained in:
rayd1o
2026-05-14 01:02:17 +08:00
parent f14ff6ec0f
commit dd176a6ae6
18 changed files with 541 additions and 68 deletions

373
planet.sh
View File

@@ -120,6 +120,9 @@ FRONTEND_PID_FILE="$PLANET_STATE_DIR/frontend.pid"
FRONTEND_LOG_FILE="$PLANET_STATE_DIR/frontend.log"
PLANET_PORT_STATE_FILE="$PLANET_STATE_DIR/ports.env"
FRONTEND_VITE_ENTRY="$SCRIPT_DIR/frontend/node_modules/vite/bin/vite.js"
WINDOWS_LAN_RELAY_SCRIPT="$SCRIPT_DIR/scripts/windows-lan-relay.ps1"
WINDOWS_FRONTEND_RELAY_PID_FILE="$PLANET_STATE_DIR/windows_frontend_relay.pid"
WINDOWS_BACKEND_RELAY_PID_FILE="$PLANET_STATE_DIR/windows_backend_relay.pid"
MOTION_AGENT_PID_FILE="$PLANET_STATE_DIR/motion_agent.pid"
MOTION_AGENT_LOG_FILE="$PLANET_STATE_DIR/motion_agent.log"
AI_PROVIDER_BUILD_STAMP_FILE="$PLANET_CACHE_DIR/aiprovider_build.sha256"
@@ -133,6 +136,10 @@ START_RUN_COMPLETED=0
STARTED_BACKEND_THIS_RUN=0
STARTED_FRONTEND_THIS_RUN=0
STARTED_MOTION_AGENT_THIS_RUN=0
WINDOWS_LAN_RELAY_ENABLED=0
LAN_PUBLIC_FRONTEND_PORT="$DEFAULT_FRONTEND_PORT"
LAN_PUBLIC_BACKEND_PORT="$DEFAULT_BACKEND_PORT"
WINDOWS_LAN_RELAY_LISTEN_ADDRESS=""
AI_PROVIDER_RUNTIME_ENV_NAMES=(
SERVICE_NAME
SERVICE_VERSION
@@ -639,17 +646,246 @@ EOF
log_lan_access_notes() {
local frontend_port="$1"
local backend_port="$2"
local public_frontend_port="${3:-$frontend_port}"
local public_backend_port="${4:-$backend_port}"
local recommended_lan_ip=""
if recommended_lan_ip="$(get_recommended_lan_ipv4)"; then
log_note "推荐访问地址: http://${recommended_lan_ip}:${frontend_port}"
log_note "后端健康检查: http://${recommended_lan_ip}:${backend_port}/health"
log_note "推荐访问地址: http://${recommended_lan_ip}:${public_frontend_port}"
log_note "后端健康检查: http://${recommended_lan_ip}:${public_backend_port}/health"
else
log_note "前端已对局域网开放,请使用本机局域网 IP 访问 :${frontend_port}"
log_note "后端已对局域网开放,请使用本机局域网 IP 访问 :${backend_port}/health"
log_note "前端已对局域网开放,请使用本机局域网 IP 访问 :${public_frontend_port}"
log_note "后端已对局域网开放,请使用本机局域网 IP 访问 :${public_backend_port}/health"
fi
}
cleanup_windows_lan_relays() {
local pid_file
local pid
for pid_file in "$WINDOWS_FRONTEND_RELAY_PID_FILE" "$WINDOWS_BACKEND_RELAY_PID_FILE"; do
if [ -f "$pid_file" ]; then
if pid="$(read_pid_file "$pid_file")"; then
terminate_process_tree TERM "$pid"
sleep 0.3
terminate_process_tree KILL "$pid"
fi
remove_pid_file "$pid_file"
fi
done
}
start_windows_lan_relay() {
local name="$1"
local public_port="$2"
local target_port="$3"
local pid_file="$4"
local target_host="$5"
local listen_address="$6"
local script_path
local relay_pid
script_path="$(wslpath -w "$WINDOWS_LAN_RELAY_SCRIPT" 2>/dev/null || true)"
if [ -z "$script_path" ]; then
log_warn "无法转换 Windows relay 脚本路径,跳过 ${name} 局域网 relay"
return 1
fi
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$script_path" \
-ListenAddress "$listen_address" \
-ListenPort "$public_port" \
-TargetHost "$target_host" \
-TargetPort "$target_port" \
> /dev/null 2>&1 &
relay_pid=$!
write_pid_file "$pid_file" "$relay_pid"
sleep 0.5
if ! kill -0 "$relay_pid" 2>/dev/null; then
remove_pid_file "$pid_file"
log_warn "${name} Windows relay 未能监听端口 ${public_port}"
print_windows_port_listener_details "$public_port" || true
return 1
fi
log_success "${name} Windows relay 已启动: ${listen_address}:${public_port} -> ${target_host}:${target_port}"
}
start_windows_lan_relays() {
local target_host="127.0.0.1"
[ "$WINDOWS_LAN_RELAY_ENABLED" -eq 1 ] || return 0
cleanup_windows_lan_relays
start_windows_lan_relay "前端" "$LAN_PUBLIC_FRONTEND_PORT" "$FRONTEND_PORT" "$WINDOWS_FRONTEND_RELAY_PID_FILE" "$target_host" "$WINDOWS_LAN_RELAY_LISTEN_ADDRESS" || return 1
start_windows_lan_relay "后端" "$LAN_PUBLIC_BACKEND_PORT" "$BACKEND_PORT" "$WINDOWS_BACKEND_RELAY_PID_FILE" "$target_host" "$WINDOWS_LAN_RELAY_LISTEN_ADDRESS" || return 1
}
run_windows_admin_powershell_script() {
local script_path="$1"
local warn_context="$2"
local script_win_path=""
chmod 600 "$script_path" 2>/dev/null || true
script_win_path="$(wslpath -w "$script_path" 2>/dev/null || true)"
if [ -z "$script_win_path" ]; then
log_warn "${warn_context},但无法生成管理员 PowerShell 请求"
return 1
fi
powershell.exe -NoProfile -Command "Start-Process powershell.exe -Verb RunAs -Wait -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File \"${script_win_path}\"'" >/dev/null 2>&1
}
windows_firewall_missing_ports() {
local frontend_port="$1"
local backend_port="$2"
command -v powershell.exe >/dev/null 2>&1 || return 1
powershell.exe -NoProfile -Command "
\$ErrorActionPreference = 'SilentlyContinue'
\$ports = @([int]${frontend_port}, [int]${backend_port})
function Test-PortAllowed {
param([int]\$Port)
\$displayName = 'WSL Planet ' + \$Port
\$rule = Get-NetFirewallRule -DisplayName \$displayName -ErrorAction SilentlyContinue |
Where-Object { \$_.Enabled -eq 'True' -and \$_.Direction -eq 'Inbound' -and \$_.Action -eq 'Allow' } |
Select-Object -First 1
if (-not \$rule) { return \$false }
\$filter = \$rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue |
Where-Object { \$_.Protocol -in @('TCP', 'Any') -and \$_.LocalPort -eq [string]\$Port } |
Select-Object -First 1
if (\$filter) {
return \$true
}
return \$false
}
\$missing = @()
foreach (\$port in \$ports) {
if (-not (Test-PortAllowed \$port)) { \$missing += \$port }
}
if (\$missing.Count -gt 0) {
'missing=' + (\$missing -join ',')
}
" 2>/dev/null | tr -d '\r' | sed -nE 's/^missing=//p' | tail -n 1
}
request_windows_firewall_rules_if_needed() {
local frontend_port="$1"
local backend_port="$2"
local missing_ports=""
local script_path=""
[ "$WINDOWS_LAN_RELAY_ENABLED" -eq 1 ] || return 0
case "${PLANET_WINDOWS_FIREWALL_AUTO_PROMPT:-1}" in
0|false|no|off)
return 0
;;
esac
missing_ports="$(windows_firewall_missing_ports "$frontend_port" "$backend_port" || true)"
[ -n "$missing_ports" ] || return 0
script_path="$PLANET_STATE_DIR/windows_firewall_planet.ps1"
mkdir -p "$PLANET_STATE_DIR"
cat > "$script_path" <<EOF
\$ErrorActionPreference = 'Stop'
\$ports = @(${missing_ports})
foreach (\$port in \$ports) {
\$displayName = "WSL Planet \$port"
\$exists = Get-NetFirewallRule -DisplayName \$displayName -ErrorAction SilentlyContinue |
Where-Object { \$_.Enabled -eq 'True' -and \$_.Direction -eq 'Inbound' -and \$_.Action -eq 'Allow' }
if (-not \$exists) {
New-NetFirewallRule -DisplayName \$displayName -Direction Inbound -Action Allow -Protocol TCP -LocalPort \$port | Out-Null
}
}
Write-Host "Planet firewall rules are ready for ports: \$((\$ports -join ', '))"
Start-Sleep -Seconds 2
EOF
log_warn "检测到 Windows 防火墙可能未放行端口 ${missing_ports},即将请求管理员 PowerShell 添加规则"
run_windows_admin_powershell_script "$script_path" "检测到 Windows 防火墙缺少端口 ${missing_ports} 放行规则" || {
log_warn "管理员 PowerShell 未完成防火墙规则创建;局域网设备可能仍无法访问"
return 1
}
}
windows_portproxy_conflict_ports() {
local frontend_port="$1"
local backend_port="$2"
command -v powershell.exe >/dev/null 2>&1 || return 1
powershell.exe -NoProfile -Command "
\$ErrorActionPreference = 'SilentlyContinue'
\$ports = @([int]${frontend_port}, [int]${backend_port})
\$lines = @(netsh interface portproxy show v4tov4)
\$found = @()
foreach (\$line in \$lines) {
if (\$line -match '^\\s*(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(\\d+)\\s*$') {
\$listenPort = [int]\$Matches[2]
if (\$ports -contains \$listenPort) { \$found += \$listenPort }
}
}
if (\$found.Count -gt 0) {
'conflict=' + ((\$found | Sort-Object -Unique) -join ',')
}
" 2>/dev/null | tr -d '\r' | sed -nE 's/^conflict=//p' | tail -n 1
}
write_windows_portproxy_cleanup_script() {
local script_path="$1"
local frontend_port="$2"
local backend_port="$3"
cat > "$script_path" <<EOF
\$ErrorActionPreference = 'Continue'
\$ports = @([int]${frontend_port}, [int]${backend_port})
\$lines = @(netsh interface portproxy show v4tov4)
\$removed = @()
foreach (\$line in \$lines) {
if (\$line -match '^\\s*(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(\\d+)\\s*$') {
\$listenAddress = \$Matches[1]
\$listenPort = [int]\$Matches[2]
if (\$ports -contains \$listenPort) {
netsh interface portproxy delete v4tov4 listenaddress=\$listenAddress listenport=\$listenPort | Out-Null
\$removed += (\$listenAddress + ':' + \$listenPort)
}
}
}
Write-Host "Planet removed stale portproxy rules: \$((\$removed -join ', '))"
Start-Sleep -Seconds 2
EOF
}
request_windows_portproxy_cleanup_if_needed() {
local frontend_port="$1"
local backend_port="$2"
local conflict_ports=""
local script_path=""
[ "$WINDOWS_LAN_RELAY_ENABLED" -eq 1 ] || return 0
case "${PLANET_WINDOWS_PORTPROXY_CLEANUP_PROMPT:-1}" in
0|false|no|off)
return 0
;;
esac
conflict_ports="$(windows_portproxy_conflict_ports "$frontend_port" "$backend_port" || true)"
[ -n "$conflict_ports" ] || return 0
script_path="$PLANET_STATE_DIR/windows_portproxy_cleanup_planet.ps1"
mkdir -p "$PLANET_STATE_DIR"
write_windows_portproxy_cleanup_script "$script_path" "$frontend_port" "$backend_port"
log_warn "检测到旧 Windows portproxy 占用端口 ${conflict_ports},即将请求管理员 PowerShell 删除"
run_windows_admin_powershell_script "$script_path" "检测到旧 portproxy 占用端口 ${conflict_ports}" || {
log_warn "管理员 PowerShell 未完成旧 portproxy 清理;端口 ${conflict_ports} 可能仍被 iphlpsvc 占用"
return 1
}
}
log_motion_agent_access_notes() {
local motion_agent_port="$1"
local lan_enabled="${2:-0}"
@@ -1351,7 +1587,7 @@ fail_unreleased_port() {
if [ -z "$(collect_port_pids "$port" || true)" ]; then
log_error "端口 ${port} 当前环境内未发现占用进程,但端口仍不可用,请检查宿主机或外部环境占用"
print_port_listener_details "$port"
log_note "如果显示 Windows listener如 svchost.exe / iphlpsvc请优先用管理员 PowerShell 检查 portproxynetsh interface portproxy show all删除冲突转发或改用其他端口。"
log_note "如果显示 Windows listener如 svchost.exe / iphlpsvc请优先用管理员 PowerShell 检查 portproxynetsh interface portproxy show all删除冲突转发后重新启动,--allow-lan 会改用临时 Windows relay。"
else
log_error "端口 ${port} 清理失败,请检查占用进程"
if command -v lsof >/dev/null 2>&1; then
@@ -1360,7 +1596,7 @@ fail_unreleased_port() {
ss -ltnp "( sport = :${port} )" 2>/dev/null || true
fi
print_windows_port_listener_details "$port" || true
log_note "请手动停止占用进程,或改用其他端口。"
log_note "请手动停止占用进程后重试。"
fi
exit 1
@@ -1395,6 +1631,48 @@ retry_wait_for_port_release() {
return 1
}
print_windows_cleanup_recovery_steps() {
local port="$1"
local service_name="$2"
local port_flag
local command_example
case "$service_name" in
前端)
port_flag="-f"
command_example="./planet.sh restart ${port_flag} ${port} --allow-lan"
;;
后端)
port_flag="-b"
command_example="./planet.sh restart ${port_flag} ${port} --allow-lan"
;;
"AI Provider")
port_flag="-a"
command_example="./planet.sh restart ${port_flag} ${port}"
;;
"Motion Agent")
port_flag="--motion-agent-port"
command_example="./planet.sh restart ${port_flag} ${port} --allow-lan"
;;
*)
port_flag=""
command_example="./planet.sh restart --allow-lan"
;;
esac
log_note "Windows 侧端口被 svchost.exe / iphlpsvc 占用时,通常是管理员 PowerShell 中创建过持久 portproxy 规则,例如 listenport=${port}"
log_note "该规则会由 Windows IP Helper 持续监听端口,项目停止后也不会自动消失;下次启动前必须先删除,否则会与 Vite/后端绑定同一端口冲突。"
log_note "请打开“管理员 PowerShell”优先检查并删除冲突 portproxy"
printf "${DIM} netsh interface portproxy show all${NC}\n"
printf "${DIM} netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=%s${NC}\n" "$port"
log_note "如果没有 portproxy 规则,再确认 PID/服务并临时停止对应服务:"
printf "${DIM} netstat -ano | findstr :%s${NC}\n" "$port"
printf "${DIM} tasklist /svc /fi \"PID eq <PID>\"${NC}\n"
printf "${DIM} Stop-Service iphlpsvc -Force${NC}\n"
log_note "如需局域网仍使用 ${port},请删除旧 portproxy 后重新运行 --allow-lan脚本会使用临时 Windows relay 暴露该端口。"
log_note "重新启动示例:${command_example}"
}
force_cleanup_external_port_listener() {
local port="$1"
local service_name="$2"
@@ -1487,6 +1765,7 @@ EOF
log_warn "Windows 侧未发现端口 ${port} 监听,但端口仍不可绑定"
elif [ "$saw_cleanup_failure" -eq 1 ]; then
log_warn "Windows 侧监听清理失败,端口 ${port} 仍不可绑定"
print_windows_cleanup_recovery_steps "$port" "$service_name"
fi
return 1
}
@@ -1885,6 +2164,48 @@ wait_for_port_release() {
return 1
}
get_windows_lan_ipv4() {
command -v powershell.exe >/dev/null 2>&1 || return 1
powershell.exe -NoProfile -Command "
\$ErrorActionPreference = 'SilentlyContinue'
\$route = Get-NetRoute -DestinationPrefix '0.0.0.0/0' |
Where-Object { \$_.NextHop -and \$_.NextHop -ne '0.0.0.0' } |
Sort-Object RouteMetric, InterfaceMetric |
Select-Object -First 1
if (\$route) {
\$ip = Get-NetIPAddress -AddressFamily IPv4 -InterfaceIndex \$route.InterfaceIndex |
Where-Object { \$_.IPAddress -notmatch '^(127|169\\.254)\\.' } |
Select-Object -First 1 -ExpandProperty IPAddress
if (\$ip) { \$ip }
}
" 2>/dev/null | tr -d '\r' | sed -n '1p'
}
prepare_windows_lan_relay_ports() {
local listen_address=""
[ "$FRONTEND_LAN_ENABLED" -eq 1 ] || return 0
is_wsl_environment || return 0
command -v powershell.exe >/dev/null 2>&1 || return 0
[ -f "$WINDOWS_LAN_RELAY_SCRIPT" ] || return 0
listen_address="$(get_windows_lan_ipv4 || true)"
if [ -z "$listen_address" ]; then
log_warn "未能识别 Windows 局域网 IP跳过 Windows 局域网 relay本机 localhost 仍可使用 ${FRONTEND_PORT}/${BACKEND_PORT}"
return 0
fi
WINDOWS_LAN_RELAY_ENABLED=1
LAN_PUBLIC_FRONTEND_PORT="$FRONTEND_PORT"
LAN_PUBLIC_BACKEND_PORT="$BACKEND_PORT"
WINDOWS_LAN_RELAY_LISTEN_ADDRESS="$listen_address"
cleanup_windows_lan_relays
request_windows_portproxy_cleanup_if_needed "$LAN_PUBLIC_FRONTEND_PORT" "$LAN_PUBLIC_BACKEND_PORT" || true
log_note "WSL 局域网 relay: Windows ${WINDOWS_LAN_RELAY_LISTEN_ADDRESS}:${LAN_PUBLIC_FRONTEND_PORT}/${LAN_PUBLIC_BACKEND_PORT} -> localhost:${FRONTEND_PORT}/${BACKEND_PORT}"
}
kill_port_if_requested() {
local port="$1"
local service_name="$2"
@@ -2071,6 +2392,7 @@ start_frontend_with_retry() {
local frontend_port="$1"
local frontend_port_requested="${2:-0}"
local frontend_lan_enabled="${3:-0}"
local backend_port="${4:-$DEFAULT_BACKEND_PORT}"
local retry=1
while [ "$retry" -le "$FRONTEND_MAX_RETRIES" ]; do
@@ -2087,7 +2409,7 @@ start_frontend_with_retry() {
frontend_args+=(--host 0.0.0.0)
fi
frontend_args+=(--port "$frontend_port" --strictPort)
nohup "$FRONTEND_RUNTIME_BIN" "${frontend_args[@]}" > "$FRONTEND_LOG_FILE" 2>&1 &
PLANET_BACKEND_PORT="$backend_port" nohup "$FRONTEND_RUNTIME_BIN" "${frontend_args[@]}" > "$FRONTEND_LOG_FILE" 2>&1 &
FRONTEND_PID=$!
write_pid_file "$FRONTEND_PID_FILE" "$FRONTEND_PID"
@@ -2114,6 +2436,7 @@ start_frontend_service() {
local frontend_port="$1"
local frontend_port_requested="$2"
local frontend_lan_enabled="${3:-0}"
local backend_port="${4:-$DEFAULT_BACKEND_PORT}"
if [ "$frontend_port_requested" -eq 1 ]; then
kill_port_if_requested "$frontend_port" "前端"
@@ -2130,11 +2453,14 @@ start_frontend_service() {
else
set_wait_detail "启动 Vite 开发服务器"
fi
if ! start_frontend_with_retry "$frontend_port" "$frontend_port_requested" "$frontend_lan_enabled"; then
if ! start_frontend_with_retry "$frontend_port" "$frontend_port_requested" "$frontend_lan_enabled" "$backend_port"; then
stop_wait_session
log_error "前端启动失败,已重试 ${FRONTEND_MAX_RETRIES}"
tail -10 "$FRONTEND_LOG_FILE"
print_port_listener_details "$frontend_port"
if frontend_log_indicates_port_conflict "$FRONTEND_LOG_FILE"; then
print_windows_cleanup_recovery_steps "$frontend_port" "前端"
fi
exit 1
fi
stop_wait_session
@@ -2485,6 +2811,7 @@ cleanup_failed_start() {
clear_wait_spinner
log_warn "启动未完成,清理本轮已拉起的本地进程"
cleanup_windows_lan_relays
if [ "$STARTED_MOTION_AGENT_THIS_RUN" -eq 1 ]; then
cleanup_motion_agent_processes TERM
@@ -2605,6 +2932,7 @@ PY
# Top-level commands
start() {
parse_service_args "$@"
prepare_windows_lan_relay_ports
cleanup_exit_containers
START_RUN_ACTIVE=1
@@ -2617,7 +2945,7 @@ start() {
start_backend_service "$BACKEND_PORT" "$BACKEND_PORT_REQUESTED" "$AI_PROVIDER_PORT"
STARTED_BACKEND_THIS_RUN=1
start_frontend_service "$FRONTEND_PORT" "$FRONTEND_PORT_REQUESTED" "$FRONTEND_LAN_ENABLED"
start_frontend_service "$FRONTEND_PORT" "$FRONTEND_PORT_REQUESTED" "$FRONTEND_LAN_ENABLED" "$BACKEND_PORT"
STARTED_FRONTEND_THIS_RUN=1
if [ "$MOTION_AGENT_REQUESTED" -eq 1 ]; then
start_motion_agent_service "$MOTION_AGENT_PORT" "$MOTION_AGENT_DRY_RUN" "$FRONTEND_LAN_ENABLED"
@@ -2625,24 +2953,37 @@ start() {
fi
write_port_state "$BACKEND_PORT" "$FRONTEND_PORT" "$AI_PROVIDER_PORT" "$MOTION_AGENT_PORT"
if [ "$WINDOWS_LAN_RELAY_ENABLED" -eq 1 ]; then
start_windows_lan_relays
request_windows_firewall_rules_if_needed "$LAN_PUBLIC_FRONTEND_PORT" "$LAN_PUBLIC_BACKEND_PORT" || true
fi
START_RUN_COMPLETED=1
START_RUN_ACTIVE=0
log_success "启动完成"
log_note "智能星球计划: http://localhost:${FRONTEND_PORT}/earth"
log_note "智能星球仪表盘: http://localhost:${FRONTEND_PORT}/admin"
log_note "AI Playground: http://localhost:${FRONTEND_PORT}/playground"
log_note "智能星球开发文档: http://localhost:${BACKEND_PORT}/docs"
if [ "$WINDOWS_LAN_RELAY_ENABLED" -eq 1 ]; then
log_note "智能星球计划: http://localhost:${LAN_PUBLIC_FRONTEND_PORT}/earth"
log_note "智能星球仪表盘: http://localhost:${LAN_PUBLIC_FRONTEND_PORT}/admin"
log_note "AI Playground: http://localhost:${LAN_PUBLIC_FRONTEND_PORT}/playground"
log_note "智能星球开发文档: http://localhost:${LAN_PUBLIC_BACKEND_PORT}/docs"
log_note "局域网入口: http://${WINDOWS_LAN_RELAY_LISTEN_ADDRESS}:${LAN_PUBLIC_FRONTEND_PORT}/earth"
else
log_note "智能星球计划: http://localhost:${FRONTEND_PORT}/earth"
log_note "智能星球仪表盘: http://localhost:${FRONTEND_PORT}/admin"
log_note "AI Playground: http://localhost:${FRONTEND_PORT}/playground"
log_note "智能星球开发文档: http://localhost:${BACKEND_PORT}/docs"
fi
if [ "$MOTION_AGENT_REQUESTED" -eq 1 ]; then
log_motion_agent_access_notes "$MOTION_AGENT_PORT" "$FRONTEND_LAN_ENABLED"
fi
if [ "$FRONTEND_LAN_ENABLED" -eq 1 ]; then
log_lan_access_notes "$FRONTEND_PORT" "$BACKEND_PORT"
if [ "$FRONTEND_LAN_ENABLED" -eq 1 ] && [ "$WINDOWS_LAN_RELAY_ENABLED" -eq 0 ]; then
log_lan_access_notes "$FRONTEND_PORT" "$BACKEND_PORT" "$LAN_PUBLIC_FRONTEND_PORT" "$LAN_PUBLIC_BACKEND_PORT"
fi
}
stop() {
log_warn "停止服务"
cleanup_windows_lan_relays
stop_backend_service
stop_ai_provider_service
stop_frontend_service
@@ -2688,7 +3029,7 @@ restart() {
if [ "$FRONTEND_PORT_REQUESTED" -eq 1 ]; then
stop_frontend_service
sleep 1
start_frontend_service "$FRONTEND_PORT" 1 "$FRONTEND_LAN_ENABLED"
start_frontend_service "$FRONTEND_PORT" 1 "$FRONTEND_LAN_ENABLED" "$BACKEND_PORT"
fi
if [ "$MOTION_AGENT_REQUESTED" -eq 1 ]; then