Browse Source

初步连接机器人

Taio_O 1 week ago
parent
commit
8a4de49dbf
4 changed files with 774 additions and 0 deletions
  1. 153 0
      BOT_USAGE.md
  2. 2 0
      env.example
  3. 15 0
      src/app.js
  4. 604 0
      src/core/botManager.js

+ 153 - 0
BOT_USAGE.md

@@ -0,0 +1,153 @@
+# Telegram机器人使用说明
+
+## 🤖 机器人功能
+
+这个Telegram机器人可以帮助您通过聊天界面管理订阅链接和监控节点状态。
+
+## 📋 配置要求
+
+### 1. 创建Telegram机器人
+1. 在Telegram中搜索 `@BotFather`
+2. 发送 `/newbot` 命令
+3. 按提示设置机器人名称和用户名
+4. 获取Bot Token(类似:`123456789:ABCdefGHIjklMNOpqrsTUVwxyz`)
+
+### 2. 获取Chat ID
+1. 将机器人添加到您的聊天或群组
+2. 发送任意消息给机器人
+3. 访问:`https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates`
+4. 找到 `chat.id` 字段的值
+
+### 3. 配置环境变量
+在 `.env` 文件中添加:
+```bash
+TELEGRAM_BOT_TOKEN=你的机器人Token
+TELEGRAM_CHAT_ID=你的Chat ID
+# 支持多个用户,用逗号分隔
+# TELEGRAM_CHAT_ID=123456789,987654321
+```
+
+## 🚀 启动机器人
+
+1. 确保配置正确后,启动应用:
+```bash
+node start.js
+```
+
+2. 机器人会自动启动并开始监听消息
+
+## 📱 可用命令
+
+### 基础命令
+- `/start` - 开始使用机器人,显示欢迎信息
+- `/help` - 显示帮助信息和使用说明
+- `/status` - 查看系统状态和运行信息
+
+### 订阅管理
+- `/subscriptions` - 查看所有订阅列表
+- `/add_subscription` - 添加订阅链接
+- `/remove_subscription` - 删除订阅
+- `/update_subscriptions` - 手动更新所有订阅
+
+### 测速功能
+- `/test_speed` - 手动触发测速(开发中)
+
+## 💡 使用技巧
+
+### 1. 直接添加订阅
+直接发送订阅链接给机器人即可添加:
+```
+https://example.com/subscription
+ss://user:pass@server:port
+vmess://...
+trojan://...
+```
+
+### 2. 删除订阅
+1. 发送 `/remove_subscription`
+2. 选择要删除的订阅编号
+3. 发送数字(如:1)确认删除
+
+### 3. 查看状态
+发送 `/status` 查看:
+- 订阅数量和节点数量
+- 自动更新状态
+- 测速功能状态
+- 系统运行时间
+
+## 🔧 支持格式
+
+机器人支持以下订阅格式:
+- **Clash配置**:`https://example.com/clash.yaml`
+- **Shadowsocks**:`ss://user:pass@server:port`
+- **Vmess**:`vmess://...`
+- **Trojan**:`trojan://...`
+- **Base64编码**:自动解码
+
+## 🛡️ 安全特性
+
+- **权限控制**:只有配置的Chat ID才能使用机器人
+- **输入验证**:自动验证订阅链接格式
+- **错误处理**:友好的错误提示信息
+- **日志记录**:所有操作都有详细日志
+
+## 📊 功能特点
+
+### 自动管理
+- 自动解析订阅内容
+- 自动去重节点
+- 自动更新节点信息
+- 自动触发测速
+
+### 实时监控
+- 节点状态监控
+- 延迟和速度测试
+- 故障节点通知
+- 恢复节点通知
+
+### 便捷操作
+- 一键添加订阅
+- 一键删除订阅
+- 一键更新订阅
+- 一键查看状态
+
+## 🔍 故障排除
+
+### 机器人无响应
+1. 检查Bot Token是否正确
+2. 检查Chat ID是否正确
+3. 检查网络连接
+4. 查看应用日志
+
+### 权限被拒绝
+1. 确认Chat ID在允许列表中
+2. 检查环境变量配置
+3. 重启应用
+
+### 订阅添加失败
+1. 检查订阅链接格式
+2. 确认链接可访问
+3. 查看错误日志
+
+## 📝 日志查看
+
+机器人操作日志会记录在应用日志中:
+```bash
+# 查看实时日志
+tail -f logs/app.log
+
+# 查看机器人相关日志
+grep "bot" logs/app.log
+```
+
+## 🔄 更新说明
+
+机器人功能会持续更新,新功能包括:
+- 手动测速功能
+- 节点排序功能
+- 批量操作功能
+- 更丰富的通知
+
+---
+
+💡 **提示**:机器人功能需要正确的Telegram配置才能正常工作。如果遇到问题,请检查配置和网络连接。 

+ 2 - 0
env.example

@@ -8,6 +8,8 @@ DB_PASSWORD=BjKhwBRAGSfKc4e6
 # Telegram机器人配置
 TELEGRAM_BOT_TOKEN=7804040067:AAFeV7WeCWHUJTJzLUnN83C0Wid0pGSj6NQ
 TELEGRAM_CHAT_ID=-4840979728
+# 支持多个聊天ID,用逗号分隔
+# TELEGRAM_CHAT_ID=-4840979728,123456789
 
 # 应用配置
 PORT=3000

+ 15 - 0
src/app.js

@@ -9,6 +9,7 @@ const sequelize = require('./config/database');
 const routes = require('./api/routes');
 const Scheduler = require('./core/scheduler');
 const MultiSubscriptionManager = require('./core/multiSubscriptionManager');
+const BotManager = require('./core/botManager');
 
 const app = express();
 const PORT = process.env.PORT || 3000;
@@ -129,6 +130,10 @@ async function startApp() {
     
     app.set('subscriptionManager', subscriptionManager);
 
+    // 启动Telegram机器人管理器
+    const botManager = new BotManager();
+    app.set('botManager', botManager);
+
     // 检查是否启用启动时立即测速
     const enableStartupSpeedTest = process.env.ENABLE_SCHEDULED_SPEED_TEST !== 'false';
     
@@ -172,6 +177,11 @@ process.on('SIGTERM', async () => {
     subscriptionManager.stopAutoUpdate();
   }
   
+  const botManager = app.get('botManager');
+  if (botManager) {
+    botManager.stop();
+  }
+  
   await sequelize.close();
   logger.info('应用已关闭');
   process.exit(0);
@@ -190,6 +200,11 @@ process.on('SIGINT', async () => {
     subscriptionManager.stopAutoUpdate();
   }
   
+  const botManager = app.get('botManager');
+  if (botManager) {
+    botManager.stop();
+  }
+  
   await sequelize.close();
   logger.info('应用已关闭');
   process.exit(0);

+ 604 - 0
src/core/botManager.js

@@ -0,0 +1,604 @@
+const TelegramBot = require('node-telegram-bot-api');
+const logger = require('../utils/logger');
+const { Subscription } = require('../models');
+const MultiSubscriptionManager = require('./multiSubscriptionManager');
+
+class BotManager {
+  constructor() {
+    this.botToken = process.env.TELEGRAM_BOT_TOKEN;
+    this.allowedChatIds = process.env.TELEGRAM_CHAT_ID?.split(',').map(id => id.trim()) || [];
+    this.subscriptionManager = new MultiSubscriptionManager();
+    
+    // 可选的代理配置
+    this.proxyConfig = null;
+    if (process.env.TELEGRAM_PROXY_URL) {
+      this.proxyConfig = {
+        host: process.env.TELEGRAM_PROXY_HOST,
+        port: parseInt(process.env.TELEGRAM_PROXY_PORT) || 1080,
+        protocol: process.env.TELEGRAM_PROXY_PROTOCOL || 'http'
+      };
+    }
+    
+    if (!this.botToken) {
+      logger.warn('Telegram Bot Token未配置,机器人功能将被禁用');
+      this.enabled = false;
+      return;
+    }
+
+    try {
+      const botOptions = {
+        polling: true,
+        request: {
+          timeout: 30000, // 增加超时时间到30秒
+          connect_timeout: 30000
+        }
+      };
+      
+      // 如果配置了代理,添加代理设置
+      if (this.proxyConfig) {
+        const { HttpsProxyAgent } = require('https-proxy-agent');
+        const proxyUrl = `${this.proxyConfig.protocol}://${this.proxyConfig.host}:${this.proxyConfig.port}`;
+        botOptions.request.httpsAgent = new HttpsProxyAgent(proxyUrl);
+        logger.info(`使用代理连接Telegram: ${proxyUrl}`);
+      } else {
+        botOptions.request.agent = false; // 禁用代理,避免网络问题
+      }
+      
+      this.bot = new TelegramBot(this.botToken, botOptions);
+      
+      // 添加错误处理
+      this.bot.on('polling_error', (error) => {
+        logger.warn('Telegram轮询错误,尝试重连...', { 
+          error: error.message,
+          code: error.code 
+        });
+        
+        // 如果是网络超时,尝试重新启动轮询
+        if (error.code === 'EFATAL' || error.message.includes('ESOCKETTIMEDOUT')) {
+          setTimeout(() => {
+            try {
+              this.bot.stopPolling();
+              setTimeout(() => {
+                this.bot.startPolling();
+                logger.info('Telegram机器人重连成功');
+              }, 5000);
+            } catch (reconnectError) {
+              logger.error('Telegram机器人重连失败', { error: reconnectError.message });
+            }
+          }, 10000);
+        }
+      });
+      
+      this.enabled = true;
+      this.setupCommands();
+      this.setupMessageHandlers();
+      logger.info('Telegram机器人管理器初始化成功');
+    } catch (error) {
+      logger.error('Telegram机器人管理器初始化失败', { error: error.message });
+      this.enabled = false;
+    }
+  }
+
+  /**
+   * 设置机器人命令
+   */
+  setupCommands() {
+    if (!this.enabled) return;
+
+    this.bot.setMyCommands([
+      { command: '/start', description: '开始使用机器人' },
+      { command: '/help', description: '显示帮助信息' },
+      { command: '/status', description: '查看系统状态' },
+      { command: '/subscriptions', description: '查看所有订阅' },
+      { command: '/add_subscription', description: '添加订阅链接' },
+      { command: '/remove_subscription', description: '删除订阅' },
+      { command: '/update_subscriptions', description: '手动更新订阅' },
+      { command: '/test_speed', description: '手动触发测速' }
+    ]);
+  }
+
+  /**
+   * 设置消息处理器
+   */
+  setupMessageHandlers() {
+    if (!this.enabled) return;
+
+    // 处理 /start 命令
+    this.bot.onText(/\/start/, async (msg) => {
+      await this.handleStart(msg);
+    });
+
+    // 处理 /help 命令
+    this.bot.onText(/\/help/, async (msg) => {
+      await this.handleHelp(msg);
+    });
+
+    // 处理 /status 命令
+    this.bot.onText(/\/status/, async (msg) => {
+      await this.handleStatus(msg);
+    });
+
+    // 处理 /subscriptions 命令
+    this.bot.onText(/\/subscriptions/, async (msg) => {
+      await this.handleSubscriptions(msg);
+    });
+
+    // 处理 /add_subscription 命令
+    this.bot.onText(/\/add_subscription/, async (msg) => {
+      await this.handleAddSubscription(msg);
+    });
+
+    // 处理 /remove_subscription 命令
+    this.bot.onText(/\/remove_subscription/, async (msg) => {
+      await this.handleRemoveSubscription(msg);
+    });
+
+    // 处理 /update_subscriptions 命令
+    this.bot.onText(/\/update_subscriptions/, async (msg) => {
+      await this.handleUpdateSubscriptions(msg);
+    });
+
+    // 处理 /test_speed 命令
+    this.bot.onText(/\/test_speed/, async (msg) => {
+      await this.handleTestSpeed(msg);
+    });
+
+    // 处理普通消息(用于添加订阅链接)
+    this.bot.on('message', async (msg) => {
+      await this.handleMessage(msg);
+    });
+  }
+
+  /**
+   * 检查用户权限
+   */
+  isAuthorized(chatId) {
+    return this.allowedChatIds.includes(chatId.toString());
+  }
+
+  /**
+   * 发送消息
+   */
+  async sendMessage(chatId, message, options = {}) {
+    try {
+      return await this.bot.sendMessage(chatId, message, {
+        parse_mode: 'Markdown',
+        disable_web_page_preview: true,
+        ...options
+      });
+    } catch (error) {
+      logger.error('发送Telegram消息失败', { error: error.message, chatId });
+      throw error;
+    }
+  }
+
+  /**
+   * 处理 /start 命令
+   */
+  async handleStart(msg) {
+    const chatId = msg.chat.id;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    const message = `🤖 *欢迎使用测速机器人!*
+
+📋 *可用命令:*
+• /help - 显示帮助信息
+• /status - 查看系统状态
+• /subscriptions - 查看所有订阅
+• /add_subscription - 添加订阅链接
+• /remove_subscription - 删除订阅
+• /update_subscriptions - 手动更新订阅
+• /test_speed - 手动触发测速
+
+💡 *使用提示:*
+• 发送订阅链接可直接添加订阅
+• 支持多种格式:Clash、Shadowsocks、Vmess等
+• 系统会自动解析并更新节点信息`;
+
+    await this.sendMessage(chatId, message);
+  }
+
+  /**
+   * 处理 /help 命令
+   */
+  async handleHelp(msg) {
+    const chatId = msg.chat.id;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    const message = `📖 *帮助信息*
+
+🔧 *订阅管理:*
+• 直接发送订阅链接即可添加
+• 支持格式:Clash、Shadowsocks、Vmess、Trojan
+• 系统会自动解析并去重
+
+⚡ *测速功能:*
+• 自动定时测速(默认每10分钟)
+• 支持手动触发测速
+• 节点故障自动通知
+
+📊 *状态监控:*
+• 实时监控节点状态
+• 延迟和速度测试
+• 故障节点自动标记
+
+🔔 *通知功能:*
+• 节点故障通知
+• 节点恢复通知
+• 测试摘要报告
+
+💡 *使用示例:*
+• 发送:\`https://example.com/subscription\`
+• 发送:\`ss://...\`
+• 发送:\`vmess://...\``;
+
+    await this.sendMessage(chatId, message);
+  }
+
+  /**
+   * 处理 /status 命令
+   */
+  async handleStatus(msg) {
+    const chatId = msg.chat.id;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    try {
+      const status = await this.subscriptionManager.getStatus();
+      const subscriptions = await Subscription.findAll({
+        where: { isActive: true }
+      });
+
+      const totalNodes = subscriptions.reduce((sum, sub) => sum + (sub.nodeCount || 0), 0);
+      
+      const message = `📊 *系统状态*
+
+📡 *订阅信息:*
+• 活跃订阅:${subscriptions.length} 个
+• 总节点数:${totalNodes} 个
+
+🔄 *更新状态:*
+• 自动更新:${status.autoUpdateEnabled ? '✅ 启用' : '❌ 禁用'}
+• 更新间隔:${status.updateInterval || '未设置'} 秒
+• 最后更新:${status.lastUpdateTime || '未更新'}
+
+⚡ *测速状态:*
+• 测速触发器:${status.speedTestTrigger ? '✅ 已设置' : '❌ 未设置'}
+• 定时测速:${process.env.ENABLE_SCHEDULED_SPEED_TEST !== 'false' ? '✅ 启用' : '❌ 禁用'}
+
+🛠️ *系统信息:*
+• 运行时间:${this.getUptime()}
+• 内存使用:${this.getMemoryUsage()}`;
+
+      await this.sendMessage(chatId, message);
+    } catch (error) {
+      logger.error('获取状态失败', { error: error.message });
+      await this.sendMessage(chatId, '❌ 获取系统状态失败');
+    }
+  }
+
+  /**
+   * 处理 /subscriptions 命令
+   */
+  async handleSubscriptions(msg) {
+    const chatId = msg.chat.id;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    try {
+      const subscriptions = await Subscription.findAll({
+        where: { isActive: true },
+        order: [['createdAt', 'DESC']]
+      });
+
+      if (subscriptions.length === 0) {
+        await this.sendMessage(chatId, '📭 暂无订阅,请使用 /add_subscription 添加订阅');
+        return;
+      }
+
+      let message = `📡 *订阅列表*\n\n`;
+      
+      subscriptions.forEach((sub, index) => {
+        const status = sub.isActive ? '✅' : '❌';
+        const lastUpdate = sub.lastUpdateTime 
+          ? new Date(sub.lastUpdateTime).toLocaleString('zh-CN')
+          : '未更新';
+        
+        message += `${index + 1}. ${status} *${sub.name}*\n`;
+        message += `   📊 节点数:${sub.nodeCount || 0}\n`;
+        message += `   🔗 URL:\`${sub.url}\`\n`;
+        message += `   ⏰ 最后更新:${lastUpdate}\n\n`;
+      });
+
+      message += `💡 *操作提示:*\n`;
+      message += `• 使用 /remove_subscription 删除订阅\n`;
+      message += `• 使用 /update_subscriptions 手动更新\n`;
+      message += `• 直接发送新链接添加订阅`;
+
+      await this.sendMessage(chatId, message);
+    } catch (error) {
+      logger.error('获取订阅列表失败', { error: error.message });
+      await this.sendMessage(chatId, '❌ 获取订阅列表失败');
+    }
+  }
+
+  /**
+   * 处理 /add_subscription 命令
+   */
+  async handleAddSubscription(msg) {
+    const chatId = msg.chat.id;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    await this.sendMessage(chatId, 
+      `📥 *添加订阅*\n\n` +
+      `请发送订阅链接,支持以下格式:\n` +
+      `• Clash配置:\`https://example.com/clash.yaml\`\n` +
+      `• Shadowsocks:\`ss://...\`\n` +
+      `• Vmess:\`vmess://...\`\n` +
+      `• Trojan:\`trojan://...\`\n\n` +
+      `💡 直接发送链接即可添加订阅`
+    );
+  }
+
+  /**
+   * 处理 /remove_subscription 命令
+   */
+  async handleRemoveSubscription(msg) {
+    const chatId = msg.chat.id;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    try {
+      const subscriptions = await Subscription.findAll({
+        where: { isActive: true },
+        order: [['createdAt', 'DESC']]
+      });
+
+      if (subscriptions.length === 0) {
+        await this.sendMessage(chatId, '📭 暂无订阅可删除');
+        return;
+      }
+
+      let message = `🗑️ *删除订阅*\n\n`;
+      message += `请选择要删除的订阅(发送数字):\n\n`;
+      
+      subscriptions.forEach((sub, index) => {
+        message += `${index + 1}. *${sub.name}*\n`;
+        message += `   📊 节点数:${sub.nodeCount || 0}\n`;
+        message += `   🔗 \`${sub.url}\`\n\n`;
+      });
+
+      message += `💡 发送数字(如:1)来删除对应订阅`;
+
+      await this.sendMessage(chatId, message);
+    } catch (error) {
+      logger.error('获取订阅列表失败', { error: error.message });
+      await this.sendMessage(chatId, '❌ 获取订阅列表失败');
+    }
+  }
+
+  /**
+   * 处理 /update_subscriptions 命令
+   */
+  async handleUpdateSubscriptions(msg) {
+    const chatId = msg.chat.id;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    try {
+      await this.sendMessage(chatId, '🔄 开始手动更新订阅...');
+      
+      const results = await this.subscriptionManager.manualUpdate();
+      
+      let message = `✅ *订阅更新完成*\n\n`;
+      
+      results.forEach(result => {
+        if (result.error) {
+          message += `❌ *${result.subscriptionName}*\n`;
+          message += `   错误:${result.error}\n\n`;
+        } else {
+          message += `✅ *${result.subscriptionName}*\n`;
+          message += `   新增:${result.added} 个\n`;
+          message += `   更新:${result.updated} 个\n`;
+          message += `   移除:${result.removed} 个\n\n`;
+        }
+      });
+
+      await this.sendMessage(chatId, message);
+    } catch (error) {
+      logger.error('手动更新订阅失败', { error: error.message });
+      await this.sendMessage(chatId, '❌ 更新订阅失败:' + error.message);
+    }
+  }
+
+  /**
+   * 处理 /test_speed 命令
+   */
+  async handleTestSpeed(msg) {
+    const chatId = msg.chat.id;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    try {
+      await this.sendMessage(chatId, '⚡ 开始手动测速...');
+      
+      // 这里需要调用测速功能
+      // 暂时发送一个简单的消息
+      await this.sendMessage(chatId, '✅ 测速功能开发中,请稍后...');
+    } catch (error) {
+      logger.error('手动测速失败', { error: error.message });
+      await this.sendMessage(chatId, '❌ 测速失败:' + error.message);
+    }
+  }
+
+  /**
+   * 处理普通消息
+   */
+  async handleMessage(msg) {
+    const chatId = msg.chat.id;
+    const text = msg.text;
+    
+    if (!this.isAuthorized(chatId)) {
+      await this.sendMessage(chatId, '❌ 您没有权限使用此机器人');
+      return;
+    }
+
+    // 检查是否是订阅链接
+    if (this.isSubscriptionUrl(text)) {
+      await this.addSubscription(chatId, text);
+      return;
+    }
+
+    // 检查是否是删除订阅的数字
+    if (/^\d+$/.test(text)) {
+      await this.removeSubscriptionByIndex(chatId, parseInt(text));
+      return;
+    }
+
+    // 其他消息
+    await this.sendMessage(chatId, 
+      `💡 *消息处理*\n\n` +
+      `收到消息:\`${text}\`\n\n` +
+      `💡 *使用提示:*\n` +
+      `• 发送订阅链接可直接添加订阅\n` +
+      `• 使用 /help 查看所有命令\n` +
+      `• 使用 /subscriptions 查看订阅列表`
+    );
+  }
+
+  /**
+   * 检查是否是订阅链接
+   */
+  isSubscriptionUrl(text) {
+    return /^(https?:\/\/|ss:\/\/|vmess:\/\/|trojan:\/\/)/.test(text);
+  }
+
+  /**
+   * 添加订阅
+   */
+  async addSubscription(chatId, url) {
+    try {
+      await this.sendMessage(chatId, '📥 正在添加订阅...');
+      
+      // 创建新订阅
+      const subscription = await Subscription.create({
+        name: `订阅_${Date.now()}`,
+        url: url,
+        isActive: true,
+        nodeCount: 0
+      });
+
+      // 更新订阅
+      const result = await this.subscriptionManager.manualUpdateSubscription(subscription.id);
+      
+      if (result.error) {
+        await this.sendMessage(chatId, `❌ 添加订阅失败:${result.error}`);
+        return;
+      }
+
+      const message = `✅ *订阅添加成功*\n\n` +
+        `📡 订阅名称:*${subscription.name}*\n` +
+        `🔗 URL:\`${url}\`\n` +
+        `📊 节点数:${result.actualNodeCount || 0}\n` +
+        `➕ 新增:${result.added || 0} 个\n` +
+        `🔄 更新:${result.updated || 0} 个\n` +
+        `🗑️ 移除:${result.removed || 0} 个`;
+
+      await this.sendMessage(chatId, message);
+    } catch (error) {
+      logger.error('添加订阅失败', { error: error.message, url });
+      await this.sendMessage(chatId, '❌ 添加订阅失败:' + error.message);
+    }
+  }
+
+  /**
+   * 根据索引删除订阅
+   */
+  async removeSubscriptionByIndex(chatId, index) {
+    try {
+      const subscriptions = await Subscription.findAll({
+        where: { isActive: true },
+        order: [['createdAt', 'DESC']]
+      });
+
+      if (index < 1 || index > subscriptions.length) {
+        await this.sendMessage(chatId, '❌ 无效的订阅编号');
+        return;
+      }
+
+      const subscription = subscriptions[index - 1];
+      
+      // 标记为非活跃
+      await subscription.update({ isActive: false });
+      
+      const message = `🗑️ *订阅删除成功*\n\n` +
+        `📡 订阅名称:*${subscription.name}*\n` +
+        `🔗 URL:\`${subscription.url}\`\n` +
+        `📊 节点数:${subscription.nodeCount || 0}`;
+
+      await this.sendMessage(chatId, message);
+    } catch (error) {
+      logger.error('删除订阅失败', { error: error.message, index });
+      await this.sendMessage(chatId, '❌ 删除订阅失败:' + error.message);
+    }
+  }
+
+  /**
+   * 获取运行时间
+   */
+  getUptime() {
+    const uptime = process.uptime();
+    const hours = Math.floor(uptime / 3600);
+    const minutes = Math.floor((uptime % 3600) / 60);
+    return `${hours}小时${minutes}分钟`;
+  }
+
+  /**
+   * 获取内存使用情况
+   */
+  getMemoryUsage() {
+    const usage = process.memoryUsage();
+    const used = Math.round(usage.heapUsed / 1024 / 1024);
+    const total = Math.round(usage.heapTotal / 1024 / 1024);
+    return `${used}MB / ${total}MB`;
+  }
+
+  /**
+   * 停止机器人
+   */
+  stop() {
+    if (this.enabled && this.bot) {
+      this.bot.stopPolling();
+      logger.info('Telegram机器人已停止');
+    }
+  }
+}
+
+module.exports = BotManager;