From 846d35d112606b59aac7f78da93f408910e116dd Mon Sep 17 00:00:00 2001 From: Jeason <1710884619@qq.com> Date: Tue, 17 Mar 2026 09:41:37 +0800 Subject: [PATCH] =?UTF-8?q?linux=E5=AE=89=E8=A3=85=E4=BC=98=E5=8C=96=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- init-db.sql | 48 +++++----- qrcode.png | Bin 3350 -> 0 bytes setup_linux.sh | 245 +++++++++++++++++++++++++++++++++++++++++++++++++ start_linux.sh | 105 +++++++++++++++++++++ stop_linux.sh | 67 ++++++++++++++ 5 files changed, 441 insertions(+), 24 deletions(-) delete mode 100644 qrcode.png create mode 100644 setup_linux.sh create mode 100644 start_linux.sh create mode 100644 stop_linux.sh diff --git a/init-db.sql b/init-db.sql index f1d2b79..fa87c33 100644 --- a/init-db.sql +++ b/init-db.sql @@ -1,15 +1,24 @@ -- Weibo-HotSign Database Initialization Script for MySQL --- Create tables according to development document specification +-- 创建数据库和表结构 + +CREATE DATABASE IF NOT EXISTS weibo_hotsign DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +USE weibo_hotsign; -- Users table CREATE TABLE IF NOT EXISTS users ( id CHAR(36) PRIMARY KEY, username VARCHAR(50) UNIQUE NOT NULL, - email VARCHAR(255) UNIQUE NOT NULL, - hashed_password VARCHAR(255) NOT NULL, + email VARCHAR(255) UNIQUE, + hashed_password VARCHAR(255), + wx_openid VARCHAR(64) UNIQUE, + wx_nickname VARCHAR(100), + wx_avatar VARCHAR(500), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - is_active BOOLEAN DEFAULT TRUE -); + is_active BOOLEAN DEFAULT TRUE, + INDEX idx_users_email (email), + INDEX idx_users_username (username), + INDEX idx_users_wx_openid (wx_openid) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Accounts table CREATE TABLE IF NOT EXISTS accounts ( @@ -22,8 +31,10 @@ CREATE TABLE IF NOT EXISTS accounts ( status VARCHAR(20) DEFAULT 'pending', last_checked_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_accounts_user_id (user_id), + INDEX idx_accounts_status (status), FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -); +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Tasks table CREATE TABLE IF NOT EXISTS tasks ( @@ -32,8 +43,10 @@ CREATE TABLE IF NOT EXISTS tasks ( cron_expression VARCHAR(50) NOT NULL, is_enabled BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_tasks_account_id (account_id), + INDEX idx_tasks_is_enabled (is_enabled), FOREIGN KEY (account_id) REFERENCES accounts(id) ON DELETE CASCADE -); +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Signin logs table CREATE TABLE IF NOT EXISTS signin_logs ( @@ -44,21 +57,8 @@ CREATE TABLE IF NOT EXISTS signin_logs ( reward_info JSON, error_message TEXT, signed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_signin_logs_account_id (account_id), + INDEX idx_signin_logs_signed_at (signed_at), + INDEX idx_signin_logs_status (status), FOREIGN KEY (account_id) REFERENCES accounts(id) -); - --- Create indexes for better performance -CREATE INDEX idx_users_email ON users(email); -CREATE INDEX idx_users_username ON users(username); -CREATE INDEX idx_accounts_user_id ON accounts(user_id); -CREATE INDEX idx_accounts_status ON accounts(status); -CREATE INDEX idx_tasks_account_id ON tasks(account_id); -CREATE INDEX idx_tasks_is_enabled ON tasks(is_enabled); -CREATE INDEX idx_signin_logs_account_id ON signin_logs(account_id); -CREATE INDEX idx_signin_logs_signed_at ON signin_logs(signed_at); -CREATE INDEX idx_signin_logs_status ON signin_logs(status); - --- Insert sample data for testing (optional) --- Note: UUIDs must be provided by the application --- INSERT INTO users (id, username, email, hashed_password) VALUES --- ('your-uuid-here', 'testuser', 'test@example.com', '$2b$12$hashed_password_here'); +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/qrcode.png b/qrcode.png deleted file mode 100644 index 6a25cce8b943de48c4f43fabde3dc2d44bf971ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3350 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 X6uf>hnD)Cv2i7*!D!=>iIop2#u`zfv diff --git a/setup_linux.sh b/setup_linux.sh new file mode 100644 index 0000000..09d5a96 --- /dev/null +++ b/setup_linux.sh @@ -0,0 +1,245 @@ +#!/bin/bash +set -e + +# ============================================================ +# Weibo-HotSign Linux 安装运行脚本 +# 使用方式: chmod +x setup_linux.sh && ./setup_linux.sh +# ============================================================ + +# ===================== 请在此处填写配置 ===================== + +MYSQL_HOST="127.0.0.1" +MYSQL_PORT="3306" +MYSQL_USER="root" +MYSQL_PASSWORD="" # ← 填写你的 MySQL 密码 + +REDIS_HOST="127.0.0.1" +REDIS_PORT="6379" +REDIS_PASSWORD="" # ← 填写你的 Redis 密码(没有密码留空) + +# JWT 密钥(生产环境请改成随机长字符串) +JWT_SECRET="change-me-to-a-random-string-in-production" + +# Cookie 加密密钥(32 字节) +COOKIE_KEY="change-me-to-a-32byte-key-prod!" + +# 微信小程序(可选,暂时留空) +WX_APPID="" +WX_SECRET="" + +# 服务端口 +AUTH_PORT=8001 +API_PORT=8000 +FRONTEND_PORT=5000 + +# ===================== 配置结束 ===================== + +PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" +DB_NAME="weibo_hotsign" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +info() { echo -e "${GREEN}[✓]${NC} $1"; } +warn() { echo -e "${YELLOW}[!]${NC} $1"; } +error() { echo -e "${RED}[✗]${NC} $1"; exit 1; } + +echo "" +echo "========================================" +echo " Weibo-HotSign Linux 安装脚本" +echo "========================================" +echo "" + +# ------ 1. 检查系统依赖 ------ + +echo "--- 检查系统依赖 ---" + +command -v python3 >/dev/null 2>&1 || error "未找到 python3,请先安装 Python 3.8+" +PYTHON_VER=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') +info "Python $PYTHON_VER" + +command -v pip3 >/dev/null 2>&1 || command -v pip >/dev/null 2>&1 || error "未找到 pip,请先安装 pip" +PIP_CMD=$(command -v pip3 || command -v pip) +info "pip: $PIP_CMD" + +# ------ 2. 检查 MySQL ------ + +echo "" +echo "--- 检查 MySQL ---" + +command -v mysql >/dev/null 2>&1 || error "未找到 mysql 客户端,请先安装 mysql-client" + +MYSQL_CMD="mysql -h${MYSQL_HOST} -P${MYSQL_PORT} -u${MYSQL_USER}" +if [ -n "$MYSQL_PASSWORD" ]; then + MYSQL_CMD="$MYSQL_CMD -p${MYSQL_PASSWORD}" +fi + +# 测试连接 +if $MYSQL_CMD -e "SELECT 1" >/dev/null 2>&1; then + info "MySQL 连接成功 (${MYSQL_HOST}:${MYSQL_PORT})" +else + error "MySQL 连接失败,请检查地址、端口和密码" +fi + +# ------ 3. 检查 Redis ------ + +echo "" +echo "--- 检查 Redis ---" + +command -v redis-cli >/dev/null 2>&1 || error "未找到 redis-cli,请先安装 redis-tools" + +REDIS_CLI="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT}" +if [ -n "$REDIS_PASSWORD" ]; then + REDIS_CLI="$REDIS_CLI -a ${REDIS_PASSWORD}" +fi + +REDIS_PING=$($REDIS_CLI --no-auth-warning PING 2>/dev/null || true) +if [ "$REDIS_PING" = "PONG" ]; then + info "Redis 连接成功 (${REDIS_HOST}:${REDIS_PORT})" +else + error "Redis 连接失败,请检查地址、端口和密码" +fi + +# ------ 4. 初始化 MySQL 数据库 ------ + +echo "" +echo "--- 初始化 MySQL 数据库 ---" + +if $MYSQL_CMD -e "USE ${DB_NAME}" >/dev/null 2>&1; then + # 数据库已存在,检查是否需要加微信字段 + HAS_WX=$($MYSQL_CMD -N -e "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='${DB_NAME}' AND TABLE_NAME='users' AND COLUMN_NAME='wx_openid'" 2>/dev/null) + if [ "$HAS_WX" = "0" ]; then + warn "数据库已存在,正在添加微信登录字段..." + $MYSQL_CMD ${DB_NAME} -e " + ALTER TABLE users ADD COLUMN wx_openid VARCHAR(64) UNIQUE AFTER hashed_password; + ALTER TABLE users ADD COLUMN wx_nickname VARCHAR(100) AFTER wx_openid; + ALTER TABLE users ADD COLUMN wx_avatar VARCHAR(500) AFTER wx_nickname; + ALTER TABLE users MODIFY COLUMN email VARCHAR(255) NULL; + ALTER TABLE users MODIFY COLUMN hashed_password VARCHAR(255) NULL; + " 2>/dev/null || true + info "微信字段已添加" + else + info "数据库 ${DB_NAME} 已存在且结构完整" + fi +else + info "正在创建数据库和表..." + $MYSQL_CMD < "${PROJECT_DIR}/init-db.sql" + info "数据库 ${DB_NAME} 创建完成" +fi + +# 创建测试用户(如果 users 表为空) +USER_COUNT=$($MYSQL_CMD -N -e "SELECT COUNT(*) FROM ${DB_NAME}.users" 2>/dev/null) +if [ "$USER_COUNT" = "0" ]; then + info "正在创建测试用户..." + # 用 python 生成 bcrypt 密码 + HASHED_PW=$(python3 -c "import bcrypt; print(bcrypt.hashpw(b'Admin123!', bcrypt.gensalt(12)).decode())") + USER_ID=$(python3 -c "import uuid; print(str(uuid.uuid4()))") + $MYSQL_CMD ${DB_NAME} -e " + INSERT INTO users (id, username, email, hashed_password, is_active) + VALUES ('${USER_ID}', 'admin', 'admin@example.com', '${HASHED_PW}', 1); + " + info "测试用户: admin / Admin123!" +fi + +# ------ 5. 构建 Redis URL ------ + +if [ -n "$REDIS_PASSWORD" ]; then + REDIS_URL="redis://:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT}/0" +else + REDIS_URL="redis://${REDIS_HOST}:${REDIS_PORT}/0" +fi + +# ------ 6. 构建 MySQL URL ------ + +if [ -n "$MYSQL_PASSWORD" ]; then + MYSQL_URL="mysql+aiomysql://${MYSQL_USER}:${MYSQL_PASSWORD}@${MYSQL_HOST}:${MYSQL_PORT}/${DB_NAME}?charset=utf8mb4" +else + MYSQL_URL="mysql+aiomysql://${MYSQL_USER}@${MYSQL_HOST}:${MYSQL_PORT}/${DB_NAME}?charset=utf8mb4" +fi + +# ------ 7. 生成 .env 文件 ------ + +echo "" +echo "--- 生成配置文件 ---" + +cat > "${PROJECT_DIR}/backend/.env" << EOF +# ===== 由 setup_linux.sh 自动生成 ===== + +# MySQL +DATABASE_URL=${MYSQL_URL} + +# Redis +USE_REDIS=true +REDIS_URL=${REDIS_URL} + +# JWT +JWT_SECRET_KEY=${JWT_SECRET} +JWT_ALGORITHM=HS256 +JWT_EXPIRATION_HOURS=24 + +# Cookie 加密 +COOKIE_ENCRYPTION_KEY=${COOKIE_KEY} + +# 微信小程序 +WX_APPID=${WX_APPID} +WX_SECRET=${WX_SECRET} + +# 环境 +ENVIRONMENT=production +EOF +info "backend/.env 已生成" + +cat > "${PROJECT_DIR}/frontend/.env" << EOF +# ===== 由 setup_linux.sh 自动生成 ===== + +FLASK_ENV=production +FLASK_DEBUG=False +SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))") + +API_BASE_URL=http://127.0.0.1:${API_PORT} +AUTH_BASE_URL=http://127.0.0.1:${AUTH_PORT} + +SESSION_TYPE=filesystem +EOF +info "frontend/.env 已生成" + +# ------ 8. 创建虚拟环境并安装依赖 ------ + +echo "" +echo "--- 安装 Python 依赖 ---" + +# 后端 +if [ ! -d "${PROJECT_DIR}/backend/venv" ]; then + info "创建后端虚拟环境..." + python3 -m venv "${PROJECT_DIR}/backend/venv" +fi +source "${PROJECT_DIR}/backend/venv/bin/activate" +pip install -q --upgrade pip +pip install -q -r "${PROJECT_DIR}/backend/requirements.txt" +deactivate +info "后端依赖安装完成" + +# 前端 +if [ ! -d "${PROJECT_DIR}/frontend/venv" ]; then + info "创建前端虚拟环境..." + python3 -m venv "${PROJECT_DIR}/frontend/venv" +fi +source "${PROJECT_DIR}/frontend/venv/bin/activate" +pip install -q --upgrade pip +pip install -q -r "${PROJECT_DIR}/frontend/requirements.txt" +deactivate +info "前端依赖安装完成" + +echo "" +echo "========================================" +echo " 安装完成!" +echo "========================================" +echo "" +echo " MySQL: ${MYSQL_HOST}:${MYSQL_PORT} / ${DB_NAME}" +echo " Redis: ${REDIS_HOST}:${REDIS_PORT}" +echo "" +echo " 启动服务: ./start_linux.sh" +echo " 停止服务: ./stop_linux.sh" +echo "" diff --git a/start_linux.sh b/start_linux.sh new file mode 100644 index 0000000..32858cd --- /dev/null +++ b/start_linux.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +# ============================================================ +# Weibo-HotSign Linux 启动脚本 +# 使用方式: chmod +x start_linux.sh && ./start_linux.sh +# ============================================================ + +PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" +PID_DIR="${PROJECT_DIR}/.pids" +LOG_DIR="${PROJECT_DIR}/logs" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +info() { echo -e "${GREEN}[✓]${NC} $1"; } +warn() { echo -e "${YELLOW}[!]${NC} $1"; } +error() { echo -e "${RED}[✗]${NC} $1"; exit 1; } + +# 创建目录 +mkdir -p "$PID_DIR" "$LOG_DIR" + +# 检查是否已在运行 +check_running() { + local name=$1 + local pidfile="${PID_DIR}/${name}.pid" + if [ -f "$pidfile" ]; then + local pid=$(cat "$pidfile") + if kill -0 "$pid" 2>/dev/null; then + warn "${name} 已在运行 (PID: ${pid}),跳过" + return 0 + else + rm -f "$pidfile" + fi + fi + return 1 +} + +echo "" +echo "========================================" +echo " Weibo-HotSign 启动服务" +echo "========================================" +echo "" + +# ------ 1. 启动 Auth Service (端口 8001) ------ + +if ! check_running "auth_service"; then + info "启动 Auth Service (端口 8001)..." + source "${PROJECT_DIR}/backend/venv/bin/activate" + cd "${PROJECT_DIR}/backend" + PYTHONPATH="${PROJECT_DIR}/backend" nohup python -m uvicorn auth_service.app.main:app \ + --host 0.0.0.0 --port 8001 \ + > "${LOG_DIR}/auth_service.log" 2>&1 & + echo $! > "${PID_DIR}/auth_service.pid" + deactivate + cd "${PROJECT_DIR}" + sleep 2 + info "Auth Service 已启动 (PID: $(cat ${PID_DIR}/auth_service.pid))" +fi + +# ------ 2. 启动 API Service (端口 8000) ------ + +if ! check_running "api_service"; then + info "启动 API Service (端口 8000)..." + source "${PROJECT_DIR}/backend/venv/bin/activate" + cd "${PROJECT_DIR}/backend" + PYTHONPATH="${PROJECT_DIR}/backend" nohup python -m uvicorn api_service.app.main:app \ + --host 0.0.0.0 --port 8000 \ + > "${LOG_DIR}/api_service.log" 2>&1 & + echo $! > "${PID_DIR}/api_service.pid" + deactivate + cd "${PROJECT_DIR}" + sleep 2 + info "API Service 已启动 (PID: $(cat ${PID_DIR}/api_service.pid))" +fi + +# ------ 3. 启动 Frontend (端口 5000) ------ + +if ! check_running "frontend"; then + info "启动 Frontend (端口 5000)..." + source "${PROJECT_DIR}/frontend/venv/bin/activate" + cd "${PROJECT_DIR}/frontend" + nohup python app.py \ + > "${LOG_DIR}/frontend.log" 2>&1 & + echo $! > "${PID_DIR}/frontend.pid" + deactivate + cd "${PROJECT_DIR}" + sleep 2 + info "Frontend 已启动 (PID: $(cat ${PID_DIR}/frontend.pid))" +fi + +echo "" +echo "========================================" +echo " 所有服务已启动" +echo "========================================" +echo "" +echo " 前端界面: http://localhost:5000" +echo " API Service: http://localhost:8000" +echo " Auth Service: http://localhost:8001" +echo "" +echo " 日志目录: ${LOG_DIR}/" +echo " 停止服务: ./stop_linux.sh" +echo " 查看日志: tail -f logs/auth_service.log" +echo "" diff --git a/stop_linux.sh b/stop_linux.sh new file mode 100644 index 0000000..a31a988 --- /dev/null +++ b/stop_linux.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# ============================================================ +# Weibo-HotSign Linux 停止脚本 +# 使用方式: chmod +x stop_linux.sh && ./stop_linux.sh +# ============================================================ + +PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" +PID_DIR="${PROJECT_DIR}/.pids" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +info() { echo -e "${GREEN}[✓]${NC} $1"; } +warn() { echo -e "${YELLOW}[!]${NC} $1"; } + +echo "" +echo "========================================" +echo " Weibo-HotSign 停止服务" +echo "========================================" +echo "" + +SERVICES=("auth_service" "api_service" "frontend") +SERVICE_NAMES=("Auth Service" "API Service" "Frontend") + +stopped=0 + +for i in "${!SERVICES[@]}"; do + name="${SERVICES[$i]}" + display="${SERVICE_NAMES[$i]}" + pidfile="${PID_DIR}/${name}.pid" + + if [ -f "$pidfile" ]; then + pid=$(cat "$pidfile") + if kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null + # 等待进程退出(最多 5 秒) + for j in $(seq 1 10); do + if ! kill -0 "$pid" 2>/dev/null; then + break + fi + sleep 0.5 + done + # 如果还没退出,强制杀 + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null + fi + info "${display} 已停止 (PID: ${pid})" + stopped=$((stopped + 1)) + else + warn "${display} 进程不存在 (PID: ${pid})" + fi + rm -f "$pidfile" + else + warn "${display} 未在运行" + fi +done + +echo "" +if [ $stopped -gt 0 ]; then + info "已停止 ${stopped} 个服务" +else + warn "没有正在运行的服务" +fi +echo ""