forked from linkong/planet
release: bump version to 0.53.0
This commit is contained in:
440
planet.sh
440
planet.sh
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env zsh
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_PATH="${(%):-%N}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
|
||||
@@ -81,10 +82,12 @@ VERBOSE=0
|
||||
WAIT_VERBOSE_LOG_FILE=""
|
||||
WAIT_VERBOSE_LINE_COUNT="${WAIT_VERBOSE_LINE_COUNT:-5}"
|
||||
WAIT_VERBOSE_TAIL_LINE_COUNT="${WAIT_VERBOSE_TAIL_LINE_COUNT:-40}"
|
||||
HTTP_CHECK_MAX_TIME="${HTTP_CHECK_MAX_TIME:-0.2}"
|
||||
WAIT_VERBOSE_LAST_LOG_FILE=""
|
||||
WAIT_VERBOSE_EMITTED_LINES=0
|
||||
HTTP_CHECK_MAX_TIME="${HTTP_CHECK_MAX_TIME:-2}"
|
||||
|
||||
BACKEND_MAX_RETRIES="${BACKEND_MAX_RETRIES:-3}"
|
||||
BACKEND_HEALTH_CHECK_ATTEMPTS="${BACKEND_HEALTH_CHECK_ATTEMPTS:-10}"
|
||||
BACKEND_HEALTH_CHECK_ATTEMPTS="${BACKEND_HEALTH_CHECK_ATTEMPTS:-60}"
|
||||
BACKEND_HEALTH_CHECK_INTERVAL="${BACKEND_HEALTH_CHECK_INTERVAL:-2}"
|
||||
DEPENDENCY_INSTALL_MAX_RETRIES="${DEPENDENCY_INSTALL_MAX_RETRIES:-3}"
|
||||
DEPENDENCY_INSTALL_RETRY_INTERVAL="${DEPENDENCY_INSTALL_RETRY_INTERVAL:-5}"
|
||||
@@ -94,6 +97,8 @@ AI_PROVIDER_START_MAX_RETRIES="${AI_PROVIDER_START_MAX_RETRIES:-3}"
|
||||
AI_PROVIDER_RETRY_INTERVAL="${AI_PROVIDER_RETRY_INTERVAL:-5}"
|
||||
DATABASE_START_MAX_RETRIES="${DATABASE_START_MAX_RETRIES:-3}"
|
||||
DATABASE_RETRY_INTERVAL="${DATABASE_RETRY_INTERVAL:-5}"
|
||||
DATABASE_HEALTH_CHECK_ATTEMPTS="${DATABASE_HEALTH_CHECK_ATTEMPTS:-10}"
|
||||
DATABASE_HEALTH_CHECK_INTERVAL="${DATABASE_HEALTH_CHECK_INTERVAL:-$DATABASE_RETRY_INTERVAL}"
|
||||
FRONTEND_MAX_RETRIES="${FRONTEND_MAX_RETRIES:-3}"
|
||||
FRONTEND_HEALTH_CHECK_ATTEMPTS="${FRONTEND_HEALTH_CHECK_ATTEMPTS:-10}"
|
||||
FRONTEND_HEALTH_CHECK_INTERVAL="${FRONTEND_HEALTH_CHECK_INTERVAL:-2}"
|
||||
@@ -107,16 +112,27 @@ DEFAULT_AI_PROVIDER_PORT="${DEFAULT_AI_PROVIDER_PORT:-8010}"
|
||||
DEFAULT_MOTION_AGENT_PORT="${DEFAULT_MOTION_AGENT_PORT:-8765}"
|
||||
FRONTEND_RUNTIME_BIN="${FRONTEND_RUNTIME_BIN:-}"
|
||||
FRONTEND_RUNTIME_SOURCE="${FRONTEND_RUNTIME_SOURCE:-}"
|
||||
FRONTEND_PID_FILE="/tmp/planet_frontend.pid"
|
||||
PLANET_STATE_DIR="${PLANET_STATE_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/planet}"
|
||||
PLANET_CACHE_DIR="${PLANET_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/planet}"
|
||||
BACKEND_PID_FILE="$PLANET_STATE_DIR/backend.pid"
|
||||
BACKEND_LOG_FILE="$PLANET_STATE_DIR/backend.log"
|
||||
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"
|
||||
MOTION_AGENT_PID_FILE="/tmp/planet_motion_agent.pid"
|
||||
MOTION_AGENT_LOG_FILE="/tmp/planet_motion_agent.log"
|
||||
AI_PROVIDER_BUILD_STAMP_FILE="$HOME/.cache/planet/aiprovider_build.sha256"
|
||||
AI_PROVIDER_BUILD_LOG_FILE="/tmp/planet_aiprovider_build.log"
|
||||
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"
|
||||
AI_PROVIDER_BUILD_LOG_FILE="$PLANET_STATE_DIR/aiprovider_build.log"
|
||||
AI_PROVIDER_IMAGE_NAME="${AI_PROVIDER_IMAGE_NAME:-planet_aiprovider:latest}"
|
||||
AI_PROVIDER_CONTAINER_NAME="${AI_PROVIDER_CONTAINER_NAME:-planet_aiprovider}"
|
||||
PLANET_AI_PROVIDER_RUNTIME_ENV_FILE="${PLANET_AI_PROVIDER_RUNTIME_ENV_FILE:-/tmp/planet_aiprovider_runtime.env}"
|
||||
PLANET_AI_PROVIDER_RUNTIME_ENV_FILE="${PLANET_AI_PROVIDER_RUNTIME_ENV_FILE:-$PLANET_STATE_DIR/aiprovider_runtime.env}"
|
||||
AI_PROVIDER_RECREATE_REQUIRED=0
|
||||
START_RUN_ACTIVE=0
|
||||
START_RUN_COMPLETED=0
|
||||
STARTED_BACKEND_THIS_RUN=0
|
||||
STARTED_FRONTEND_THIS_RUN=0
|
||||
STARTED_MOTION_AGENT_THIS_RUN=0
|
||||
AI_PROVIDER_RUNTIME_ENV_NAMES=(
|
||||
SERVICE_NAME
|
||||
SERVICE_VERSION
|
||||
@@ -133,6 +149,9 @@ AI_PROVIDER_RUNTIME_ENV_NAMES=(
|
||||
AI_PROVIDER_SERVICE_TOKEN
|
||||
)
|
||||
|
||||
mkdir -p "$PLANET_STATE_DIR" "$PLANET_CACHE_DIR"
|
||||
chmod 700 "$PLANET_STATE_DIR" "$PLANET_CACHE_DIR" 2>/dev/null || true
|
||||
|
||||
prepend_path_once() {
|
||||
local path_entry="$1"
|
||||
[ -n "$path_entry" ] || return 0
|
||||
@@ -152,6 +171,98 @@ ensure_local_runtime_bins_on_path() {
|
||||
ensure_local_runtime_bins_on_path
|
||||
|
||||
# Shell / Docker helpers
|
||||
is_pid() {
|
||||
[[ "${1:-}" =~ ^[0-9]+$ ]] && [ "$1" -gt 0 ]
|
||||
}
|
||||
|
||||
is_safe_signal() {
|
||||
case "${1:-}" in
|
||||
TERM|KILL|INT|HUP)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
read_pid_file() {
|
||||
local pid_file="$1"
|
||||
local pid=""
|
||||
|
||||
[ -f "$pid_file" ] || return 1
|
||||
pid="$(head -n 1 "$pid_file" 2>/dev/null | tr -d '[:space:]' || true)"
|
||||
is_pid "$pid" || return 1
|
||||
printf "%s\n" "$pid"
|
||||
}
|
||||
|
||||
write_pid_file() {
|
||||
local pid_file="$1"
|
||||
local pid="$2"
|
||||
|
||||
is_pid "$pid" || return 1
|
||||
mkdir -p "$(dirname "$pid_file")"
|
||||
printf "%s\n" "$pid" > "$pid_file"
|
||||
chmod 600 "$pid_file" 2>/dev/null || true
|
||||
}
|
||||
|
||||
remove_pid_file() {
|
||||
local pid_file="$1"
|
||||
|
||||
rm -f "$pid_file"
|
||||
}
|
||||
|
||||
http_ok() {
|
||||
local url="$1"
|
||||
|
||||
curl -fsS --max-time "$HTTP_CHECK_MAX_TIME" "$url" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
log_matches() {
|
||||
local log_file="$1"
|
||||
shift
|
||||
|
||||
[ -f "$log_file" ] || return 1
|
||||
[ "$#" -gt 0 ] || return 1
|
||||
grep -Eiq "$*" "$log_file" 2>/dev/null
|
||||
}
|
||||
|
||||
read_port_state_value() {
|
||||
local key="$1"
|
||||
local fallback="$2"
|
||||
local value=""
|
||||
|
||||
if [ -f "$PLANET_PORT_STATE_FILE" ]; then
|
||||
value="$(sed -nE "s/^${key}=([0-9]+)$/\\1/p" "$PLANET_PORT_STATE_FILE" | tail -n 1)"
|
||||
fi
|
||||
|
||||
if [ -n "$value" ]; then
|
||||
printf "%s" "$value"
|
||||
else
|
||||
printf "%s" "$fallback"
|
||||
fi
|
||||
}
|
||||
|
||||
write_port_state() {
|
||||
local backend_port="$1"
|
||||
local frontend_port="$2"
|
||||
local ai_provider_port="$3"
|
||||
local motion_agent_port="$4"
|
||||
|
||||
validate_port "$backend_port"
|
||||
validate_port "$frontend_port"
|
||||
validate_port "$ai_provider_port"
|
||||
validate_port "$motion_agent_port"
|
||||
|
||||
{
|
||||
printf "BACKEND_PORT=%s\n" "$backend_port"
|
||||
printf "FRONTEND_PORT=%s\n" "$frontend_port"
|
||||
printf "AI_PROVIDER_PORT=%s\n" "$ai_provider_port"
|
||||
printf "MOTION_AGENT_PORT=%s\n" "$motion_agent_port"
|
||||
} > "$PLANET_PORT_STATE_FILE"
|
||||
chmod 600 "$PLANET_PORT_STATE_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
compose_available() {
|
||||
docker compose version >/dev/null 2>&1
|
||||
}
|
||||
@@ -253,36 +364,10 @@ render_wait_spinner() {
|
||||
local frame_index=$(( (step - 1) % ${#WAIT_SPINNER_FRAMES[@]} ))
|
||||
local frame="${WAIT_SPINNER_FRAMES[$frame_index]}"
|
||||
local detail="${WAIT_SPINNER_DETAIL:- }"
|
||||
local verbose_line=""
|
||||
local verbose_lines=()
|
||||
local line_count=0
|
||||
local cursor_up=1
|
||||
|
||||
if [ "$VERBOSE" -eq 1 ] && [ -n "$WAIT_VERBOSE_LOG_FILE" ] && [ -f "$WAIT_VERBOSE_LOG_FILE" ]; then
|
||||
while IFS= read -r verbose_line; do
|
||||
verbose_line="$(sanitize_wait_detail "$verbose_line")"
|
||||
[ -n "$verbose_line" ] || continue
|
||||
verbose_lines+=("$verbose_line")
|
||||
done < <(tail -n "$WAIT_VERBOSE_TAIL_LINE_COUNT" "$WAIT_VERBOSE_LOG_FILE" 2>/dev/null)
|
||||
|
||||
while [ "${#verbose_lines[@]}" -gt "$WAIT_VERBOSE_LINE_COUNT" ]; do
|
||||
verbose_lines=("${verbose_lines[@]:1}")
|
||||
done
|
||||
fi
|
||||
flush_wait_verbose_log
|
||||
|
||||
printf "\r${DIM}·${NC} ${CYAN}%-2s${NC} ${WHITE}%s${NC}\033[K\n${DIM} %s${NC}\033[K" "$frame" "$message" "$detail" >&2
|
||||
|
||||
if [ "$VERBOSE" -eq 1 ]; then
|
||||
line_count=1
|
||||
while [ "$line_count" -le "$WAIT_VERBOSE_LINE_COUNT" ]; do
|
||||
verbose_line="${verbose_lines[$line_count]:- }"
|
||||
printf "\n${DIM} %s${NC}\033[K" "$verbose_line" >&2
|
||||
line_count=$((line_count + 1))
|
||||
done
|
||||
cursor_up=$((WAIT_VERBOSE_LINE_COUNT + 1))
|
||||
fi
|
||||
|
||||
printf "\033[%sA\r" "$cursor_up" >&2
|
||||
printf "\033[1A\r" >&2
|
||||
}
|
||||
|
||||
animate_wait_spinner() {
|
||||
@@ -305,11 +390,6 @@ animate_wait_spinner() {
|
||||
|
||||
clear_wait_spinner() {
|
||||
local line_count=0
|
||||
local clear_verbose_lines=0
|
||||
|
||||
if [ "$VERBOSE" -eq 1 ] && { [ "$WAIT_SESSION_ACTIVE" -eq 1 ] || [ -n "$WAIT_VERBOSE_LOG_FILE" ]; }; then
|
||||
clear_verbose_lines=1
|
||||
fi
|
||||
|
||||
printf "\r\033[K" >&2
|
||||
line_count=0
|
||||
@@ -318,15 +398,8 @@ clear_wait_spinner() {
|
||||
line_count=$((line_count + 1))
|
||||
done
|
||||
|
||||
if [ "$clear_verbose_lines" -eq 1 ]; then
|
||||
line_count=0
|
||||
while [ "$line_count" -lt "$WAIT_VERBOSE_LINE_COUNT" ]; do
|
||||
printf "\n\033[K" >&2
|
||||
line_count=$((line_count + 1))
|
||||
done
|
||||
fi
|
||||
|
||||
printf "\033[%sA\r" "$((clear_verbose_lines == 1 ? WAIT_VERBOSE_LINE_COUNT + 1 : 1))" >&2
|
||||
printf "\033[1A\r" >&2
|
||||
flush_wait_verbose_log
|
||||
}
|
||||
|
||||
start_wait_session() {
|
||||
@@ -366,6 +439,8 @@ reset_wait_spinner_state() {
|
||||
WAIT_SPINNER_DETAIL=""
|
||||
WAIT_SPINNER_MESSAGE=""
|
||||
WAIT_VERBOSE_LOG_FILE=""
|
||||
WAIT_VERBOSE_LAST_LOG_FILE=""
|
||||
WAIT_VERBOSE_EMITTED_LINES=0
|
||||
}
|
||||
|
||||
sanitize_wait_detail() {
|
||||
@@ -382,6 +457,39 @@ sanitize_wait_detail() {
|
||||
printf "%s" "$line"
|
||||
}
|
||||
|
||||
flush_wait_verbose_log() {
|
||||
local line=""
|
||||
local line_number=0
|
||||
local total_lines=0
|
||||
|
||||
[ "$VERBOSE" -eq 1 ] || return 0
|
||||
[ -n "$WAIT_VERBOSE_LOG_FILE" ] || return 0
|
||||
[ -f "$WAIT_VERBOSE_LOG_FILE" ] || return 0
|
||||
|
||||
if [ "$WAIT_VERBOSE_LAST_LOG_FILE" != "$WAIT_VERBOSE_LOG_FILE" ]; then
|
||||
WAIT_VERBOSE_LAST_LOG_FILE="$WAIT_VERBOSE_LOG_FILE"
|
||||
WAIT_VERBOSE_EMITTED_LINES=0
|
||||
fi
|
||||
|
||||
total_lines="$(wc -l < "$WAIT_VERBOSE_LOG_FILE" 2>/dev/null | tr -d '[:space:]')"
|
||||
[ -n "$total_lines" ] || total_lines=0
|
||||
if [ "$total_lines" -lt "$WAIT_VERBOSE_EMITTED_LINES" ]; then
|
||||
WAIT_VERBOSE_EMITTED_LINES=0
|
||||
fi
|
||||
[ "$total_lines" -gt "$WAIT_VERBOSE_EMITTED_LINES" ] || return 0
|
||||
|
||||
printf "\r\033[K" >&2
|
||||
while IFS= read -r line; do
|
||||
line_number=$((line_number + 1))
|
||||
[ "$line_number" -gt "$WAIT_VERBOSE_EMITTED_LINES" ] || continue
|
||||
line="$(sanitize_wait_detail "$line")"
|
||||
[ -n "$line" ] || continue
|
||||
printf "${DIM} %s${NC}\n" "$line" >&2
|
||||
done < "$WAIT_VERBOSE_LOG_FILE"
|
||||
|
||||
WAIT_VERBOSE_EMITTED_LINES="$total_lines"
|
||||
}
|
||||
|
||||
set_wait_detail() {
|
||||
WAIT_SPINNER_DETAIL="$(sanitize_wait_detail "$1")"
|
||||
if [ "$WAIT_SESSION_ACTIVE" -eq 1 ] && [ -n "$WAIT_SPINNER_MESSAGE" ]; then
|
||||
@@ -400,7 +508,7 @@ run_command_with_spinner() {
|
||||
fi
|
||||
|
||||
if [ "$VERBOSE" -eq 1 ]; then
|
||||
verbose_log_file="$(mktemp /tmp/planet_verbose.XXXXXX.log)"
|
||||
verbose_log_file="$(mktemp "$PLANET_STATE_DIR/verbose.XXXXXX.log")"
|
||||
WAIT_VERBOSE_LOG_FILE="$verbose_log_file"
|
||||
"$@" > "$verbose_log_file" 2>&1 &
|
||||
else
|
||||
@@ -494,7 +602,13 @@ log_error() {
|
||||
}
|
||||
|
||||
log_note() {
|
||||
if [ "$WAIT_SESSION_ACTIVE" -eq 1 ]; then
|
||||
clear_wait_spinner
|
||||
fi
|
||||
printf "${DIM} %s${NC}\n" "$1"
|
||||
if [ "$WAIT_SESSION_ACTIVE" -eq 1 ]; then
|
||||
resume_wait_session
|
||||
fi
|
||||
}
|
||||
|
||||
log_success() {
|
||||
@@ -704,7 +818,7 @@ remove_ai_provider_containers() {
|
||||
local container_ids
|
||||
container_ids="$(list_ai_provider_containers)"
|
||||
[ -n "$container_ids" ] || return 0
|
||||
echo "$container_ids" | xargs -r docker rm -f >/dev/null 2>&1 || true
|
||||
printf "%s\n" "$container_ids" | awk '/^[0-9a-f]{12,64}$/' | xargs -r docker rm -f >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
run_ai_provider_container_manually() {
|
||||
@@ -1086,7 +1200,7 @@ wait_for_http() {
|
||||
set_wait_detail "${wait_detail_prefix} ${url} (1/${attempts})"
|
||||
|
||||
while [ "$attempt" -le "$attempts" ]; do
|
||||
if curl -s --max-time "$HTTP_CHECK_MAX_TIME" "$url" > /dev/null 2>&1; then
|
||||
if http_ok "$url"; then
|
||||
finish_wait_spinner "${service_name}已就绪"
|
||||
return 0
|
||||
fi
|
||||
@@ -1179,7 +1293,7 @@ wait_for_frontend_ready() {
|
||||
fi
|
||||
|
||||
if [ $(( tick % probe_every_ticks )) -eq 0 ] &&
|
||||
curl -s --max-time "$HTTP_CHECK_MAX_TIME" "http://localhost:${frontend_port}" > /dev/null 2>&1; then
|
||||
http_ok "http://localhost:${frontend_port}"; then
|
||||
if [ "$owns_wait_session" -eq 1 ]; then
|
||||
stop_wait_session
|
||||
finish_wait_spinner "前端已就绪"
|
||||
@@ -1289,6 +1403,7 @@ force_cleanup_external_port_listener() {
|
||||
local saw_no_windows_listener=0
|
||||
local saw_cleanup_failure=0
|
||||
|
||||
validate_port "$port"
|
||||
is_wsl_environment || return 1
|
||||
command -v powershell.exe >/dev/null 2>&1 || return 1
|
||||
|
||||
@@ -1378,12 +1493,12 @@ EOF
|
||||
|
||||
# Service startup helpers
|
||||
wait_for_database_health() {
|
||||
wait_for_container_health "planet_postgres" "$AI_PROVIDER_HEALTH_CHECK_ATTEMPTS" "$DATABASE_RETRY_INTERVAL" "PostgreSQL" &&
|
||||
wait_for_container_health "planet_redis" "$AI_PROVIDER_HEALTH_CHECK_ATTEMPTS" "$DATABASE_RETRY_INTERVAL" "Redis"
|
||||
wait_for_container_health "planet_postgres" "$DATABASE_HEALTH_CHECK_ATTEMPTS" "$DATABASE_HEALTH_CHECK_INTERVAL" "PostgreSQL" &&
|
||||
wait_for_container_health "planet_redis" "$DATABASE_HEALTH_CHECK_ATTEMPTS" "$DATABASE_HEALTH_CHECK_INTERVAL" "Redis"
|
||||
}
|
||||
|
||||
wait_for_postgres_health() {
|
||||
wait_for_container_health "planet_postgres" "$AI_PROVIDER_HEALTH_CHECK_ATTEMPTS" "$DATABASE_RETRY_INTERVAL" "PostgreSQL"
|
||||
wait_for_container_health "planet_postgres" "$DATABASE_HEALTH_CHECK_ATTEMPTS" "$DATABASE_HEALTH_CHECK_INTERVAL" "PostgreSQL"
|
||||
}
|
||||
|
||||
start_database_services() {
|
||||
@@ -1401,6 +1516,19 @@ start_postgres_service() {
|
||||
# Backend lifecycle helpers
|
||||
cleanup_backend_processes() {
|
||||
local backend_port="${1:-$DEFAULT_BACKEND_PORT}"
|
||||
local tracked_pid=""
|
||||
|
||||
if [ -f "$BACKEND_PID_FILE" ]; then
|
||||
if tracked_pid="$(read_pid_file "$BACKEND_PID_FILE")"; then
|
||||
terminate_process_group TERM "$tracked_pid"
|
||||
terminate_process_tree TERM "$tracked_pid"
|
||||
sleep 1
|
||||
terminate_process_group KILL "$tracked_pid"
|
||||
terminate_process_tree KILL "$tracked_pid"
|
||||
fi
|
||||
remove_pid_file "$BACKEND_PID_FILE"
|
||||
fi
|
||||
|
||||
terminate_backend_processes TERM "$backend_port"
|
||||
|
||||
if ! wait_for_port_release "$backend_port" 15 0.2; then
|
||||
@@ -1424,11 +1552,12 @@ start_backend_with_retry() {
|
||||
fail_unreleased_port "$backend_port"
|
||||
fi
|
||||
cd "$SCRIPT_DIR/backend"
|
||||
: > /tmp/planet_backend.log
|
||||
PYTHONPATH="$SCRIPT_DIR/backend" nohup uv run --project "$SCRIPT_DIR" python -m uvicorn app.main:app --host 0.0.0.0 --port "$backend_port" --reload > /tmp/planet_backend.log 2>&1 &
|
||||
: > "$BACKEND_LOG_FILE"
|
||||
PYTHONPATH="$SCRIPT_DIR/backend" nohup uv run --project "$SCRIPT_DIR" python -m uvicorn app.main:app --host 0.0.0.0 --port "$backend_port" --reload > "$BACKEND_LOG_FILE" 2>&1 &
|
||||
BACKEND_PID=$!
|
||||
write_pid_file "$BACKEND_PID_FILE" "$BACKEND_PID"
|
||||
if [ "$VERBOSE" -eq 1 ]; then
|
||||
WAIT_VERBOSE_LOG_FILE="/tmp/planet_backend.log"
|
||||
WAIT_VERBOSE_LOG_FILE="$BACKEND_LOG_FILE"
|
||||
fi
|
||||
|
||||
if wait_for_http "http://localhost:${backend_port}/health" "$BACKEND_HEALTH_CHECK_ATTEMPTS" "$BACKEND_HEALTH_CHECK_INTERVAL" "后端"; then
|
||||
@@ -1436,14 +1565,14 @@ start_backend_with_retry() {
|
||||
fi
|
||||
|
||||
kill "$BACKEND_PID" 2>/dev/null || true
|
||||
if backend_log_indicates_port_conflict "/tmp/planet_backend.log"; then
|
||||
if backend_log_indicates_port_conflict "$BACKEND_LOG_FILE"; then
|
||||
cleanup_backend_processes "$backend_port" || fail_unreleased_port "$backend_port"
|
||||
if wait_for_port_release "$backend_port" 5 0.2; then
|
||||
log_warn "后端端口冲突已清理,立即重试启动"
|
||||
retry=$((retry + 1))
|
||||
continue
|
||||
fi
|
||||
report_backend_port_conflict_if_needed "$backend_port" "/tmp/planet_backend.log"
|
||||
report_backend_port_conflict_if_needed "$backend_port" "$BACKEND_LOG_FILE"
|
||||
return 1
|
||||
fi
|
||||
animate_wait_spinner "后端第 ${retry}/${BACKEND_MAX_RETRIES} 次启动未就绪,准备重试" "$BACKEND_HEALTH_CHECK_INTERVAL"
|
||||
@@ -1451,7 +1580,7 @@ start_backend_with_retry() {
|
||||
done
|
||||
|
||||
clear_wait_spinner
|
||||
report_backend_port_conflict_if_needed "$backend_port" "/tmp/planet_backend.log" || true
|
||||
report_backend_port_conflict_if_needed "$backend_port" "$BACKEND_LOG_FILE" || true
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -1500,8 +1629,7 @@ ai_provider_service_healthy() {
|
||||
local ai_provider_port="${1:-$DEFAULT_AI_PROVIDER_PORT}"
|
||||
|
||||
docker inspect "$AI_PROVIDER_CONTAINER_NAME" >/dev/null 2>&1 || return 1
|
||||
curl -s --max-time "$HTTP_CHECK_MAX_TIME" \
|
||||
"http://localhost:${ai_provider_port}/health" >/dev/null 2>&1
|
||||
http_ok "http://localhost:${ai_provider_port}/health"
|
||||
}
|
||||
|
||||
ensure_database_services_healthy() {
|
||||
@@ -1596,7 +1724,7 @@ start_backend_service() {
|
||||
ensure_uv_backend_deps
|
||||
if ! start_backend_with_retry "$backend_port"; then
|
||||
log_error "后端启动失败,已重试 ${BACKEND_MAX_RETRIES} 次"
|
||||
tail -10 /tmp/planet_backend.log
|
||||
tail -10 "$BACKEND_LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -1650,11 +1778,12 @@ terminate_process_group() {
|
||||
local pid="$2"
|
||||
local pgid=""
|
||||
|
||||
[ -n "$pid" ] || return 0
|
||||
is_safe_signal "$signal" || return 1
|
||||
is_pid "$pid" || return 0
|
||||
kill -0 "$pid" 2>/dev/null || return 0
|
||||
|
||||
pgid="$(ps -o pgid= -p "$pid" 2>/dev/null | tr -d '[:space:]')"
|
||||
[ -n "$pgid" ] || return 0
|
||||
is_pid "$pgid" || return 0
|
||||
|
||||
kill "-${signal}" -- "-${pgid}" 2>/dev/null || true
|
||||
}
|
||||
@@ -1665,7 +1794,7 @@ terminate_backend_processes() {
|
||||
local pids=""
|
||||
local pid=""
|
||||
|
||||
pids="$(pgrep -f "uvicorn" 2>/dev/null || true)"
|
||||
pids="$(pgrep -f "uvicorn .*--port ${backend_port}" 2>/dev/null || true)"
|
||||
for pid in $pids; do
|
||||
terminate_process_group "$signal" "$pid"
|
||||
terminate_process_tree "$signal" "$pid"
|
||||
@@ -1683,12 +1812,13 @@ terminate_process_tree() {
|
||||
local pid="$2"
|
||||
local child_pid
|
||||
|
||||
[ -n "$pid" ] || return 0
|
||||
is_safe_signal "$signal" || return 1
|
||||
is_pid "$pid" || return 0
|
||||
kill -0 "$pid" 2>/dev/null || return 0
|
||||
|
||||
if command -v pgrep >/dev/null 2>&1; then
|
||||
while IFS= read -r child_pid; do
|
||||
[ -n "$child_pid" ] || continue
|
||||
is_pid "$child_pid" || continue
|
||||
terminate_process_tree "$signal" "$child_pid"
|
||||
done < <(pgrep -P "$pid" 2>/dev/null || true)
|
||||
fi
|
||||
@@ -1821,15 +1951,13 @@ kill_port_if_requested() {
|
||||
frontend_log_indicates_port_conflict() {
|
||||
local log_file="$1"
|
||||
|
||||
[ -f "$log_file" ] || return 1
|
||||
grep -q "Port .* is already in use" "$log_file" 2>/dev/null
|
||||
log_matches "$log_file" "Port .* is already in use"
|
||||
}
|
||||
|
||||
backend_log_indicates_port_conflict() {
|
||||
local log_file="$1"
|
||||
|
||||
[ -f "$log_file" ] || return 1
|
||||
grep -Eiq "Address already in use|Errno 98" "$log_file" 2>/dev/null
|
||||
log_matches "$log_file" "Address already in use|Errno 98"
|
||||
}
|
||||
|
||||
print_windows_port_listener_details() {
|
||||
@@ -1927,18 +2055,16 @@ cleanup_frontend_processes() {
|
||||
local tracked_pid=""
|
||||
|
||||
if [ -f "$FRONTEND_PID_FILE" ]; then
|
||||
tracked_pid="$(cat "$FRONTEND_PID_FILE" 2>/dev/null || true)"
|
||||
if [ -n "$tracked_pid" ]; then
|
||||
if tracked_pid="$(read_pid_file "$FRONTEND_PID_FILE")"; then
|
||||
terminate_process_tree TERM "$tracked_pid"
|
||||
sleep 1
|
||||
terminate_process_tree KILL "$tracked_pid"
|
||||
fi
|
||||
rm -f "$FRONTEND_PID_FILE"
|
||||
remove_pid_file "$FRONTEND_PID_FILE"
|
||||
fi
|
||||
|
||||
pkill -f "${FRONTEND_VITE_ENTRY} --port ${frontend_port} --strictPort" 2>/dev/null || true
|
||||
pkill -f "${FRONTEND_VITE_ENTRY} --host 0.0.0.0 --port ${frontend_port} --strictPort" 2>/dev/null || true
|
||||
pkill -f "${FRONTEND_VITE_ENTRY}" 2>/dev/null || true
|
||||
}
|
||||
|
||||
start_frontend_with_retry() {
|
||||
@@ -1954,25 +2080,25 @@ start_frontend_with_retry() {
|
||||
log_warn "前端端口 ${frontend_port} 预清理后仍需由 Vite 启动流程确认"
|
||||
fi
|
||||
cd "$SCRIPT_DIR/frontend"
|
||||
: > /tmp/planet_frontend.log
|
||||
: > "$FRONTEND_LOG_FILE"
|
||||
local -a frontend_args
|
||||
frontend_args=("$FRONTEND_VITE_ENTRY")
|
||||
if [ "$frontend_lan_enabled" -eq 1 ]; then
|
||||
frontend_args+=(--host 0.0.0.0)
|
||||
fi
|
||||
frontend_args+=(--port "$frontend_port" --strictPort)
|
||||
nohup "$FRONTEND_RUNTIME_BIN" "${frontend_args[@]}" > /tmp/planet_frontend.log 2>&1 &
|
||||
nohup "$FRONTEND_RUNTIME_BIN" "${frontend_args[@]}" > "$FRONTEND_LOG_FILE" 2>&1 &
|
||||
FRONTEND_PID=$!
|
||||
printf "%s" "$FRONTEND_PID" > "$FRONTEND_PID_FILE"
|
||||
write_pid_file "$FRONTEND_PID_FILE" "$FRONTEND_PID"
|
||||
|
||||
if wait_for_frontend_ready "$frontend_port" "$FRONTEND_PID" "/tmp/planet_frontend.log" "$FRONTEND_HEALTH_CHECK_ATTEMPTS" "$FRONTEND_HEALTH_CHECK_INTERVAL"; then
|
||||
if wait_for_frontend_ready "$frontend_port" "$FRONTEND_PID" "$FRONTEND_LOG_FILE" "$FRONTEND_HEALTH_CHECK_ATTEMPTS" "$FRONTEND_HEALTH_CHECK_INTERVAL"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
cleanup_frontend_processes "$frontend_port"
|
||||
reset_wait_spinner_state
|
||||
|
||||
if [ "$frontend_port_requested" -eq 1 ] && frontend_log_indicates_port_conflict "/tmp/planet_frontend.log"; then
|
||||
if [ "$frontend_port_requested" -eq 1 ] && frontend_log_indicates_port_conflict "$FRONTEND_LOG_FILE"; then
|
||||
kill_port_if_requested "$frontend_port" "前端"
|
||||
fi
|
||||
|
||||
@@ -2007,7 +2133,8 @@ start_frontend_service() {
|
||||
if ! start_frontend_with_retry "$frontend_port" "$frontend_port_requested" "$frontend_lan_enabled"; then
|
||||
stop_wait_session
|
||||
log_error "前端启动失败,已重试 ${FRONTEND_MAX_RETRIES} 次"
|
||||
tail -10 /tmp/planet_frontend.log
|
||||
tail -10 "$FRONTEND_LOG_FILE"
|
||||
print_port_listener_details "$frontend_port"
|
||||
exit 1
|
||||
fi
|
||||
stop_wait_session
|
||||
@@ -2139,7 +2266,7 @@ cleanup_exit_containers() {
|
||||
exit_containers="$(docker ps -a --filter status=exited -q 2>/dev/null || true)"
|
||||
if [ -n "$exit_containers" ]; then
|
||||
log_step "清理残留 Exit 容器"
|
||||
echo "$exit_containers" | xargs -r docker rm -f >/dev/null 2>&1 || true
|
||||
printf "%s\n" "$exit_containers" | awk '/^[0-9a-f]{12,64}$/' | xargs -r docker rm -f >/dev/null 2>&1 || true
|
||||
log_success "残留容器已清理"
|
||||
fi
|
||||
}
|
||||
@@ -2157,7 +2284,7 @@ stop_container_if_running() {
|
||||
}
|
||||
|
||||
stop_backend_service() {
|
||||
if pgrep -f "uvicorn" >/dev/null 2>&1 || ! can_bind_port "$DEFAULT_BACKEND_PORT"; then
|
||||
if pgrep -f "uvicorn .*--port ${DEFAULT_BACKEND_PORT}" >/dev/null 2>&1 || [ -f "$BACKEND_PID_FILE" ] || ! can_bind_port "$DEFAULT_BACKEND_PORT"; then
|
||||
cleanup_backend_processes "$DEFAULT_BACKEND_PORT"
|
||||
log_halt "后端服务已停止"
|
||||
fi
|
||||
@@ -2168,7 +2295,7 @@ stop_ai_provider_service() {
|
||||
}
|
||||
|
||||
stop_frontend_service() {
|
||||
if pgrep -f "${FRONTEND_VITE_ENTRY}" >/dev/null 2>&1 || [ -f "$FRONTEND_PID_FILE" ]; then
|
||||
if pgrep -f "${FRONTEND_VITE_ENTRY} .*--port ${DEFAULT_FRONTEND_PORT}" >/dev/null 2>&1 || [ -f "$FRONTEND_PID_FILE" ]; then
|
||||
cleanup_frontend_processes "$DEFAULT_FRONTEND_PORT"
|
||||
if [ -n "${FRONTEND_PORT:-}" ] && [ "$FRONTEND_PORT" != "$DEFAULT_FRONTEND_PORT" ]; then
|
||||
cleanup_frontend_processes "$FRONTEND_PORT"
|
||||
@@ -2183,11 +2310,39 @@ stop_frontend_service() {
|
||||
fi
|
||||
}
|
||||
|
||||
print_http_health_status() {
|
||||
local service_name="$1"
|
||||
local url="$2"
|
||||
|
||||
if http_ok "$url"; then
|
||||
echo -e "${DIM} ${service_name}:${NC} ${GREEN}online${NC}"
|
||||
else
|
||||
echo -e "${DIM} ${service_name}:${NC} ${RED}offline${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
print_process_health_status() {
|
||||
local service_name="$1"
|
||||
local pattern="$2"
|
||||
local pid_file="${3:-}"
|
||||
local tracked_pid=""
|
||||
|
||||
if [ -n "$pid_file" ]; then
|
||||
tracked_pid="$(read_pid_file "$pid_file" || true)"
|
||||
fi
|
||||
|
||||
if pgrep -f "$pattern" >/dev/null 2>&1 || { [ -n "$tracked_pid" ] && kill -0 "$tracked_pid" 2>/dev/null; }; then
|
||||
echo -e "${DIM} ${service_name}:${NC} ${GREEN}online${NC}"
|
||||
else
|
||||
echo -e "${DIM} ${service_name}:${NC} ${RED}offline${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
motion_agent_pids() {
|
||||
local pids=""
|
||||
|
||||
if [ -f "$MOTION_AGENT_PID_FILE" ]; then
|
||||
pids="$(cat "$MOTION_AGENT_PID_FILE" 2>/dev/null || true)"
|
||||
pids="$(read_pid_file "$MOTION_AGENT_PID_FILE" || true)"
|
||||
if [ -n "$pids" ] && kill -0 "$pids" 2>/dev/null; then
|
||||
printf "%s\n" "$pids"
|
||||
fi
|
||||
@@ -2206,7 +2361,7 @@ cleanup_motion_agent_processes() {
|
||||
terminate_process_tree "$signal" "$pid"
|
||||
done < <(motion_agent_pids | awk '!seen[$0]++')
|
||||
|
||||
rm -f "$MOTION_AGENT_PID_FILE"
|
||||
remove_pid_file "$MOTION_AGENT_PID_FILE"
|
||||
}
|
||||
|
||||
wait_for_motion_agent_ready() {
|
||||
@@ -2298,7 +2453,7 @@ start_motion_agent_service() {
|
||||
cd "$SCRIPT_DIR"
|
||||
nohup "$SCRIPT_DIR/.venv/bin/python" "${motion_args[@]}" > "$MOTION_AGENT_LOG_FILE" 2>&1 &
|
||||
MOTION_AGENT_PID=$!
|
||||
printf "%s" "$MOTION_AGENT_PID" > "$MOTION_AGENT_PID_FILE"
|
||||
write_pid_file "$MOTION_AGENT_PID_FILE" "$MOTION_AGENT_PID"
|
||||
|
||||
if wait_for_motion_agent_ready "$motion_agent_port" "$MOTION_AGENT_PID"; then
|
||||
log_success "Motion Agent 已就绪"
|
||||
@@ -2308,6 +2463,7 @@ start_motion_agent_service() {
|
||||
|
||||
log_error "Motion Agent 启动失败"
|
||||
tail -20 "$MOTION_AGENT_LOG_FILE" 2>/dev/null || true
|
||||
print_port_listener_details "$motion_agent_port"
|
||||
log_note "如只需验证 Web 端连接,可加 --motion-agent-dry-run。"
|
||||
log_note "如需真实摄像头识别,请确认系统存在 /dev/video*;脚本会自动发现,也可用 --motion-agent-camera-indexes 1,2 覆盖。"
|
||||
log_note "WSL 下也可用 --motion-agent-camera-urls rtsp://... 或 http://... 接入手机/网络摄像头。"
|
||||
@@ -2323,6 +2479,24 @@ stop_motion_agent_service() {
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup_failed_start() {
|
||||
[ "$START_RUN_ACTIVE" -eq 1 ] || return 0
|
||||
[ "$START_RUN_COMPLETED" -eq 0 ] || return 0
|
||||
|
||||
clear_wait_spinner
|
||||
log_warn "启动未完成,清理本轮已拉起的本地进程"
|
||||
|
||||
if [ "$STARTED_MOTION_AGENT_THIS_RUN" -eq 1 ]; then
|
||||
cleanup_motion_agent_processes TERM
|
||||
fi
|
||||
if [ "$STARTED_FRONTEND_THIS_RUN" -eq 1 ]; then
|
||||
cleanup_frontend_processes "${FRONTEND_PORT:-$DEFAULT_FRONTEND_PORT}"
|
||||
fi
|
||||
if [ "$STARTED_BACKEND_THIS_RUN" -eq 1 ]; then
|
||||
cleanup_backend_processes "${BACKEND_PORT:-$DEFAULT_BACKEND_PORT}" || true
|
||||
fi
|
||||
}
|
||||
|
||||
create_user() {
|
||||
local username
|
||||
local password
|
||||
@@ -2433,14 +2607,27 @@ start() {
|
||||
parse_service_args "$@"
|
||||
cleanup_exit_containers
|
||||
|
||||
START_RUN_ACTIVE=1
|
||||
START_RUN_COMPLETED=0
|
||||
STARTED_BACKEND_THIS_RUN=0
|
||||
STARTED_FRONTEND_THIS_RUN=0
|
||||
STARTED_MOTION_AGENT_THIS_RUN=0
|
||||
|
||||
print_splash
|
||||
|
||||
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"
|
||||
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"
|
||||
STARTED_MOTION_AGENT_THIS_RUN=1
|
||||
fi
|
||||
|
||||
write_port_state "$BACKEND_PORT" "$FRONTEND_PORT" "$AI_PROVIDER_PORT" "$MOTION_AGENT_PORT"
|
||||
START_RUN_COMPLETED=1
|
||||
START_RUN_ACTIVE=0
|
||||
|
||||
log_success "启动完成"
|
||||
log_note "智能星球计划: http://localhost:${FRONTEND_PORT}/earth"
|
||||
log_note "智能星球仪表盘: http://localhost:${FRONTEND_PORT}/admin"
|
||||
@@ -2468,6 +2655,10 @@ stop() {
|
||||
restart() {
|
||||
parse_service_args "$@"
|
||||
cleanup_exit_containers
|
||||
local state_backend_port=""
|
||||
local state_frontend_port=""
|
||||
local state_ai_provider_port=""
|
||||
local state_motion_agent_port=""
|
||||
|
||||
if [ "$BACKEND_PORT_REQUESTED" -eq 0 ] && [ "$FRONTEND_PORT_REQUESTED" -eq 0 ] && [ "$AI_PROVIDER_REQUESTED" -eq 0 ] && [ "$MOTION_AGENT_REQUESTED" -eq 0 ] && [ "$DATABASE_REQUESTED" -eq 0 ]; then
|
||||
stop
|
||||
@@ -2506,6 +2697,24 @@ restart() {
|
||||
start_motion_agent_service "$MOTION_AGENT_PORT" "$MOTION_AGENT_DRY_RUN" "$FRONTEND_LAN_ENABLED"
|
||||
fi
|
||||
|
||||
state_backend_port="$(read_port_state_value BACKEND_PORT "$DEFAULT_BACKEND_PORT")"
|
||||
state_frontend_port="$(read_port_state_value FRONTEND_PORT "$DEFAULT_FRONTEND_PORT")"
|
||||
state_ai_provider_port="$(read_port_state_value AI_PROVIDER_PORT "$DEFAULT_AI_PROVIDER_PORT")"
|
||||
state_motion_agent_port="$(read_port_state_value MOTION_AGENT_PORT "$DEFAULT_MOTION_AGENT_PORT")"
|
||||
if [ "$BACKEND_PORT_REQUESTED" -eq 1 ]; then
|
||||
state_backend_port="$BACKEND_PORT"
|
||||
fi
|
||||
if [ "$FRONTEND_PORT_REQUESTED" -eq 1 ]; then
|
||||
state_frontend_port="$FRONTEND_PORT"
|
||||
fi
|
||||
if [ "$AI_PROVIDER_REQUESTED" -eq 1 ]; then
|
||||
state_ai_provider_port="$AI_PROVIDER_PORT"
|
||||
fi
|
||||
if [ "$MOTION_AGENT_REQUESTED" -eq 1 ]; then
|
||||
state_motion_agent_port="$MOTION_AGENT_PORT"
|
||||
fi
|
||||
write_port_state "$state_backend_port" "$state_frontend_port" "$state_ai_provider_port" "$state_motion_agent_port"
|
||||
|
||||
echo ""
|
||||
log_success "重启完成"
|
||||
if [ "$DATABASE_REQUESTED" -eq 1 ]; then
|
||||
@@ -2529,34 +2738,23 @@ restart() {
|
||||
}
|
||||
|
||||
health() {
|
||||
local backend_port=""
|
||||
local frontend_port=""
|
||||
local ai_provider_port=""
|
||||
|
||||
backend_port="$(read_port_state_value BACKEND_PORT "$DEFAULT_BACKEND_PORT")"
|
||||
frontend_port="$(read_port_state_value FRONTEND_PORT "$DEFAULT_FRONTEND_PORT")"
|
||||
ai_provider_port="$(read_port_state_value AI_PROVIDER_PORT "$DEFAULT_AI_PROVIDER_PORT")"
|
||||
|
||||
echo -e "${DIM}·${NC} ${BLUE}view${NC} ${WHITE}容器状态${NC}"
|
||||
docker ps --filter "name=planet_" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||||
docker ps --filter "name=planet_" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || log_note "Docker daemon 不可用,跳过容器状态"
|
||||
|
||||
echo ""
|
||||
echo -e "${DIM}·${NC} ${BLUE}view${NC} ${WHITE}服务状态${NC}"
|
||||
if curl -s http://localhost:8000/health > /dev/null 2>&1; then
|
||||
echo -e "${DIM} 后端:${NC} ${GREEN}online${NC}"
|
||||
else
|
||||
echo -e "${DIM} 后端:${NC} ${RED}offline${NC}"
|
||||
fi
|
||||
|
||||
if curl -s "http://localhost:${DEFAULT_AI_PROVIDER_PORT}/health" > /dev/null 2>&1; then
|
||||
echo -e "${DIM} AI Provider:${NC} ${GREEN}online${NC}"
|
||||
else
|
||||
echo -e "${DIM} AI Provider:${NC} ${RED}offline${NC}"
|
||||
fi
|
||||
|
||||
if curl -s http://localhost:3000 > /dev/null 2>&1; then
|
||||
echo -e "${DIM} 前端:${NC} ${GREEN}online${NC}"
|
||||
else
|
||||
echo -e "${DIM} 前端:${NC} ${RED}offline${NC}"
|
||||
fi
|
||||
|
||||
if pgrep -f "python.*-m motion_agent" >/dev/null 2>&1 || [ -f "$MOTION_AGENT_PID_FILE" ]; then
|
||||
echo -e "${DIM} Motion Agent:${NC} ${GREEN}online${NC}"
|
||||
else
|
||||
echo -e "${DIM} Motion Agent:${NC} ${RED}offline${NC}"
|
||||
fi
|
||||
print_http_health_status "后端" "http://localhost:${backend_port}/health"
|
||||
print_http_health_status "AI Provider" "http://localhost:${ai_provider_port}/health"
|
||||
print_http_health_status "前端" "http://localhost:${frontend_port}"
|
||||
print_process_health_status "Motion Agent" "python.*-m motion_agent" "$MOTION_AGENT_PID_FILE"
|
||||
}
|
||||
|
||||
log() {
|
||||
@@ -2564,12 +2762,12 @@ log() {
|
||||
-f|--frontend)
|
||||
log_step "查看前端日志"
|
||||
log_note "按 Ctrl+C 退出"
|
||||
tail -f /tmp/planet_frontend.log
|
||||
tail -f "$FRONTEND_LOG_FILE"
|
||||
;;
|
||||
-b|--backend)
|
||||
log_step "查看后端日志"
|
||||
log_note "按 Ctrl+C 退出"
|
||||
tail -f /tmp/planet_backend.log
|
||||
tail -f "$BACKEND_LOG_FILE"
|
||||
;;
|
||||
-a|--ai-provider)
|
||||
log_step "查看 AI Provider 日志"
|
||||
@@ -2584,11 +2782,11 @@ log() {
|
||||
*)
|
||||
log_step "查看最近日志"
|
||||
log_note "后端"
|
||||
tail -20 /tmp/planet_backend.log 2>/dev/null || log_note "无日志"
|
||||
tail -20 "$BACKEND_LOG_FILE" 2>/dev/null || log_note "无日志"
|
||||
log_note "AI Provider"
|
||||
docker logs --tail 20 planet_aiprovider 2>/dev/null || log_note "无日志"
|
||||
log_note "前端"
|
||||
tail -20 /tmp/planet_frontend.log 2>/dev/null || log_note "无日志"
|
||||
tail -20 "$FRONTEND_LOG_FILE" 2>/dev/null || log_note "无日志"
|
||||
log_note "Motion Agent"
|
||||
tail -20 "$MOTION_AGENT_LOG_FILE" 2>/dev/null || log_note "无日志"
|
||||
;;
|
||||
@@ -2611,6 +2809,8 @@ parse_global_args() {
|
||||
GLOBAL_ARG_REMAINDER=("$@")
|
||||
}
|
||||
|
||||
trap cleanup_failed_start EXIT
|
||||
|
||||
parse_global_args "$@"
|
||||
set -- "${GLOBAL_ARG_REMAINDER[@]}"
|
||||
|
||||
@@ -2637,7 +2837,7 @@ case "$1" in
|
||||
;;
|
||||
*)
|
||||
log_error "用法: ./planet.sh {start|stop|restart|createuser|health|log}"
|
||||
log_note "全局参数: -v, --verbose 在当前执行行下方滚动显示最多 5 行命令输出"
|
||||
log_note "全局参数: -v, --verbose 在状态提示之间增量输出命令日志"
|
||||
log_note "start 启动服务,可选: -b <后端端口> -f <前端端口> -a <AI Provider 端口> -m/--motion-agent --motion-agent-port <端口> --motion-agent-camera-indexes 0,1 --motion-agent-camera-urls rtsp://... --motion-agent-dry-run --allow-lan --verbose"
|
||||
log_note "stop 停止服务"
|
||||
log_note "restart 重启服务,可选: -b [后端端口] -f [前端端口] -a [AI Provider 端口] -m [Motion Agent] -d --allow-lan --verbose"
|
||||
|
||||
Reference in New Issue
Block a user