#!/usr/bin/env bash set -e # Sanguo Mail 系统管理脚本 # 支持启动、停止、配置、健康检查等操作 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # 日志函数 log() { local level="$1" local message="$2" local color case "$level" in "error") color="$RED" ;; "warning") color="$YELLOW" ;; "info") color="$BLUE" ;; "success") color="$GREEN" ;; *) color="$NC" ;; esac local timestamp=$(date +"%Y-%m-%d %H:%M:%S") local level_uppercase=$(echo "$level" | tr '[:lower:]' '[:upper:]') echo -e "${color}[${timestamp}] [${level_uppercase}] ${message}${NC}" } # 配置常量 PROJECT_ROOT="/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live" MAIL_PROJECT_DIR="$PROJECT_ROOT/mail" SCRIPTS_DIR="$PROJECT_ROOT/scripts" # 检查节点是否在线 check_node() { log "info" "检查节点连接..." openclaw nodes list >/dev/null 2>&1 if [ $? -eq 0 ]; then log "success" "节点连接正常" else log "error" "节点连接失败,请确保 OpenClaw 服务正在运行" exit 1 fi } # 获取服务配置 get_config() { local config_file="$SCRIPTS_DIR/config.json" if [ -f "$config_file" ]; then cat "$config_file" else cat << 'EOF' { "server": { "port": 18888, "host": "0.0.0.0", "timeout": 30000 }, "api": { "baseUrl": "http://127.0.0.1:18888", "timeout": 10000 }, "mailSystem": { "rootPath": "/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live", "teamName": "sanguo-quant" }, "autoCheck": { "interval": 60, "enabled": true } } EOF fi } # 设置配置 set_config() { local config_file="$SCRIPTS_DIR/config.json" local config=$(get_config) local key="$1" local value="$2" if [ -z "$key" ] || [ -z "$value" ]; then log "error" "设置配置需要提供配置项和值" log "usage" "使用方法: $0 config set " exit 1 fi log "info" "正在设置 $key = $value" if [ -f "$config_file" ]; then jq ".${key} = \"${value}\"" "$config_file" > "${config_file}.tmp" && mv "${config_file}.tmp" "$config_file" else local default_config=$(get_config | jq ".${key} = \"${value}\"") echo "$default_config" > "$config_file" fi log "success" "配置已更新" log "info" "重启服务使配置生效" } # 启动服务 start_server() { log "info" "正在启动 Sanguo Mail 服务..." # 检查项目是否已安装 if [ ! -d "$PROJECT_ROOT" ]; then log "error" "项目根目录不存在: $PROJECT_ROOT" exit 1 fi # 检查依赖 if [ ! -d "$PROJECT_ROOT/node_modules" ]; then log "info" "依赖未安装,正在安装..." install_deps fi # 检查邮件系统初始化 if [ ! -d "$PROJECT_ROOT/mail/sanguo-quant/inboxes" ] || [ ! -f "$PROJECT_ROOT/mail/sanguo-quant/team.json" ]; then log "info" "邮件系统未初始化,正在初始化..." init_system fi # 启动服务 log "info" "正在启动邮件服务进程..." node "$SCRIPTS_DIR/server.js" > "$SCRIPTS_DIR/mail-service.log" 2>&1 & local PID=$! # 保存 PID echo "$PID" > "$SCRIPTS_DIR/mail.pid" # 等待服务启动 log "info" "等待服务启动..." sleep 2 # 检查服务是否正在运行 if ps -p "$PID" > /dev/null 2>&1; then log "success" "服务启动成功,PID: $PID" log "success" "服务日志: $SCRIPTS_DIR/mail-service.log" log "success" "访问地址: http://127.0.0.1:18888" else log "error" "服务启动失败" if [ -f "$SCRIPTS_DIR/mail-service.log" ]; then log "error" "错误日志: $(head -20 "$SCRIPTS_DIR/mail-service.log")" fi exit 1 fi } # 停止服务 stop_server() { local PID_FILE="$SCRIPTS_DIR/mail.pid" if [ -f "$PID_FILE" ]; then local PID=$(cat "$PID_FILE") log "info" "正在停止服务,PID: $PID" if ps -p "$PID" > /dev/null 2>&1; then kill "$PID" log "success" "服务已停止" else log "warning" "服务已停止 (PID $PID 不存在)" fi rm -f "$PID_FILE" else log "warning" "服务 PID 文件不存在,可能服务未运行" # 尝试查找并停止进程 local PROCESS=$(ps aux | grep "node $SCRIPTS_DIR/server.js" | grep -v grep | awk '{print $2}') if [ -n "$PROCESS" ]; then log "info" "找到服务进程,PID: $PROCESS" kill "$PROCESS" log "success" "服务已停止" fi fi } # 查看服务状态 status() { log "info" "=== 系统状态 ===" # 检查项目根目录 if [ -d "$PROJECT_ROOT" ]; then log "success" "项目根目录存在: $PROJECT_ROOT" else log "error" "项目根目录不存在: $PROJECT_ROOT" fi # 检查邮件系统目录 MAIL_DIR="$PROJECT_ROOT/mail/sanguo-quant" if [ -d "$MAIL_DIR" ]; then log "success" "邮件系统目录存在: $MAIL_DIR" else log "warning" "邮件系统目录不存在: $MAIL_DIR" fi # 检查收件箱 if [ -d "$MAIL_DIR/inboxes" ]; then log "success" "收件箱目录存在: $MAIL_DIR/inboxes" # 统计收件箱文件数量 local inbox_count=$(ls -1 "$MAIL_DIR/inboxes"/*.json 2>/dev/null | wc -l) log "success" "收件箱数量: $inbox_count" else log "warning" "收件箱目录不存在: $MAIL_DIR/inboxes" fi # 检查成员配置 TEAM_CONFIG="$MAIL_DIR/team.json" if [ -f "$TEAM_CONFIG" ]; then log "success" "团队配置文件存在: $TEAM_CONFIG" # 统计团队成员数量 local member_count=$(jq '.members | length' "$TEAM_CONFIG" 2>/dev/null || echo 0) log "success" "团队成员数量: $member_count" else log "warning" "团队配置文件不存在: $TEAM_CONFIG" fi # 检查服务状态 if [ -f "$SCRIPTS_DIR/mail.pid" ]; then local PID=$(cat "$SCRIPTS_DIR/mail.pid") if ps -p "$PID" > /dev/null 2>&1; then log "success" "服务正在运行,PID: $PID" else log "warning" "PID 文件存在,但进程未运行" rm -f "$SCRIPTS_DIR/mail.pid" fi else log "warning" "服务未运行" fi } # 查看日志 logs() { local LOG_FILE="$SCRIPTS_DIR/mail-service.log" if [ ! -f "$LOG_FILE" ]; then log "error" "日志文件不存在: $LOG_FILE" exit 1 fi if [ -z "$2" ]; then tail -f "$LOG_FILE" else log "info" "显示最后 $2 行日志" tail -"$2" "$LOG_FILE" fi } # 健康检查 check_health() { log "info" "正在进行健康检查..." local ERROR_COUNT=0 local WARNING_COUNT=0 # 检查依赖 if [ ! -d "$PROJECT_ROOT/node_modules" ]; then log "error" "依赖未安装" ERROR_COUNT=$((ERROR_COUNT + 1)) else log "success" "依赖已安装" fi # 检查邮件系统初始化 if [ ! -d "$PROJECT_ROOT/mail/sanguo-quant/inboxes" ] || [ ! -f "$PROJECT_ROOT/mail/sanguo-quant/team.json" ]; then log "warning" "邮件系统未初始化" WARNING_COUNT=$((WARNING_COUNT + 1)) else log "success" "邮件系统已初始化" fi # 检查服务状态 if [ -f "$SCRIPTS_DIR/mail.pid" ]; then local PID=$(cat "$SCRIPTS_DIR/mail.pid") if ps -p "$PID" > /dev/null 2>&1; then log "success" "服务正在运行,PID: $PID" else log "error" "PID 文件存在,但进程未运行" ERROR_COUNT=$((ERROR_COUNT + 1)) fi else log "warning" "服务未运行" WARNING_COUNT=$((WARNING_COUNT + 1)) fi log "info" "=== 健康检查结果 ===" log "success" "成功项: $((4 - ERROR_COUNT - WARNING_COUNT))" if [ "$WARNING_COUNT" -gt 0 ]; then log "warning" "警告项: $WARNING_COUNT" fi if [ "$ERROR_COUNT" -gt 0 ]; then log "error" "错误项: $ERROR_COUNT" exit 1 fi log "success" "系统健康状况良好" } # 检查安全配置 check_security() { if [ ! -f "/Users/chufeng/.openclaw/config/security.json" ]; then log "warning" "安全配置文件未找到,使用默认策略" return 0 fi local security_level=$(jq -r '.security_level' "/Users/chufeng/.openclaw/config/security.json") log "info" "当前安全级别: $security_level" if [ "$security_level" != "full" ]; then log "warning" "安全级别不是 full,可能会影响邮件系统功能" fi } # 列出配置 list_config() { log "info" "=== 当前配置 ===" log "info" "项目根目录: $PROJECT_ROOT" log "info" "邮件系统目录: $MAIL_PROJECT_DIR" log "info" "脚本目录: $SCRIPTS_DIR" # 显示配置文件内容 if [ -f "$SCRIPTS_DIR/config.json" ]; then log "info" "配置文件内容:" cat "$SCRIPTS_DIR/config.json" else log "warning" "配置文件未找到,使用默认值" fi } # 启动邮件检查服务 watch_mail() { log "info" "正在启动邮件检查服务..." local interval=${2:-60} log "info" "邮件检查间隔: $interval 秒" # 创建检查脚本 cat > "$SCRIPTS_DIR/auto-check-mail.js" << 'EOF' import { SanguoMailbox } from '/Users/chufeng/.openclaw/sanguo_projects/sanguo_mail/dist/index.js'; import { join } from 'path'; const CONFIG = { rootPath: '/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live', teamName: 'sanguo-quant' }; async function checkMail() { const mailbox = new SanguoMailbox(CONFIG); await mailbox.initTeam(); const unreadMessages = await mailbox.listUnread('jiangwei'); if (unreadMessages.length > 0) { console.log(`发现 ${unreadMessages.length} 条未读消息`); unreadMessages.forEach((msg, index) => { console.log(`[${index + 1}] 来自 ${msg.from} - ${msg.text.substring(0, 50)}${msg.text.length > 50 ? '...' : ''}`); }); await Promise.all(unreadMessages.map((msg, index) => mailbox.markAsReadByIndex('jiangwei', index) )); console.log('所有未读消息已标记为已读'); } } async function startAutoCheck(intervalSeconds) { console.log(`邮件检查服务已启动,检查间隔: ${intervalSeconds} 秒`); checkMail(); setInterval(checkMail, intervalSeconds * 1000); } startAutoCheck(parseInt(process.argv[2]) || 60); EOF chmod +x "$SCRIPTS_DIR/auto-check-mail.js" # 启动服务 log "info" "正在启动邮件检查服务..." node "$SCRIPTS_DIR/auto-check-mail.js" "$interval" > "$SCRIPTS_DIR/auto-check-mail.log" 2>&1 & local PID=$! log "success" "邮件检查服务启动成功,PID: $PID" log "success" "检查日志: $SCRIPTS_DIR/auto-check-mail.log" log "success" "检查间隔: $interval 秒" } # 停止邮件检查服务 stop_watch_mail() { local WATCH_PID=$(ps aux | grep "node $SCRIPTS_DIR/auto-check-mail.js" | grep -v grep | awk '{print $2}') if [ -n "$WATCH_PID" ]; then log "info" "正在停止邮件检查服务,PID: $WATCH_PID" kill "$WATCH_PID" log "success" "邮件检查服务已停止" else log "warning" "邮件检查服务未运行" fi } # 显示使用说明 show_usage() { log "info" "Sanguo Mail 系统管理脚本" log "info" "使用方法: $0 <命令> [参数]" log "info" "" log "info" "可用命令:" log "info" " init 初始化系统" log " start 启动服务" log " stop 停止服务" log " restart 重启服务" log " status 显示系统状态" log " logs [行数] 显示服务日志" log " config [set <配置项> <值>] 设置/查看配置" log " install 安装项目依赖" log " check 健康检查" log " list 列出所有命令" log " watch [间隔] 启动邮件检查服务" log " stop-watch 停止邮件检查服务" log " test 测试邮件发送和接收" log " help 显示此帮助信息" } # 显示可用命令列表 list_commands() { log "info" "可用命令:" log "info" " init 初始化系统" log "info" " start 启动服务" log "info" " stop 停止服务" log "info" " restart 重启服务" log "info" " status 显示系统状态" log "info" " logs [行数] 显示服务日志" log "info" " config [set <配置项> <值>] 设置/查看配置" log "info" " install 安装项目依赖" log "info" " check 健康检查" log "info" " list 列出所有命令" log "info" " watch [间隔] 启动邮件检查服务" log "info" " stop-watch 停止邮件检查服务" log "info" " test 测试邮件发送和接收" log "info" " help 显示此帮助信息" } # 测试邮件发送 test_send_mail() { log "info" "正在测试邮件发送..." cat > "$SCRIPTS_DIR/test-send.js" << 'EOF' import { SanguoMailbox } from '/Users/chufeng/.openclaw/sanguo_projects/sanguo_mail/dist/index.js'; const CONFIG = { rootPath: '/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live', teamName: 'sanguo-quant' }; async function testSendMail() { const mailbox = new SanguoMailbox(CONFIG); await mailbox.initTeam(); await mailbox.sendMessage('zhangfei', { from: 'pangtong', to: 'zhangfei', text: '测试消息:发送一条测试邮件', type: 'text' }); console.log('测试邮件发送成功'); } testSendMail(); EOF chmod +x "$SCRIPTS_DIR/test-send.js" node "$SCRIPTS_DIR/test-send.js" log "success" "测试邮件发送成功" } # 测试邮件接收 test_receive_mail() { log "info" "正在测试邮件接收..." cat > "$SCRIPTS_DIR/test-receive.js" << 'EOF' import { SanguoMailbox } from '/Users/chufeng/.openclaw/sanguo_projects/sanguo_mail/dist/index.js'; const CONFIG = { rootPath: '/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live', teamName: 'sanguo-quant' }; async function testReceiveMail() { const mailbox = new SanguoMailbox(CONFIG); await mailbox.initTeam(); const unread = await mailbox.listUnread('zhangfei'); if (unread.length === 0) { console.log('没有未读邮件'); return; } console.log(`发现 ${unread.length} 条未读邮件`); for (let i = 0; i < unread.length; i++) { const msg = unread[i]; console.log(`[${i + 1}] ${msg.from} - ${msg.text}`); console.log(`类型: ${msg.type}`); console.log(`时间: ${msg.timestamp}`); console.log(''); } } testReceiveMail(); EOF chmod +x "$SCRIPTS_DIR/test-receive.js" node "$SCRIPTS_DIR/test-receive.js" log "success" "测试邮件接收成功" } # 测试功能 run_test() { log "info" "正在运行 Sanguo Mail 系统测试..." # 初始化系统(如果未初始化) if [ ! -d "$PROJECT_ROOT/mail/sanguo-quant/inboxes" ] || [ ! -f "$PROJECT_ROOT/mail/sanguo-quant/team.json" ]; then log "info" "邮件系统未初始化,正在初始化..." init_system fi # 测试邮件发送 test_send_mail # 测试邮件接收 test_receive_mail } # 主命令处理 case "${1:-}" in "init" | "setup" ) init_system ;; "start" | "up" ) start_server ;; "stop" | "down" ) stop_server ;; "restart" ) stop_server sleep 2 start_server ;; "watch" ) watch_mail "$@" ;; "stop-watch" ) stop_watch_mail ;; "status" ) status ;; "logs" ) logs "$@" ;; "config" ) if [ -z "$2" ]; then list_config elif [ "$2" = "set" ]; then set_config "${3:-}" "${4:-}" else log "error" "配置命令无效" log "usage" "使用方法: $0 config [set ]" fi ;; "install" ) install_deps ;; "check" ) check_health ;; "list" ) list_commands ;; "test" ) run_test ;; "help" ) show_usage ;; "" ) show_usage ;; * ) log "warning" "未知命令: $1" show_usage exit 1 ;; esac