#!/usr/bin/env bash # 启动 HTTP(uvicorn)与 SFTP;已在运行则跳过(幂等)。 set -euo pipefail cd "$(dirname "$0")" ROOT="$(pwd)" VENV="$ROOT/.venv" PY="$VENV/bin/python" [ -x "$PY" ] || { echo "未找到 venv:$VENV,请先运行 ./setup.sh" >&2; exit 1; } [ -f "$ROOT/config.yaml" ] || { echo "未找到 config.yaml,请先运行 ./setup.sh" >&2; exit 1; } mkdir -p "$ROOT/logs" "$ROOT/uploads" # 启动前清理: # - upload_service.py 用 .part 后缀做原子写,进程已停时残留必为半成品。 # - chunk_upload_service.py 的分片会话目录 .work/ 同理,残留的未完成会话无法续传。 PART_COUNT=$(find "$ROOT/uploads" -type f -name '*.part' -printf '.' 2>/dev/null | wc -c) if [ "$PART_COUNT" -gt 0 ]; then find "$ROOT/uploads" -type f -name '*.part' -delete echo "清理:删除残留 .part 文件 $PART_COUNT 个" fi WORK_COUNT=0 if [ -d "$ROOT/uploads/.work" ]; then WORK_COUNT=$(find "$ROOT/uploads/.work" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l) fi if [ "$WORK_COUNT" -gt 0 ]; then rm -rf "$ROOT/uploads/.work"/* echo "清理:删除残留分片会话目录 $WORK_COUNT 个" fi is_running() { [ -f "$1" ] && kill -0 "$(cat "$1")" 2>/dev/null; } # --- HTTP --- APP_PID="$ROOT/app.pid" if is_running "$APP_PID"; then echo "HTTP 已在运行 (pid $(cat "$APP_PID"))" else read -r HOST PORT <<<"$("$PY" - <<'PY' import yaml c = yaml.safe_load(open("config.yaml")) print(c["server"]["host"], c["server"]["port"]) PY )" nohup "$VENV/bin/uvicorn" app.main:app \ --host "$HOST" --port "$PORT" \ >>"$ROOT/logs/app.log" 2>&1 & echo $! > "$APP_PID" echo "HTTP 启动 pid=$(cat "$APP_PID") 监听 ${HOST}:${PORT} 日志 logs/app.log" fi # --- SFTP --- SFTP_PID="$ROOT/sftp.pid" SFTP_ENABLED="$("$PY" - <<'PY' import yaml print("true" if yaml.safe_load(open("config.yaml")).get("sftp", {}).get("enabled", True) else "false") PY )" if [ "$SFTP_ENABLED" = "true" ]; then if is_running "$SFTP_PID"; then echo "SFTP 已在运行 (pid $(cat "$SFTP_PID"))" else nohup "$PY" -m app.services.sftp_server >>"$ROOT/logs/sftp.log" 2>&1 & echo $! > "$SFTP_PID" echo "SFTP 启动 pid=$(cat "$SFTP_PID") 日志 logs/sftp.log" fi else echo "SFTP 已在配置中禁用,跳过。" fi echo "docs: http://127.0.0.1:6867/docs (对外 https://f.zikai.wang/docs)"