Browse Source

机器人发送测试总结报告

Taio_O 2 weeks ago
parent
commit
34865b3b55
6 changed files with 514 additions and 167 deletions
  1. 7 0
      src/api/routes.js
  2. 35 9
      src/core/notifier.js
  3. 22 6
      src/core/scheduler.js
  4. 120 152
      src/core/speedTester.js
  5. 182 0
      test-connectivity.js
  6. 148 0
      test-simple.js

+ 7 - 0
src/api/routes.js

@@ -227,6 +227,13 @@ router.post('/test/manual', async (req, res) => {
     const speedTester = new SpeedTester();
     const results = await speedTester.testNodes(nodes);
 
+    // 处理测试结果并更新节点状态
+    const scheduler = new (require('../core/scheduler'))();
+    await scheduler.processTestResults(nodes, results);
+
+    // 发送测试总结报告
+    await scheduler.sendTestSummary(nodes, results);
+
     logger.info('手动测试完成', { testedNodes: nodes.length });
     res.json({ success: true, data: { results, testedNodes: nodes.length } });
   } catch (error) {

+ 35 - 9
src/core/notifier.js

@@ -105,8 +105,18 @@ class TelegramNotifier {
    */
   async sendNotification(notificationData) {
     try {
+      // 将metadata转换为字符串,确保是字符串类型
+      const metadataString = typeof notificationData.metadata === 'object' 
+        ? JSON.stringify(notificationData.metadata) 
+        : String(notificationData.metadata || '');
+
+      const notificationDataForDB = {
+        ...notificationData,
+        metadata: metadataString
+      };
+
       // 保存通知记录
-      const notification = await Notification.create(notificationData);
+      const notification = await Notification.create(notificationDataForDB);
 
       // 发送Telegram消息
       const fullMessage = `*${notificationData.title}*\n\n${notificationData.message}`;
@@ -201,7 +211,9 @@ class TelegramNotifier {
    */
   formatSummaryMessage(summary) {
     const lines = [
-      `*测试时间:* ${new Date().toLocaleString('zh-CN')}`,
+      `📊 *节点测速总结报告*`,
+      `━━━━━━━━━━━━━━━━━━━━`,
+      `*测试时间:* ${summary.testTime}`,
       `*总节点数:* ${summary.totalNodes}`,
       `*在线节点:* ${summary.onlineNodes}`,
       `*离线节点:* ${summary.offlineNodes}`,
@@ -216,20 +228,34 @@ class TelegramNotifier {
       lines.push(`*平均速度:* ${summary.averageSpeed} Mbps`);
     }
 
-    if (summary.failedNodes && summary.failedNodes.length > 0) {
-      lines.push(`\n*故障节点:*`);
-      summary.failedNodes.forEach(node => {
-        lines.push(`• ${node.name} (${node.group})`);
+    // 按分组显示统计
+    if (summary.groupStats && Object.keys(summary.groupStats).length > 0) {
+      lines.push(`\n📈 *分组统计:*`);
+      Object.entries(summary.groupStats).forEach(([group, stats]) => {
+        const groupSuccessRate = stats.total > 0 ? Math.round((stats.online / stats.total) * 100) : 0;
+        lines.push(`• ${group}: ${stats.online}/${stats.total} (${groupSuccessRate}%)`);
       });
     }
 
     if (summary.bestNodes && summary.bestNodes.length > 0) {
-      lines.push(`\n*最佳节点:*`);
-      summary.bestNodes.slice(0, 3).forEach(node => {
-        lines.push(`• ${node.name} - ${node.latency}ms`);
+      lines.push(`\n🏆 *最佳节点 (延迟排序):*`);
+      summary.bestNodes.forEach((node, index) => {
+        const medal = index === 0 ? '🥇' : index === 1 ? '🥈' : index === 2 ? '🥉' : '•';
+        lines.push(`${medal} ${node.name} - ${node.latency}ms (${node.group})`);
+      });
+    }
+
+    if (summary.failedNodes && summary.failedNodes.length > 0) {
+      lines.push(`\n❌ *故障节点:*`);
+      summary.failedNodes.forEach(node => {
+        lines.push(`• ${node.name} (${node.group})`);
       });
     }
 
+    // 添加测试状态总结
+    const statusEmoji = summary.successRate >= 90 ? '🟢' : summary.successRate >= 70 ? '🟡' : '🔴';
+    lines.push(`\n${statusEmoji} *测试状态:* ${summary.successRate >= 90 ? '优秀' : summary.successRate >= 70 ? '良好' : '需要关注'}`);
+
     return lines.join('\n');
   }
 

+ 22 - 6
src/core/scheduler.js

@@ -198,13 +198,13 @@ class Scheduler {
     const failedNodes = nodes.filter(node => {
       const result = testResults.find(r => r.nodeId === node.id);
       return result && !result.isSuccess;
-    }).slice(0, 5); // 最多显示5
+    }).slice(0, 10); // 最多显示10
 
     // 获取最佳节点列表
     const bestNodes = testResults
       .filter(r => r.isSuccess && r.latency)
       .sort((a, b) => a.latency - b.latency)
-      .slice(0, 3)
+      .slice(0, 5)
       .map(result => {
         const node = nodes.find(n => n.id === result.nodeId);
         return {
@@ -214,6 +214,23 @@ class Scheduler {
         };
       });
 
+    // 按分组统计
+    const groupStats = {};
+    nodes.forEach(node => {
+      const group = node.group || '默认';
+      if (!groupStats[group]) {
+        groupStats[group] = { total: 0, online: 0, offline: 0 };
+      }
+      groupStats[group].total++;
+      
+      const result = testResults.find(r => r.nodeId === node.id);
+      if (result && result.isSuccess) {
+        groupStats[group].online++;
+      } else {
+        groupStats[group].offline++;
+      }
+    });
+
     const summary = {
       totalNodes,
       onlineNodes,
@@ -223,13 +240,12 @@ class Scheduler {
       averageSpeed,
       failedNodes,
       bestNodes,
+      groupStats,
       testTime: new Date().toLocaleString('zh-CN')
     };
 
-    // 只在有故障节点或成功率较低时发送摘要
-    if (failedNodes.length > 0 || successRate < 80) {
-      await this.notifier.sendSummaryNotification(summary);
-    }
+    // 每次测速完成后都发送详细的测试总结报告
+    await this.notifier.sendSummaryNotification(summary);
 
     logger.info('测试摘要生成完成', summary);
   }

+ 120 - 152
src/core/speedTester.js

@@ -10,13 +10,14 @@ class SpeedTester {
     this.testUrls = process.env.SPEED_TEST_URLS?.split(',') || [
       'https://www.google.com',
       'https://www.youtube.com',
-      'https://www.github.com'
+      'https://www.github.com',
+      'https://httpbin.org/get'
     ];
     this.timeout = parseInt(process.env.SPEED_TEST_TIMEOUT) || 10000;
   }
 
   /**
-   * 测试单个节点
+   * 测试单个节点连通性
    */
   async testNode(node) {
     const startTime = Date.now();
@@ -25,8 +26,8 @@ class SpeedTester {
       testTime: new Date(),
       isSuccess: false,
       latency: null,
-      downloadSpeed: null,
-      uploadSpeed: null,
+      downloadSpeed: null, // 保留字段但不测试
+      uploadSpeed: null,   // 保留字段但不测试
       packetLoss: null,
       testUrl: null,
       errorMessage: null,
@@ -36,7 +37,7 @@ class SpeedTester {
     };
 
     try {
-      logger.info(`开始测试节点: ${node.name} (${node.type})`);
+      logger.info(`开始测试节点连通性: ${node.name} (${node.type})`);
 
       // 创建代理配置
       const proxyConfig = this.createProxyConfig(node);
@@ -44,7 +45,7 @@ class SpeedTester {
         throw new Error(`不支持的代理类型: ${node.type}`);
       }
 
-      // 简化测试流程:只测试基本连接
+      // 只测试基本连通
       const connectivityResult = await this.testBasicConnectivity(node, proxyConfig);
       testResult.isSuccess = connectivityResult.success;
       testResult.latency = connectivityResult.latency;
@@ -55,9 +56,9 @@ class SpeedTester {
       testResult.testDuration = Date.now() - startTime;
       
       if (testResult.isSuccess) {
-        logger.info(`✅ 节点测试成功: ${node.name} - 延迟: ${testResult.latency}ms`);
+        logger.info(`✅ 节点连通性测试成功: ${node.name} - 延迟: ${testResult.latency}ms - IP: ${testResult.ipAddress}`);
       } else {
-        logger.warn(`❌ 节点测试失败: ${node.name} - ${testResult.errorMessage || '连接超时'}`);
+        logger.warn(`❌ 节点连通性测试失败: ${node.name} - ${testResult.errorMessage || '连接超时'}`);
       }
 
     } catch (error) {
@@ -111,7 +112,6 @@ class SpeedTester {
       type: 'ss',
       password: node.password,
       method: node.cipher || node.method,
-      // 尝试使用HTTP代理模式
       auth: node.username && node.password ? {
         username: node.username,
         password: node.password
@@ -130,7 +130,6 @@ class SpeedTester {
       method: node.cipher || node.method,
       protocol: node.protocol,
       obfs: node.obfs,
-      // 尝试使用HTTP代理模式
       auth: node.username && node.password ? {
         username: node.username,
         password: node.password
@@ -152,7 +151,6 @@ class SpeedTester {
       sni: node.sni,
       wsPath: node.wsPath,
       wsHeaders: node.wsHeaders ? JSON.parse(node.wsHeaders) : {},
-      // 尝试使用HTTP代理模式
       auth: node.username && node.password ? {
         username: node.username,
         password: node.password
@@ -170,7 +168,6 @@ class SpeedTester {
       password: node.password,
       tls: node.tls,
       sni: node.sni,
-      // 尝试使用HTTP代理模式
       auth: node.username && node.password ? {
         username: node.username,
         password: node.password
@@ -222,149 +219,95 @@ class SpeedTester {
   }
 
   /**
-   * 测试延迟
-   */
-  async testLatency(node, proxyConfig) {
-    try {
-      const startTime = Date.now();
-      
-      // 使用HEAD请求测试延迟
-      const response = await this.makeRequest(node, proxyConfig, {
-        method: 'HEAD',
-        url: this.testUrls[0],
-        timeout: 5000
-      });
-
-      const latency = Date.now() - startTime;
-      
-      logger.debug(`延迟测试: ${node.name} - ${latency}ms`);
-      
-      return {
-        latency: latency,
-        packetLoss: 0 // 简化实现,实际需要多次测试计算丢包率
-      };
-    } catch (error) {
-      logger.debug(`延迟测试失败: ${node.name} - ${error.message}`);
-      return {
-        latency: null,
-        packetLoss: 100
-      };
-    }
-  }
-
-  /**
-   * 测试基本连接性(简化版本)
+   * 测试基本连通性
    */
   async testBasicConnectivity(node, proxyConfig) {
     const startTime = Date.now();
     
-    try {
-      // 尝试连接Google
-      const response = await this.makeRequest(node, proxyConfig, {
-        method: 'HEAD',
-        url: 'https://www.google.com',
-        timeout: 10000,
-        maxRedirects: 3
-      });
-
-      const latency = Date.now() - startTime;
-      
-      return {
-        success: true,
-        latency: latency,
-        url: 'https://www.google.com',
-        ipAddress: this.extractIpAddress(response),
-        location: this.extractLocation(response)
-      };
-    } catch (error) {
-      // 如果Google失败,尝试其他URL
+    // 如果是直连测试
+    if (node.type === 'direct') {
+      return this.testDirectConnectivity();
+    }
+    
+    // 尝试多个测试URL
     for (const url of this.testUrls) {
       try {
+        logger.debug(`尝试连接: ${node.name} -> ${url}`);
+        
         const response = await this.makeRequest(node, proxyConfig, {
-            method: 'HEAD',
+          method: 'HEAD',
           url: url,
-            timeout: 10000,
+          timeout: this.timeout,
           maxRedirects: 3
         });
 
-          const latency = Date.now() - startTime;
-
+        const latency = Date.now() - startTime;
+        
+        logger.debug(`连接成功: ${node.name} -> ${url} (${latency}ms)`);
+        
         return {
           success: true,
-            latency: latency,
+          latency: latency,
           url: url,
           ipAddress: this.extractIpAddress(response),
           location: this.extractLocation(response)
         };
-        } catch (innerError) {
-          logger.debug(`连接测试失败: ${node.name} - ${url} - ${innerError.message}`);
+      } catch (error) {
+        logger.debug(`连接失败: ${node.name} -> ${url} - ${error.message}`);
         continue;
       }
     }
 
     return {
       success: false,
-        latency: null,
+      latency: null,
       url: null,
       ipAddress: null,
       location: null
     };
-    }
   }
 
   /**
-   * 测试下载速度
+   * 测试直连连通性
    */
-  async testDownloadSpeed(node, proxyConfig) {
-    try {
-      // 测试下载速度(使用更大的文件以获得更准确的结果)
-      const downloadStart = Date.now();
-      const downloadResponse = await this.makeRequest(node, proxyConfig, {
-        method: 'GET',
-        url: 'https://httpbin.org/bytes/1048576', // 1MB测试文件
-        timeout: this.timeout,
-        responseType: 'arraybuffer'
-      });
-
-      const downloadDuration = Date.now() - downloadStart;
-      const downloadSize = downloadResponse.data.byteLength;
-      
-      // 计算下载速度 (bytes per second)
-      const downloadSpeedBps = downloadSize / (downloadDuration / 1000);
-      
-      // 转换为Mbps
-      const downloadSpeedMbps = (downloadSpeedBps * 8) / (1024 * 1024);
-
-      // 测试上传速度(简化实现,使用POST请求)
-      const uploadStart = Date.now();
-      const testData = Buffer.alloc(1024 * 1024); // 1MB测试数据
-      await this.makeRequest(node, proxyConfig, {
-        method: 'POST',
-        url: 'https://httpbin.org/post',
-        data: testData,
-        timeout: this.timeout,
-        headers: {
-          'Content-Type': 'application/octet-stream'
-        }
-      });
-      
-      const uploadDuration = Date.now() - uploadStart;
-      const uploadSpeedBps = testData.length / (uploadDuration / 1000);
-      const uploadSpeedMbps = (uploadSpeedBps * 8) / (1024 * 1024);
-
-      logger.debug(`速度测试: ${node.name} - 下载: ${Math.round(downloadSpeedMbps * 100) / 100}Mbps, 上传: ${Math.round(uploadSpeedMbps * 100) / 100}Mbps`);
+  async testDirectConnectivity() {
+    const startTime = Date.now();
+    
+    for (const url of this.testUrls) {
+      try {
+        logger.debug(`尝试直连: ${url}`);
+        
+        const response = await axios.get(url, {
+          timeout: this.timeout,
+          headers: {
+            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+          }
+        });
 
-      return {
-        downloadSpeed: Math.round(downloadSpeedMbps * 100) / 100,
-        uploadSpeed: Math.round(uploadSpeedMbps * 100) / 100
-      };
-    } catch (error) {
-      logger.debug(`速度测试失败: ${node.name} - ${error.message}`);
-      return {
-        downloadSpeed: null,
-        uploadSpeed: null
-      };
+        const latency = Date.now() - startTime;
+        
+        logger.debug(`直连成功: ${url} (${latency}ms)`);
+        
+        return {
+          success: true,
+          latency: latency,
+          url: url,
+          ipAddress: this.extractIpAddress(response),
+          location: this.extractLocation(response)
+        };
+      } catch (error) {
+        logger.debug(`直连失败: ${url} - ${error.message}`);
+        continue;
+      }
     }
+
+    return {
+      success: false,
+      latency: null,
+      url: null,
+      ipAddress: null,
+      location: null
+    };
   }
 
   /**
@@ -393,7 +336,7 @@ class SpeedTester {
   }
 
   /**
-   * 创建代理Agent(增强版本)
+   * 创建代理Agent
    */
   createProxyAgent(node, proxyConfig) {
     try {
@@ -403,14 +346,28 @@ class SpeedTester {
         case 'http':
         case 'https':
           // HTTP/HTTPS代理
-          const httpProxyUrl = `${proxyConfig.type}://${proxyConfig.host}:${proxyConfig.port}`;
+          let httpProxyUrl = `${proxyConfig.type}://${proxyConfig.host}:${proxyConfig.port}`;
+          
+          // 如果有认证信息,添加到URL中
+          if (proxyConfig.auth) {
+            const { username, password } = proxyConfig.auth;
+            httpProxyUrl = `${proxyConfig.type}://${username}:${password}@${proxyConfig.host}:${proxyConfig.port}`;
+          }
+          
           const httpAgent = new HttpsProxyAgent(httpProxyUrl);
           logger.debug(`HTTP代理创建成功: ${node.name} - ${httpProxyUrl}`);
           return httpAgent;
           
         case 'socks5':
           // SOCKS5代理
-          const socksProxyUrl = `socks5://${proxyConfig.host}:${proxyConfig.port}`;
+          let socksProxyUrl = `socks5://${proxyConfig.host}:${proxyConfig.port}`;
+          
+          // 如果有认证信息,添加到URL中
+          if (proxyConfig.auth) {
+            const { username, password } = proxyConfig.auth;
+            socksProxyUrl = `socks5://${username}:${password}@${proxyConfig.host}:${proxyConfig.port}`;
+          }
+          
           const socksAgent = new SocksProxyAgent(socksProxyUrl);
           logger.debug(`SOCKS5代理创建成功: ${node.name} - ${socksProxyUrl}`);
           return socksAgent;
@@ -419,26 +376,19 @@ class SpeedTester {
         case 'ssr':
         case 'vmess':
         case 'trojan':
-          // 对于这些高级代理类型,我们尝试使用HTTP代理方式
-          // 这需要代理服务器支持HTTP代理模式
-          logger.info(`尝试HTTP代理模式: ${proxyConfig.type} - ${node.name}`);
+          // 对于这些高级代理类型,我们需要通过本地Clash代理来测试
+          // 因为Node.js没有直接的vmess/ss客户端库
+          logger.info(`通过本地Clash代理测试: ${proxyConfig.type} - ${node.name}`);
           
-          // 构建代理URL
-          let proxyUrl = `http://${proxyConfig.host}:${proxyConfig.port}`;
-          
-          // 如果有认证信息,添加到URL中
-          if (proxyConfig.auth) {
-            const { username, password } = proxyConfig.auth;
-            proxyUrl = `http://${username}:${password}@${proxyConfig.host}:${proxyConfig.port}`;
-          }
-          
-          const advancedAgent = new HttpsProxyAgent(proxyUrl);
-          logger.debug(`高级代理创建成功: ${node.name} - ${proxyUrl}`);
-          return advancedAgent;
+          // 使用本地Clash混合端口
+          const localProxyUrl = 'http://127.0.0.1:7897';
+          const localAgent = new HttpsProxyAgent(localProxyUrl);
+          logger.debug(`使用本地Clash代理: ${node.name} - ${localProxyUrl}`);
+          return localAgent;
           
         default:
           logger.warn(`不支持的代理类型: ${proxyConfig.type} - ${node.name}`);
-    return null;
+          return null;
       }
       
     } catch (error) {
@@ -454,6 +404,7 @@ class SpeedTester {
     // 从响应头中提取IP地址
     return response.headers['x-forwarded-for'] || 
            response.headers['x-real-ip'] || 
+           response.headers['cf-connecting-ip'] ||
            'unknown';
   }
 
@@ -462,7 +413,13 @@ class SpeedTester {
    */
   extractLocation(response) {
     // 从响应头中提取位置信息
-    return response.headers['cf-ray'] ? 'Cloudflare' : 'unknown';
+    if (response.headers['cf-ray']) {
+      return 'Cloudflare';
+    }
+    if (response.headers['cf-ipcountry']) {
+      return response.headers['cf-ipcountry'];
+    }
+    return 'unknown';
   }
 
   /**
@@ -471,8 +428,9 @@ class SpeedTester {
   async saveTestResult(testResult) {
     try {
       await TestResult.create(testResult);
+      logger.debug(`测试结果已保存: ${testResult.nodeId}`);
     } catch (error) {
-      logger.error('保存测试结果失败', { error: error.message, testResult });
+      logger.error(`保存测试结果失败: ${error.message}`);
     }
   }
 
@@ -480,25 +438,35 @@ class SpeedTester {
    * 批量测试节点
    */
   async testNodes(nodes) {
-    const results = [];
+    logger.info(`开始批量测试 ${nodes.length} 个节点`);
     
-    // 并发测试,但限制并发数
-    const concurrency = 5;
-    const chunks = this.chunkArray(nodes, concurrency);
+    const results = [];
+    const concurrency = parseInt(process.env.CONCURRENCY) || 5;
     
-    for (const chunk of chunks) {
-      const chunkPromises = chunk.map(node => this.testNode(node));
-      const chunkResults = await Promise.allSettled(chunkPromises);
+    // 分批处理,控制并发数
+    for (let i = 0; i < nodes.length; i += concurrency) {
+      const batch = nodes.slice(i, i + concurrency);
+      const batchPromises = batch.map(node => this.testNode(node));
+      
+      const batchResults = await Promise.allSettled(batchPromises);
       
-      for (const result of chunkResults) {
+      batchResults.forEach((result, index) => {
         if (result.status === 'fulfilled') {
           results.push(result.value);
         } else {
-          logger.error('节点测试失败', { error: result.reason });
+          logger.error(`节点测试失败: ${batch[index].name} - ${result.reason}`);
         }
+      });
+      
+      // 批次间延迟,避免过于频繁的请求
+      if (i + concurrency < nodes.length) {
+        await new Promise(resolve => setTimeout(resolve, 1000));
       }
     }
     
+    const successCount = results.filter(r => r.isSuccess).length;
+    logger.info(`批量测试完成: ${successCount}/${nodes.length} 个节点连通`);
+    
     return results;
   }
 

+ 182 - 0
test-connectivity.js

@@ -0,0 +1,182 @@
+const SpeedTester = require('./src/core/speedTester');
+const logger = require('./src/utils/logger');
+
+// 测试节点配置 - 使用Clash混合端口7897
+const testNodes = [
+  // 测试直连(不使用代理)
+  {
+    id: 1,
+    name: '直连测试',
+    type: 'direct',
+    server: '',
+    port: 0,
+    username: '',
+    password: ''
+  },
+  // Clash混合端口HTTP代理
+  {
+    id: 2,
+    name: '测试HTTP代理',
+    type: 'http',
+    server: '127.0.0.1',
+    port: 7897,
+    username: '',
+    password: ''
+  },
+  // Clash混合端口SOCKS5代理
+  {
+    id: 3,
+    name: '测试SOCKS5代理',
+    type: 'socks5',
+    server: '127.0.0.1',
+    port: 7897,
+    username: '',
+    password: ''
+  }
+];
+
+// 添加一个简单的直连测试函数
+async function testDirectConnection() {
+  console.log('🌐 测试直连连通性...');
+  
+  const axios = require('axios');
+  const testUrls = [
+    'https://www.google.com',
+    'https://httpbin.org/get',
+    'https://www.github.com'
+  ];
+  
+  for (const url of testUrls) {
+    try {
+      console.log(`尝试连接: ${url}`);
+      const startTime = Date.now();
+      const response = await axios.get(url, {
+        timeout: 10000,
+        headers: {
+          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+      });
+      const latency = Date.now() - startTime;
+      
+      console.log(`✅ 直连成功: ${url} (${latency}ms)`);
+      console.log(`状态码: ${response.status}`);
+      console.log(`IP: ${response.headers['x-forwarded-for'] || 'unknown'}`);
+      return true;
+    } catch (error) {
+      console.log(`❌ 直连失败: ${url} - ${error.message}`);
+    }
+  }
+  
+  console.log('❌ 所有直连测试都失败了,请检查网络连接');
+  return false;
+}
+
+async function testConnectivity() {
+  console.log('🚀 开始连通性测试...\n');
+  
+  // 首先测试直连
+  const directSuccess = await testDirectConnection();
+  console.log('');
+  
+  if (!directSuccess) {
+    console.log('⚠️  直连测试失败,代理测试可能也会失败');
+    console.log('请检查网络连接或防火墙设置\n');
+  }
+  
+  const speedTester = new SpeedTester();
+  
+  try {
+    // 测试单个节点
+    console.log('📡 测试代理节点...');
+    const singleResult = await speedTester.testNode(testNodes[1]); // 测试HTTP代理
+    console.log('单个节点测试结果:', JSON.stringify(singleResult, null, 2));
+    console.log('');
+    
+    // 批量测试节点
+    console.log('📡 批量测试节点...');
+    const batchResults = await speedTester.testNodes(testNodes.slice(1)); // 跳过直连测试
+    
+    console.log('\n📊 测试结果汇总:');
+    console.log('='.repeat(50));
+    
+    batchResults.forEach((result, index) => {
+      const node = testNodes[index + 1]; // +1 因为跳过了直连测试
+      const status = result.isSuccess ? '✅ 连通' : '❌ 不通';
+      const latency = result.latency ? `${result.latency}ms` : 'N/A';
+      const ip = result.ipAddress || 'N/A';
+      
+      console.log(`${status} ${node.name} (${node.type})`);
+      console.log(`   延迟: ${latency}`);
+      console.log(`   IP: ${ip}`);
+      console.log(`   测试URL: ${result.testUrl || 'N/A'}`);
+      if (result.errorMessage) {
+        console.log(`   错误: ${result.errorMessage}`);
+      }
+      console.log('');
+    });
+    
+    const successCount = batchResults.filter(r => r.isSuccess).length;
+    console.log(`总计: ${successCount}/${batchResults.length} 个节点连通`);
+    
+    // 提供故障排除建议
+    if (successCount === 0) {
+      console.log('\n🔧 故障排除建议:');
+      console.log('1. 检查代理服务是否正在运行');
+      console.log('2. 确认代理端口是否正确');
+      console.log('3. 检查防火墙设置');
+      console.log('4. 尝试使用其他代理服务器');
+      console.log('5. 检查代理配置是否正确');
+    }
+    
+  } catch (error) {
+    console.error('❌ 测试过程中发生错误:', error.message);
+  }
+}
+
+// 添加一个简单的代理检测函数
+async function detectLocalProxies() {
+  console.log('🔍 检测本地代理服务...');
+  
+  const net = require('net');
+  const commonPorts = [7897, 7891, 8118, 3128, 8388, 10808];
+  
+  for (const port of commonPorts) {
+    try {
+      const socket = new net.Socket();
+      const result = await new Promise((resolve) => {
+        socket.setTimeout(2000);
+        socket.on('connect', () => {
+          socket.destroy();
+          resolve(true);
+        });
+        socket.on('timeout', () => {
+          socket.destroy();
+          resolve(false);
+        });
+        socket.on('error', () => {
+          socket.destroy();
+          resolve(false);
+        });
+        socket.connect(port, '127.0.0.1');
+      });
+      
+      if (result) {
+        console.log(`✅ 发现本地代理服务: 127.0.0.1:${port}`);
+      }
+    } catch (error) {
+      // 忽略错误
+    }
+  }
+  
+  console.log('检测完成\n');
+}
+
+// 如果直接运行此脚本
+if (require.main === module) {
+  // 先检测本地代理
+  detectLocalProxies().then(() => {
+    return testConnectivity();
+  }).catch(console.error);
+}
+
+module.exports = { testConnectivity, testDirectConnection, detectLocalProxies }; 

+ 148 - 0
test-simple.js

@@ -0,0 +1,148 @@
+const axios = require('axios');
+
+console.log('🔍 简单连通性测试\n');
+
+// 测试直连
+async function testDirect() {
+  console.log('1. 测试直连...');
+  
+  const urls = [
+    'https://httpbin.org/get',
+    'https://www.google.com',
+    'https://www.github.com'
+  ];
+  
+  for (const url of urls) {
+    try {
+      console.log(`   尝试: ${url}`);
+      const start = Date.now();
+      const response = await axios.get(url, {
+        timeout: 10000,
+        headers: {
+          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+        }
+      });
+      const latency = Date.now() - start;
+      
+      console.log(`   ✅ 成功: ${latency}ms (状态码: ${response.status})`);
+      return true;
+    } catch (error) {
+      console.log(`   ❌ 失败: ${error.message}`);
+    }
+  }
+  
+  console.log('   ❌ 所有直连测试都失败了');
+  return false;
+}
+
+// 测试本地代理端口
+async function testLocalProxy() {
+  console.log('\n2. 测试本地代理端口...');
+  
+  const net = require('net');
+  const ports = [8080, 1080, 7890, 7891, 8118, 3128];
+  
+  for (const port of ports) {
+    try {
+      const socket = new net.Socket();
+      const result = await new Promise((resolve) => {
+        socket.setTimeout(3000);
+        socket.on('connect', () => {
+          socket.destroy();
+          resolve(true);
+        });
+        socket.on('timeout', () => {
+          socket.destroy();
+          resolve(false);
+        });
+        socket.on('error', () => {
+          socket.destroy();
+          resolve(false);
+        });
+        socket.connect(port, '127.0.0.1');
+      });
+      
+      if (result) {
+        console.log(`   ✅ 端口 ${port} 可连接`);
+      } else {
+        console.log(`   ❌ 端口 ${port} 不可连接`);
+      }
+    } catch (error) {
+      console.log(`   ❌ 端口 ${port} 测试失败: ${error.message}`);
+    }
+  }
+}
+
+// 测试HTTP代理
+async function testHttpProxy() {
+  console.log('\n3. 测试HTTP代理...');
+  
+  try {
+    const { HttpsProxyAgent } = require('https-proxy-agent');
+    const proxyUrl = 'http://127.0.0.1:7897';
+    const agent = new HttpsProxyAgent(proxyUrl);
+    
+    const response = await axios.get('https://httpbin.org/get', {
+      httpsAgent: agent,
+      timeout: 10000,
+      headers: {
+        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+      }
+    });
+    
+    console.log(`   ✅ HTTP代理测试成功: ${response.status}`);
+    console.log(`   IP: ${response.data.origin}`);
+  } catch (error) {
+    console.log(`   ❌ HTTP代理测试失败: ${error.message}`);
+  }
+}
+
+// 测试SOCKS5代理
+async function testSocks5Proxy() {
+  console.log('\n4. 测试SOCKS5代理...');
+  
+  try {
+    const { SocksProxyAgent } = require('socks-proxy-agent');
+    const proxyUrl = 'socks5://127.0.0.1:7897';
+    const agent = new SocksProxyAgent(proxyUrl);
+    
+    const response = await axios.get('https://httpbin.org/get', {
+      httpsAgent: agent,
+      timeout: 10000,
+      headers: {
+        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+      }
+    });
+    
+    console.log(`   ✅ SOCKS5代理测试成功: ${response.status}`);
+    console.log(`   IP: ${response.data.origin}`);
+  } catch (error) {
+    console.log(`   ❌ SOCKS5代理测试失败: ${error.message}`);
+  }
+}
+
+// 主函数
+async function main() {
+  const directSuccess = await testDirect();
+  
+  if (!directSuccess) {
+    console.log('\n⚠️  直连测试失败,请检查网络连接');
+    console.log('可能的原因:');
+    console.log('- 网络连接问题');
+    console.log('- 防火墙阻止');
+    console.log('- DNS解析问题');
+    return;
+  }
+  
+  await testLocalProxy();
+  await testHttpProxy();
+  await testSocks5Proxy();
+  
+  console.log('\n📋 测试完成');
+  console.log('如果直连成功但代理测试失败,说明:');
+  console.log('1. 代理服务未运行');
+  console.log('2. 代理端口配置错误');
+  console.log('3. 代理配置有问题');
+}
+
+main().catch(console.error);