#!/bin/bash # 本地站点管理:启动 / 停止 / 重启 / 状态 # 用法:bash sites-manage-local.sh [start|stop|restart|status] [站点名...] # 不加参数默认 status # # 站点名: # cc: www-cc cloud-cc token-cc # ai: www-ai cloud-ai token-ai issue assets ldap oa sso gitea monitor # all: 全部站点 set -e BASE_DIR="/Users/niuniu/programs/docker" ISSUE_DIR="$BASE_DIR/issue-ai" ASSETS_DIR="$BASE_DIR/assets-ai" LDAP_DIR="$BASE_DIR/ldap-ai" OA_DIR="$BASE_DIR/oa-ai" GITEA_DIR="$BASE_DIR/gitea-ai" SSO_DIR="$BASE_DIR/sso-ai" MONITOR_DIR="$BASE_DIR/monitor-ai" # 颜色 GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; RED='\033[0;31m'; NC='\033[0m' log() { printf "${GREEN}[✓]${NC} %s\n" "$1"; } warn() { printf "${YELLOW}[!]${NC} %s\n" "$1"; } err() { printf "${RED}[✗]${NC} %s\n" "$1"; } # 端口 WWW_AI_PORT=6173 CLOUD_AI_PORT=6174 TOKEN_AI_PORT=6175 ISSUE_PORT=6176 ASSETS_PORT=6177 LDAP_WEB_PORT=6178 OA_PORT=6179 SSO_PORT=6180 MONITOR_PORT=6181 WWW_CC_PORT=5173 CLOUD_CC_PORT=5174 TOKEN_CC_PORT=5175 GITEA_PORT=6182 is_port() { lsof -i :"$1" >/dev/null 2>&1; } # 检查 Docker 服务是否运行 check_docker() { if ! docker info >/dev/null 2>&1; then err "Docker 服务未启动,请先启动 Docker Desktop" exit 1 fi } # ============================================================ # 单个 Docker 站点操作 # ============================================================ docker_start() { local name=$1 dir=$2 if [ "$(cd "$dir" && docker compose ps -q --status running 2>/dev/null)" ]; then warn "$name 已在运行" else log "启动 $name..." cd "$dir" && docker compose up -d 2>/dev/null || { err "$name 启动失败"; return 1; } for i in $(seq 1 30); do [ "$(cd "$dir" && docker compose ps -q --status running 2>/dev/null)" ] && { log "$name 已启动"; return 0; } sleep 1 done err "$name 启动异常(可能处于重启循环,请检查 docker compose logs)" fi } docker_stop() { local name=$1 dir=$2 if [ "$(cd "$dir" && docker compose ps -q --status running --status restarting 2>/dev/null)" ]; then log "停止 $name..." cd "$dir" && docker compose down 2>/dev/null && log "$name 已停止" || err "$name 停止失败" else warn "$name 未在运行" fi } # ============================================================ # 单个 Node.js 服务(npm run dev) # ============================================================ node_start() { local name=$1 dir=$2 port=$3 logfile=$4 if is_port $port; then warn "$name 已在运行 (port $port)" else log "启动 $name (port $port)..." cd "$dir" && npm run dev > "$logfile" 2>&1 & sleep 2 is_port $port && log "$name 已启动" || err "$name 启动失败,请查看 $logfile" fi } node_stop() { local name=$1 port=$2 if is_port $port; then kill $(lsof -ti :$port) 2>/dev/null && log "$name 已停止" || warn "$name 停止失败" else warn "$name 未在运行" fi } # ============================================================ # 批量操作 # ============================================================ start_all() { for name in "$@"; do case $name in www-cc) docker_start www-cc "$BASE_DIR/cc-site/www-cc" ;; cloud-cc) docker_start cloud-cc "$BASE_DIR/cc-site/cloud-cc" ;; token-cc) docker_start token-cc "$BASE_DIR/cc-site/token-cc" ;; www-ai) docker_start www-ai "$BASE_DIR/www-ai" ;; cloud-ai) docker_start cloud-ai "$BASE_DIR/cloud-ai" ;; token-ai) docker_start token-ai "$BASE_DIR/token-ai" ;; issue) node_start issue "$ISSUE_DIR" $ISSUE_PORT "/tmp/issue-ai-dev.log" if ! is_port $ASSETS_PORT; then node_start assets "$ASSETS_DIR" $ASSETS_PORT "/tmp/assets-ai-dev.log" warn "已自动启动 assets-ai(issue 依赖 assets API)" fi ;; assets) node_start assets "$ASSETS_DIR" $ASSETS_PORT "/tmp/assets-ai-dev.log" ;; ldap) docker_start ldap "$LDAP_DIR" if is_port $LDAP_WEB_PORT; then log "LLDAP Web UI: http://127.0.0.1:$LDAP_WEB_PORT" fi ;; oa) node_start oa "$OA_DIR" $OA_PORT "/tmp/oa-ai-dev.log" ;; sso) docker_start sso "$SSO_DIR" ;; gitea) docker_start gitea "$GITEA_DIR" ;; monitor) node_start monitor "$MONITOR_DIR" $MONITOR_PORT "/tmp/monitor-ai-dev.log" ;; cc) start_all www-cc cloud-cc token-cc ;; ai) start_all www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea ;; all) start_all cc ai ;; *) err "未知站点: $name" ;; esac done } stop_all() { for name in "$@"; do case $name in www-cc) docker_stop www-cc "$BASE_DIR/cc-site/www-cc" ;; cloud-cc) docker_stop cloud-cc "$BASE_DIR/cc-site/cloud-cc" ;; token-cc) docker_stop token-cc "$BASE_DIR/cc-site/token-cc" ;; www-ai) docker_stop www-ai "$BASE_DIR/www-ai" ;; cloud-ai) docker_stop cloud-ai "$BASE_DIR/cloud-ai" ;; token-ai) docker_stop token-ai "$BASE_DIR/token-ai" ;; issue) node_stop issue $ISSUE_PORT ;; assets) node_stop assets $ASSETS_PORT ;; ldap) docker_stop ldap "$LDAP_DIR" ;; oa) node_stop oa $OA_PORT ;; sso) docker_stop sso "$SSO_DIR" ;; gitea) docker_stop gitea "$GITEA_DIR" ;; monitor) node_stop monitor $MONITOR_PORT ;; cc) stop_all www-cc cloud-cc token-cc ;; ai) stop_all www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea ;; all) stop_all cc ai ;; *) err "未知站点: $name" ;; esac done } restart_all() { stop_all "$@" echo "" log "正在重启..." start_all "$@" } # ============================================================ # 状态 # ============================================================ show_status() { local targets=("$@") # 合并 all/cc/ai local expanded=() for t in "${targets[@]}"; do case $t in all) eval "expanded=(www-cc cloud-cc token-cc www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea)" ;; cc) eval "expanded=(\${expanded[@]} www-cc cloud-cc token-cc)" ;; ai) eval "expanded=(\${expanded[@]} www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea)" ;; *) expanded+=($t) ;; esac done echo "" printf "${CYAN}=========================================${NC}\n" printf "${CYAN} 当前状态${NC}\n" printf "${CYAN}=========================================${NC}\n" echo "" # 获取站点对应端口 get_port() { case $1 in www-cc) echo $WWW_CC_PORT ;; cloud-cc) echo $CLOUD_CC_PORT ;; token-cc) echo $TOKEN_CC_PORT ;; www-ai) echo $WWW_AI_PORT ;; cloud-ai) echo $CLOUD_AI_PORT ;; token-ai) echo $TOKEN_AI_PORT ;; issue) echo $ISSUE_PORT ;; assets) echo $ASSETS_PORT ;; ldap) echo $LDAP_WEB_PORT ;; oa) echo $OA_PORT ;; sso) echo $SSO_PORT ;; gitea) echo $GITEA_PORT ;; monitor) echo $MONITOR_PORT ;; esac } local running=0 # 按 cc/ai 分组输出 _status_group() { local label=$1; shift local group=() gname n for gname in "$@"; do for n in "${expanded[@]}"; do [ "$n" = "$gname" ] && group+=("$n") && break done done [ ${#group[@]} -eq 0 ] && return printf " ${CYAN}%s站点:${NC}\n" "$label" for gname in "${group[@]}"; do local port=$(get_port $gname) if [ -n "$port" ] && is_port $port; then printf " ${GREEN}●${NC} %-12s 运行中 (port %d)\n" "$gname" $port running=$((running + 1)) else printf " ${RED}●${NC} %-12s 未运行\n" "$gname" fi done echo "" } _status_group "cc " www-cc cloud-cc token-cc _status_group "ai " www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea printf "${CYAN}=========================================${NC}\n" printf "${CYAN} 访问地址${NC}\n" printf "${CYAN}=========================================${NC}\n" echo "" echo " cc 站点:" echo " www-cc http://127.0.0.1:5173" echo " cloud-cc http://127.0.0.1:5174" echo " token-cc http://127.0.0.1:5175" echo "" echo " ai 站点:" echo " www-ai http://127.0.0.1:6173" echo " cloud-ai http://127.0.0.1:6174" echo " token-ai http://127.0.0.1:6175" echo " issue http://127.0.0.1:$ISSUE_PORT" echo " assets http://127.0.0.1:$ASSETS_PORT" echo " ldap http://127.0.0.1:$LDAP_WEB_PORT (LLDAP Web UI)" echo " oa http://127.0.0.1:$OA_PORT" echo " sso http://127.0.0.1:$SSO_PORT (Authelia OIDC)" echo " monitor http://127.0.0.1:$MONITOR_PORT" echo " gitea http://127.0.0.1:$GITEA_PORT" echo "" } # ============================================================ # 帮助 # ============================================================ show_help() { echo "" printf "${CYAN}用法:${NC} bash sites-manage-local.sh [命令] [站点名...]\n" echo "" echo " 命令:" echo " start 启动站点" echo " stop 停止站点" echo " restart 重启站点" echo " status 查看状态" echo "" echo " 站点名(可指定多个,空格分隔):" echo " www-cc cloud-cc token-cc" echo " ldap www-ai cloud-ai token-ai issue assets oa sso gitea monitor" echo " cc — tlyq.cc 全部 (www-cc cloud-cc token-cc)" echo " ai — tlyq.ai 全部 (ldap www-ai cloud-ai token-ai issue assets oa sso gitea monitor)" echo " all — 全部站点" echo "" echo "示例:" echo " bash sites-manage-local.sh start all # 启动全部" echo " bash sites-manage-local.sh start ai # 启动 ai 全部" echo " bash sites-manage-local.sh start issue assets # 只启 issue + assets" echo " bash sites-manage-local.sh stop www-ai # 只停 www-ai" echo " bash sites-manage-local.sh status # 查看所有状态" echo "" } # ============================================================ # 入口 # ============================================================ # 检查 Docker 服务 check_docker ACTION=${1:-status} shift || true # 解析站点列表 if [ $# -eq 0 ]; then case $ACTION in start|stop|restart) TARGETS=(all) ;; status) TARGETS=(all) ;; help|--help|-h) show_help; exit 0 ;; *) err "未知命令: $ACTION"; show_help; exit 1 ;; esac else TARGETS=("$@") fi case $ACTION in start) start_all "${TARGETS[@]}" ;; stop) stop_all "${TARGETS[@]}" ;; restart) restart_all "${TARGETS[@]}" ;; status) show_status "${TARGETS[@]}" ;; help|--help|-h) show_help ;; *) err "未知命令: $ACTION"; show_help; exit 1 ;; esac