feat:聊天信息支持 文件、图片、语音发送,增加一键启停脚本
This commit is contained in:
@@ -1,5 +1,27 @@
|
||||
#!/bin/bash
|
||||
# EchoChat 开发环境一键搭建脚本
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# EchoChat 开发环境【首次】初始化脚本
|
||||
# ------------------------------------------------------------------------------
|
||||
# ✅ 适用时机:
|
||||
# - 开发者首次 clone 仓库后
|
||||
# - 删除过所有 Docker 卷 / 需要重建数据库时
|
||||
# - 中间件容器长时间未使用、需要做一次性健康验证时
|
||||
#
|
||||
# ❌ 非适用时机(请改用 scripts/start.sh):
|
||||
# - 每天日常启停(开机/关机)
|
||||
# - 仅想拉起应用层(Go 后端 + 前台 + 管理端)
|
||||
#
|
||||
# 职责:
|
||||
# 1. 检查 Docker / Docker Compose 是否安装
|
||||
# 2. 启动 PostgreSQL + Redis + MinIO 容器(docker-compose up -d)
|
||||
# 3. 通过重试式健康检查(pg_isready / redis ping / MinIO /health/live)确认就绪
|
||||
# 4. 输出基础设施连接信息与默认管理员账号
|
||||
#
|
||||
# 日常启停请使用:
|
||||
# ./scripts/start.sh # 一键启动全部服务
|
||||
# ./scripts/stop.sh # 一键停止应用层
|
||||
# ./scripts/status.sh # 查看端口/PID/容器状态
|
||||
# ==============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
@@ -8,16 +30,14 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
DEPLOY_DIR="$PROJECT_ROOT/deploy"
|
||||
|
||||
echo "========================================="
|
||||
echo " EchoChat 开发环境搭建"
|
||||
echo " EchoChat 开发环境【首次】搭建"
|
||||
echo "========================================="
|
||||
|
||||
# 检查 Docker 是否安装
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "❌ Docker 未安装,请先安装 Docker Desktop"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查 Docker Compose 是否可用
|
||||
if ! docker compose version &> /dev/null; then
|
||||
echo "❌ Docker Compose 不可用,请确保 Docker Desktop 已正确安装"
|
||||
exit 1
|
||||
@@ -25,19 +45,18 @@ fi
|
||||
|
||||
echo "✅ Docker 和 Docker Compose 已就绪"
|
||||
|
||||
# 启动基础设施服务
|
||||
echo ""
|
||||
echo "🚀 启动 PostgreSQL 和 Redis ..."
|
||||
echo "🚀 启动 PostgreSQL / Redis / MinIO ..."
|
||||
cd "$DEPLOY_DIR"
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
docker compose -f docker-compose.dev.yml up -d postgres redis minio
|
||||
|
||||
# 等待服务就绪
|
||||
echo ""
|
||||
echo "⏳ 等待服务健康检查通过 ..."
|
||||
sleep 3
|
||||
|
||||
# 检查 PostgreSQL
|
||||
MAX_RETRIES=30
|
||||
|
||||
# PostgreSQL
|
||||
RETRY=0
|
||||
until docker exec echochat-postgres pg_isready -U echochat > /dev/null 2>&1; do
|
||||
RETRY=$((RETRY + 1))
|
||||
@@ -49,7 +68,7 @@ until docker exec echochat-postgres pg_isready -U echochat > /dev/null 2>&1; do
|
||||
done
|
||||
echo "✅ PostgreSQL 已就绪 (localhost:5432)"
|
||||
|
||||
# 检查 Redis
|
||||
# Redis
|
||||
RETRY=0
|
||||
until docker exec echochat-redis redis-cli ping > /dev/null 2>&1; do
|
||||
RETRY=$((RETRY + 1))
|
||||
@@ -61,17 +80,35 @@ until docker exec echochat-redis redis-cli ping > /dev/null 2>&1; do
|
||||
done
|
||||
echo "✅ Redis 已就绪 (localhost:6379)"
|
||||
|
||||
# MinIO:使用 /minio/health/live 端点(容器内 curl 检查)
|
||||
RETRY=0
|
||||
until docker exec echochat-minio curl -fs http://localhost:9000/minio/health/live > /dev/null 2>&1; do
|
||||
RETRY=$((RETRY + 1))
|
||||
if [ $RETRY -ge $MAX_RETRIES ]; then
|
||||
echo "❌ MinIO 启动超时"
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo "✅ MinIO 已就绪 (API: localhost:9000 | Console: localhost:9001)"
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " ✅ 开发环境搭建完成!"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
echo " PostgreSQL: localhost:5432"
|
||||
echo " 数据库: echochat"
|
||||
echo " 用户名: echochat"
|
||||
echo " 密码: echochat_dev_2026"
|
||||
echo " PostgreSQL: localhost:5432"
|
||||
echo " 数据库: echochat"
|
||||
echo " 用户名: echochat"
|
||||
echo " 密码: echochat_dev_2026"
|
||||
echo ""
|
||||
echo " Redis: localhost:6379"
|
||||
echo " Redis: localhost:6379"
|
||||
echo ""
|
||||
echo " 管理员账号: admin / admin123456"
|
||||
echo " MinIO API: http://localhost:9000"
|
||||
echo " MinIO 控制台: http://localhost:9001"
|
||||
echo " 账号: echochat / echochat123456"
|
||||
echo ""
|
||||
echo " 管理员账号: admin / admin123456"
|
||||
echo ""
|
||||
echo " 👉 下一步:运行 ./scripts/start.sh 启动应用层服务"
|
||||
echo "========================================="
|
||||
|
||||
137
scripts/start.sh
Executable file
137
scripts/start.sh
Executable file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env bash
|
||||
# EchoChat 一键启动脚本
|
||||
# 用法:
|
||||
# ./scripts/start.sh # 启动全部(Docker 中间件 + Go 后端 + 前台 + 管理端)
|
||||
# ./scripts/start.sh --no-docker # 仅启动应用层(假设 Docker 容器已在运行)
|
||||
# ./scripts/start.sh backend # 仅启动指定服务(backend|frontend|admin|docker)
|
||||
# 注意:不使用 set -e,避免单个服务启动失败中断其他服务;
|
||||
# 失败时由 spawn_bg 内部打印日志末尾辅助排障
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
RUN_DIR="$ROOT_DIR/.run"
|
||||
LOG_DIR="$RUN_DIR/logs"
|
||||
mkdir -p "$RUN_DIR" "$LOG_DIR"
|
||||
|
||||
COLOR_GREEN='\033[0;32m'
|
||||
COLOR_YELLOW='\033[0;33m'
|
||||
COLOR_RED='\033[0;31m'
|
||||
COLOR_CYAN='\033[0;36m'
|
||||
COLOR_RESET='\033[0m'
|
||||
|
||||
log_info() { printf "${COLOR_CYAN}[INFO]${COLOR_RESET} %s\n" "$*"; }
|
||||
log_ok() { printf "${COLOR_GREEN}[OK]${COLOR_RESET} %s\n" "$*"; }
|
||||
log_warn() { printf "${COLOR_YELLOW}[WARN]${COLOR_RESET} %s\n" "$*"; }
|
||||
log_err() { printf "${COLOR_RED}[ERR]${COLOR_RESET} %s\n" "$*"; }
|
||||
|
||||
# 判断端口是否被占用
|
||||
port_in_use() {
|
||||
lsof -iTCP:"$1" -sTCP:LISTEN -n -P >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# 将命令以后台方式启动,并记录 PID 与日志
|
||||
# 启动失败时自动打印日志末尾帮助排障,但不中断其他服务的启动
|
||||
spawn_bg() {
|
||||
local name="$1"; shift
|
||||
local workdir="$1"; shift
|
||||
local log_file="$LOG_DIR/$name.log"
|
||||
local pid_file="$RUN_DIR/$name.pid"
|
||||
(
|
||||
cd "$workdir"
|
||||
nohup "$@" >"$log_file" 2>&1 &
|
||||
echo $! >"$pid_file"
|
||||
)
|
||||
sleep 1
|
||||
local pid
|
||||
pid="$(cat "$pid_file" 2>/dev/null || echo '')"
|
||||
if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
|
||||
log_ok "$name 已启动 (PID=$pid) 日志: $log_file"
|
||||
return 0
|
||||
fi
|
||||
log_err "$name 启动失败,日志末尾:"
|
||||
if [[ -f "$log_file" ]]; then
|
||||
echo "------------------------------------------------------------"
|
||||
tail -n 20 "$log_file"
|
||||
echo "------------------------------------------------------------"
|
||||
fi
|
||||
log_err "完整日志: $log_file"
|
||||
return 1
|
||||
}
|
||||
|
||||
start_docker() {
|
||||
log_info "启动 Docker 中间件(Postgres/Redis/MinIO)..."
|
||||
cd "$ROOT_DIR/deploy"
|
||||
docker compose -f docker-compose.dev.yml up -d postgres redis minio
|
||||
log_ok "Docker 中间件已启动"
|
||||
}
|
||||
|
||||
start_backend() {
|
||||
if port_in_use 8085; then
|
||||
log_warn "端口 8085 已被占用,跳过 Go 后端启动"
|
||||
return 0
|
||||
fi
|
||||
log_info "启动 Go 后端 (port 8085)..."
|
||||
spawn_bg "backend" "$ROOT_DIR/backend/go-service" go run cmd/server/main.go
|
||||
}
|
||||
|
||||
start_frontend() {
|
||||
if port_in_use 5173; then
|
||||
log_warn "端口 5173 已被占用,跳过前台启动"
|
||||
return 0
|
||||
fi
|
||||
log_info "启动前台用户端 (port 5173)..."
|
||||
spawn_bg "frontend" "$ROOT_DIR/frontend" npm run dev:h5
|
||||
}
|
||||
|
||||
start_admin() {
|
||||
if port_in_use 3100; then
|
||||
log_warn "端口 3100 已被占用,跳过管理端启动"
|
||||
return 0
|
||||
fi
|
||||
log_info "启动后台管理端 (port 3100)..."
|
||||
spawn_bg "admin" "$ROOT_DIR/admin" npm run dev
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
printf "\n${COLOR_GREEN}=============== EchoChat 启动完成 ===============${COLOR_RESET}\n"
|
||||
printf " 前台用户端 (H5): http://localhost:5173\n"
|
||||
printf " 后台管理端: http://localhost:3100\n"
|
||||
printf " Go 后端 API: http://localhost:8085\n"
|
||||
printf " MinIO 控制台: http://localhost:9001 (echochat / echochat123456)\n\n"
|
||||
printf " 日志目录: %s\n" "$LOG_DIR"
|
||||
printf " PID 目录: %s\n" "$RUN_DIR"
|
||||
printf " 查看状态: ./scripts/status.sh\n"
|
||||
printf " 停止全部: ./scripts/stop.sh\n"
|
||||
printf "${COLOR_GREEN}=================================================${COLOR_RESET}\n"
|
||||
}
|
||||
|
||||
main() {
|
||||
local target="${1:-all}"
|
||||
local skip_docker=false
|
||||
if [[ "$target" == "--no-docker" ]]; then
|
||||
skip_docker=true
|
||||
target="all"
|
||||
fi
|
||||
|
||||
case "$target" in
|
||||
all)
|
||||
$skip_docker || start_docker || log_err "Docker 中间件启动异常,请检查 Docker Desktop 是否运行"
|
||||
start_backend || true
|
||||
start_frontend || true
|
||||
start_admin || true
|
||||
print_summary
|
||||
;;
|
||||
docker) start_docker ;;
|
||||
backend) start_backend ;;
|
||||
frontend) start_frontend ;;
|
||||
admin) start_admin ;;
|
||||
*)
|
||||
log_err "未知参数: $target"
|
||||
echo "用法: $0 [all|docker|backend|frontend|admin|--no-docker]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
59
scripts/status.sh
Executable file
59
scripts/status.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# EchoChat 服务状态查看脚本
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
RUN_DIR="$ROOT_DIR/.run"
|
||||
|
||||
COLOR_GREEN='\033[0;32m'
|
||||
COLOR_RED='\033[0;31m'
|
||||
COLOR_YELLOW='\033[0;33m'
|
||||
COLOR_RESET='\033[0m'
|
||||
|
||||
check_port() {
|
||||
local name="$1"
|
||||
local port="$2"
|
||||
local url="$3"
|
||||
local pid
|
||||
pid="$(lsof -iTCP:"$port" -sTCP:LISTEN -n -P -t 2>/dev/null | head -n1 || true)"
|
||||
if [[ -n "$pid" ]]; then
|
||||
printf " %-22s ${COLOR_GREEN}● RUNNING${COLOR_RESET} PID=%-8s %s\n" "$name (:$port)" "$pid" "$url"
|
||||
else
|
||||
printf " %-22s ${COLOR_RED}○ STOPPED${COLOR_RESET} %-12s %s\n" "$name (:$port)" "" "$url"
|
||||
fi
|
||||
}
|
||||
|
||||
check_container() {
|
||||
local name="$1"
|
||||
local port="$2"
|
||||
local status
|
||||
status="$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null || echo 'missing')"
|
||||
case "$status" in
|
||||
running)
|
||||
printf " %-22s ${COLOR_GREEN}● RUNNING${COLOR_RESET} container=%s\n" "$name (:$port)" "$name"
|
||||
;;
|
||||
missing)
|
||||
printf " %-22s ${COLOR_YELLOW}? NOT-CREATED${COLOR_RESET}\n" "$name (:$port)"
|
||||
;;
|
||||
*)
|
||||
printf " %-22s ${COLOR_RED}○ %s${COLOR_RESET}\n" "$name (:$port)" "$status"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "===== EchoChat 应用层 ====="
|
||||
check_port "Go 后端" 8085 "http://localhost:8085"
|
||||
check_port "前台用户端" 5173 "http://localhost:5173"
|
||||
check_port "后台管理端" 3100 "http://localhost:3100"
|
||||
|
||||
echo ""
|
||||
echo "===== Docker 中间件 ====="
|
||||
check_container "echochat-postgres" 5432
|
||||
check_container "echochat-redis" 6379
|
||||
check_container "echochat-minio" 9000
|
||||
|
||||
echo ""
|
||||
echo "日志目录:$RUN_DIR/logs"
|
||||
echo ""
|
||||
118
scripts/stop.sh
Executable file
118
scripts/stop.sh
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env bash
|
||||
# EchoChat 一键停止脚本
|
||||
# 用法:
|
||||
# ./scripts/stop.sh # 停止应用层(Go 后端 + 前台 + 管理端),保留 Docker 容器
|
||||
# ./scripts/stop.sh --all # 停止全部(含 Docker 中间件)
|
||||
# ./scripts/stop.sh backend # 仅停止指定服务(backend|frontend|admin|docker)
|
||||
# 不使用 set -e:即使某一项停止失败,其他项也要继续尝试
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
RUN_DIR="$ROOT_DIR/.run"
|
||||
|
||||
COLOR_GREEN='\033[0;32m'
|
||||
COLOR_YELLOW='\033[0;33m'
|
||||
COLOR_RED='\033[0;31m'
|
||||
COLOR_CYAN='\033[0;36m'
|
||||
COLOR_RESET='\033[0m'
|
||||
|
||||
log_info() { printf "${COLOR_CYAN}[INFO]${COLOR_RESET} %s\n" "$*"; }
|
||||
log_ok() { printf "${COLOR_GREEN}[OK]${COLOR_RESET} %s\n" "$*"; }
|
||||
log_warn() { printf "${COLOR_YELLOW}[WARN]${COLOR_RESET} %s\n" "$*"; }
|
||||
|
||||
# 根据端口查找监听进程 PID
|
||||
pids_by_port() {
|
||||
lsof -iTCP:"$1" -sTCP:LISTEN -n -P -t 2>/dev/null || true
|
||||
}
|
||||
|
||||
# 终止 PID(先 TERM,2s 后仍存在则 KILL),同时杀掉其子进程组
|
||||
kill_pid() {
|
||||
local pid="$1"
|
||||
[[ -z "$pid" ]] && return 0
|
||||
kill -0 "$pid" 2>/dev/null || return 0
|
||||
# 尝试杀死进程组(负 PID 表示进程组)
|
||||
kill -TERM -"$pid" 2>/dev/null || kill -TERM "$pid" 2>/dev/null || true
|
||||
for _ in 1 2 3 4; do
|
||||
kill -0 "$pid" 2>/dev/null || return 0
|
||||
sleep 0.5
|
||||
done
|
||||
kill -KILL -"$pid" 2>/dev/null || kill -KILL "$pid" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# 停止由 start.sh 启动的命名服务(以 .pid 文件 + 端口兜底)
|
||||
stop_named() {
|
||||
local name="$1"
|
||||
local port="$2"
|
||||
local pid_file="$RUN_DIR/$name.pid"
|
||||
local killed=0
|
||||
|
||||
if [[ -f "$pid_file" ]]; then
|
||||
local pid
|
||||
pid="$(cat "$pid_file")"
|
||||
if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
|
||||
log_info "停止 $name (PID=$pid, port=$port)..."
|
||||
kill_pid "$pid"
|
||||
killed=1
|
||||
fi
|
||||
rm -f "$pid_file"
|
||||
fi
|
||||
|
||||
# 端口兜底:清理任何仍占用目标端口的进程
|
||||
local port_pids
|
||||
port_pids="$(pids_by_port "$port")"
|
||||
if [[ -n "$port_pids" ]]; then
|
||||
for p in $port_pids; do
|
||||
log_info "清理 $name 残留进程 (PID=$p, port=$port)..."
|
||||
kill_pid "$p"
|
||||
killed=1
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ $killed -eq 1 ]]; then
|
||||
log_ok "$name 已停止"
|
||||
else
|
||||
log_warn "$name 未在运行"
|
||||
fi
|
||||
}
|
||||
|
||||
stop_backend() { stop_named "backend" 8085; }
|
||||
stop_frontend() { stop_named "frontend" 5173; }
|
||||
stop_admin() { stop_named "admin" 3100; }
|
||||
|
||||
stop_docker() {
|
||||
log_info "停止 Docker 中间件..."
|
||||
cd "$ROOT_DIR/deploy"
|
||||
docker compose -f docker-compose.dev.yml stop postgres redis minio || true
|
||||
log_ok "Docker 中间件已停止(数据卷保留)"
|
||||
}
|
||||
|
||||
main() {
|
||||
local target="${1:-app}"
|
||||
|
||||
case "$target" in
|
||||
app|"")
|
||||
stop_backend
|
||||
stop_frontend
|
||||
stop_admin
|
||||
log_ok "应用层服务已停止(Docker 中间件保持运行)"
|
||||
;;
|
||||
--all|all)
|
||||
stop_backend
|
||||
stop_frontend
|
||||
stop_admin
|
||||
stop_docker
|
||||
log_ok "所有服务已停止"
|
||||
;;
|
||||
backend) stop_backend ;;
|
||||
frontend) stop_frontend ;;
|
||||
admin) stop_admin ;;
|
||||
docker) stop_docker ;;
|
||||
*)
|
||||
echo "用法: $0 [app|--all|backend|frontend|admin|docker]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user