Files
CyberStrikeAI/run.sh
2026-01-17 14:17:20 +08:00

390 lines
12 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
set -euo pipefail
# CyberStrikeAI 一键部署启动脚本
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT_DIR"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# 打印带颜色的消息
info() { echo -e "${BLUE} $1${NC}"; }
success() { echo -e "${GREEN}$1${NC}"; }
warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
error() { echo -e "${RED}$1${NC}"; }
note() { echo -e "${CYAN} $1${NC}"; }
# 临时源配置(仅在此脚本中生效)
PIP_INDEX_URL="${PIP_INDEX_URL:-https://pypi.tuna.tsinghua.edu.cn/simple}"
GOPROXY="${GOPROXY:-https://goproxy.cn,direct}"
# 保存原始环境变量(用于恢复)
ORIGINAL_PIP_INDEX_URL="${PIP_INDEX_URL:-}"
ORIGINAL_GOPROXY="${GOPROXY:-}"
# 进度显示函数
show_progress() {
local pid=$1
local message=$2
local i=0
local dots=""
# 检查进程是否存在
if ! kill -0 "$pid" 2>/dev/null; then
# 进程已经结束,立即返回
return 0
fi
while kill -0 "$pid" 2>/dev/null; do
i=$((i + 1))
case $((i % 4)) in
0) dots="." ;;
1) dots=".." ;;
2) dots="..." ;;
3) dots="...." ;;
esac
printf "\r${BLUE}⏳ %s%s${NC}" "$message" "$dots"
sleep 0.5
# 再次检查进程是否还存在
if ! kill -0 "$pid" 2>/dev/null; then
break
fi
done
printf "\r"
}
echo ""
echo "=========================================="
echo " CyberStrikeAI 一键部署启动脚本"
echo "=========================================="
echo ""
# 显示临时源配置信息
echo ""
warning "⚠️ 注意:此脚本将使用临时镜像源加速下载"
echo ""
info "Python pip 临时镜像源:"
echo " ${PIP_INDEX_URL}"
info "Go Proxy 临时镜像源:"
echo " ${GOPROXY}"
echo ""
note "这些设置仅在脚本运行期间生效,不会修改系统配置"
echo ""
sleep 1
CONFIG_FILE="$ROOT_DIR/config.yaml"
VENV_DIR="$ROOT_DIR/venv"
REQUIREMENTS_FILE="$ROOT_DIR/requirements.txt"
BINARY_NAME="cyberstrike-ai"
# 检查配置文件
if [ ! -f "$CONFIG_FILE" ]; then
error "配置文件 config.yaml 不存在"
info "请确保在项目根目录运行此脚本"
exit 1
fi
# 检查并安装 Python 环境
check_python() {
if ! command -v python3 >/dev/null 2>&1; then
error "未找到 python3"
echo ""
info "请先安装 Python 3.10 或更高版本:"
echo " macOS: brew install python3"
echo " Ubuntu: sudo apt-get install python3 python3-venv"
echo " CentOS: sudo yum install python3 python3-pip"
exit 1
fi
PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}')
PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
if [ "$PYTHON_MAJOR" -lt 3 ] || ([ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]); then
error "Python 版本过低: $PYTHON_VERSION (需要 3.10+)"
exit 1
fi
success "Python 环境检查通过: $PYTHON_VERSION"
}
# 检查并安装 Go 环境
check_go() {
if ! command -v go >/dev/null 2>&1; then
error "未找到 Go"
echo ""
info "请先安装 Go 1.21 或更高版本:"
echo " macOS: brew install go"
echo " Ubuntu: sudo apt-get install golang-go"
echo " CentOS: sudo yum install golang"
echo " 或访问: https://go.dev/dl/"
exit 1
fi
GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//')
GO_MAJOR=$(echo "$GO_VERSION" | cut -d. -f1)
GO_MINOR=$(echo "$GO_VERSION" | cut -d. -f2)
if [ "$GO_MAJOR" -lt 1 ] || ([ "$GO_MAJOR" -eq 1 ] && [ "$GO_MINOR" -lt 21 ]); then
error "Go 版本过低: $GO_VERSION (需要 1.21+)"
exit 1
fi
success "Go 环境检查通过: $(go version)"
}
# 设置 Python 虚拟环境
setup_python_env() {
if [ ! -d "$VENV_DIR" ]; then
info "创建 Python 虚拟环境..."
python3 -m venv "$VENV_DIR"
success "虚拟环境创建完成"
else
info "Python 虚拟环境已存在"
fi
info "激活虚拟环境..."
# shellcheck disable=SC1091
source "$VENV_DIR/bin/activate"
if [ -f "$REQUIREMENTS_FILE" ]; then
echo ""
note "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
note "⚠️ 使用临时 pip 镜像源(仅本次脚本运行有效)"
note " 镜像地址: ${PIP_INDEX_URL}"
note " 如需永久配置,请设置环境变量 PIP_INDEX_URL"
note "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
info "升级 pip..."
pip install --index-url "$PIP_INDEX_URL" --upgrade pip >/dev/null 2>&1 || true
info "安装 Python 依赖包..."
echo ""
# 尝试安装依赖,捕获错误输出并显示进度
PIP_LOG=$(mktemp)
(
set +e # 在子shell中禁用错误退出
pip install --index-url "$PIP_INDEX_URL" -r "$REQUIREMENTS_FILE" >"$PIP_LOG" 2>&1
echo $? > "${PIP_LOG}.exit"
) &
PIP_PID=$!
# 等待一小段时间,确保进程启动
sleep 0.1
# 显示进度(如果进程还在运行)
if kill -0 "$PIP_PID" 2>/dev/null; then
show_progress "$PIP_PID" "正在安装依赖包"
else
# 进程已经结束,等待一下确保退出码文件已写入
sleep 0.2
fi
# 等待进程完成,忽略 wait 的退出码
wait "$PIP_PID" 2>/dev/null || true
PIP_EXIT_CODE=0
if [ -f "${PIP_LOG}.exit" ]; then
PIP_EXIT_CODE=$(cat "${PIP_LOG}.exit" 2>/dev/null || echo "1")
rm -f "${PIP_LOG}.exit" 2>/dev/null || true
else
# 如果没有退出码文件,检查日志中是否有错误
if [ -f "$PIP_LOG" ] && grep -q -i "error\|failed\|exception" "$PIP_LOG" 2>/dev/null; then
PIP_EXIT_CODE=1
fi
fi
if [ $PIP_EXIT_CODE -eq 0 ]; then
success "Python 依赖安装完成"
else
# 检查是否是 angr 安装失败(需要 Rust
if grep -q "angr" "$PIP_LOG" && grep -q "Rust compiler\|can't find Rust" "$PIP_LOG"; then
warning "angr 安装失败(需要 Rust 编译器)"
echo ""
info "angr 是可选依赖,主要用于二进制分析工具"
info "如果需要使用 angr请先安装 Rust"
echo " macOS: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
echo " Ubuntu: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
echo " 或访问: https://rustup.rs/"
echo ""
info "其他依赖已安装,可以继续使用(部分工具可能不可用)"
else
warning "部分 Python 依赖安装失败,但可以继续尝试运行"
warning "如果遇到问题,请检查错误信息并手动安装缺失的依赖"
# 显示最后几行错误信息
echo ""
info "错误详情(最后 10 行):"
tail -n 10 "$PIP_LOG" | sed 's/^/ /'
echo ""
fi
fi
rm -f "$PIP_LOG"
else
warning "未找到 requirements.txt跳过 Python 依赖安装"
fi
}
# 构建 Go 项目
build_go_project() {
echo ""
note "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
note "⚠️ 使用临时 Go Proxy仅本次脚本运行有效"
note " Proxy 地址: ${GOPROXY}"
note " 如需永久配置,请设置环境变量 GOPROXY"
note "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
info "下载 Go 依赖..."
GO_DOWNLOAD_LOG=$(mktemp)
(
set +e # 在子shell中禁用错误退出
export GOPROXY="$GOPROXY"
go mod download >"$GO_DOWNLOAD_LOG" 2>&1
echo $? > "${GO_DOWNLOAD_LOG}.exit"
) &
GO_DOWNLOAD_PID=$!
# 等待一小段时间,确保进程启动
sleep 0.1
# 显示进度(如果进程还在运行)
if kill -0 "$GO_DOWNLOAD_PID" 2>/dev/null; then
show_progress "$GO_DOWNLOAD_PID" "正在下载 Go 依赖"
else
# 进程已经结束,等待一下确保退出码文件已写入
sleep 0.2
fi
# 等待进程完成,忽略 wait 的退出码
wait "$GO_DOWNLOAD_PID" 2>/dev/null || true
GO_DOWNLOAD_EXIT_CODE=0
if [ -f "${GO_DOWNLOAD_LOG}.exit" ]; then
GO_DOWNLOAD_EXIT_CODE=$(cat "${GO_DOWNLOAD_LOG}.exit" 2>/dev/null || echo "1")
rm -f "${GO_DOWNLOAD_LOG}.exit" 2>/dev/null || true
else
# 如果没有退出码文件,检查日志中是否有错误
if [ -f "$GO_DOWNLOAD_LOG" ] && grep -q -i "error\|failed" "$GO_DOWNLOAD_LOG" 2>/dev/null; then
GO_DOWNLOAD_EXIT_CODE=1
fi
fi
rm -f "$GO_DOWNLOAD_LOG" 2>/dev/null || true
if [ $GO_DOWNLOAD_EXIT_CODE -ne 0 ]; then
error "Go 依赖下载失败"
exit 1
fi
success "Go 依赖下载完成"
info "构建项目..."
GO_BUILD_LOG=$(mktemp)
(
set +e # 在子shell中禁用错误退出
export GOPROXY="$GOPROXY"
go build -o "$BINARY_NAME" cmd/server/main.go >"$GO_BUILD_LOG" 2>&1
echo $? > "${GO_BUILD_LOG}.exit"
) &
GO_BUILD_PID=$!
# 等待一小段时间,确保进程启动
sleep 0.1
# 显示进度(如果进程还在运行)
if kill -0 "$GO_BUILD_PID" 2>/dev/null; then
show_progress "$GO_BUILD_PID" "正在构建项目"
else
# 进程已经结束,等待一下确保退出码文件已写入
sleep 0.2
fi
# 等待进程完成,忽略 wait 的退出码
wait "$GO_BUILD_PID" 2>/dev/null || true
GO_BUILD_EXIT_CODE=0
if [ -f "${GO_BUILD_LOG}.exit" ]; then
GO_BUILD_EXIT_CODE=$(cat "${GO_BUILD_LOG}.exit" 2>/dev/null || echo "1")
rm -f "${GO_BUILD_LOG}.exit" 2>/dev/null || true
else
# 如果没有退出码文件,检查日志中是否有错误
if [ -f "$GO_BUILD_LOG" ] && grep -q -i "error\|failed" "$GO_BUILD_LOG" 2>/dev/null; then
GO_BUILD_EXIT_CODE=1
fi
fi
if [ $GO_BUILD_EXIT_CODE -eq 0 ]; then
success "项目构建完成: $BINARY_NAME"
rm -f "$GO_BUILD_LOG"
else
error "项目构建失败"
# 显示构建错误
echo ""
info "构建错误详情:"
cat "$GO_BUILD_LOG" | sed 's/^/ /'
echo ""
rm -f "$GO_BUILD_LOG"
exit 1
fi
}
# 检查是否需要重新构建
need_rebuild() {
if [ ! -f "$BINARY_NAME" ]; then
return 0 # 需要构建
fi
# 检查源代码是否有更新
if [ "$BINARY_NAME" -ot cmd/server/main.go ] || \
[ "$BINARY_NAME" -ot go.mod ] || \
find internal cmd -name "*.go" -newer "$BINARY_NAME" 2>/dev/null | grep -q .; then
return 0 # 需要重新构建
fi
return 1 # 不需要构建
}
# 主流程
main() {
# 环境检查
info "检查运行环境..."
check_python
check_go
echo ""
# 设置 Python 环境
info "设置 Python 环境..."
setup_python_env
echo ""
# 构建 Go 项目
if need_rebuild; then
info "准备构建项目..."
build_go_project
else
success "可执行文件已是最新,跳过构建"
fi
echo ""
# 启动服务器
success "所有准备工作完成!"
echo ""
info "启动 CyberStrikeAI 服务器..."
echo "=========================================="
echo ""
# 运行服务器
exec "./$BINARY_NAME"
}
# 执行主流程
main