diff --git a/server/proxy/service/subscription-server-v3.js b/server/proxy/service/subscription-server-v3.js index a1add3f1..876d146e 100644 --- a/server/proxy/service/subscription-server-v3.js +++ b/server/proxy/service/subscription-server-v3.js @@ -307,19 +307,20 @@ ${nodeNames} : ` - "♻️ 自动选择"\n${nodeNames}`) : nodeNames; - // Claude专线独立代理组: 只包含SV节点 + 备选 - // 用户可以在VPN软件中手动下拉选择,精准定位Claude专线 + // Claude专线独立代理组: 始终显示为下拉菜单 (select类型) + // 无论是否有硅谷节点,都创建Claude专线组,让用户手动选择 + // 有SV节点时优先SV,无SV节点时使用现有节点 const claudeProxies = svNode ? ` - "${svNode.name}"\n${nodes.length > 1 ? ' - "♻️ 自动选择"\n' : ''}${nodeNames}` - : toolProxies; + : (nodes.length > 1 ? ` - "♻️ 自动选择"\n${nodeNames}` : nodeNames); - // Claude专线代理组YAML块 - const claudeGroupBlock = svNode ? ` + // Claude专线代理组YAML块 — 始终生成 (下拉选择·select类型) + const claudeGroupBlock = ` - name: "🇺🇸 Claude专线" type: select proxies: ${claudeProxies} -` : ''; +`; return `# 光湖语言世界 · ${user.label} 的独立专线 — 冰朔开发维护 # 自动生成 · ${new Date().toISOString()} @@ -451,9 +452,9 @@ ${toolProxies} # ── 路由规则 ────────────────────────────── rules: - # Claude专线 (独立代理组·手动选择·精准定位) - - DOMAIN-SUFFIX,claude.ai,${svNode ? '🇺🇸 Claude专线' : '🤖 AI服务'} - - DOMAIN-SUFFIX,anthropic.com,${svNode ? '🇺🇸 Claude专线' : '🤖 AI服务'} + # Claude专线 (独立代理组·下拉选择·始终可选) + - DOMAIN-SUFFIX,claude.ai,🇺🇸 Claude专线 + - DOMAIN-SUFFIX,anthropic.com,🇺🇸 Claude专线 # AI服务 (其他AI) - DOMAIN-SUFFIX,openai.com,🤖 AI服务 @@ -803,18 +804,28 @@ mode: direct boostStatus = bs.current?.bbr?.is_bbr ? '✅ BBR加速中' : '⚠️ 未加速'; } catch { /* ignore */ } - // 读取用户带宽共享状态 + // 读取用户带宽共享状态 (系统内部状态) let bwContribStatus = '未加入'; let bwContribActive = false; + let bwContribAuthTime = ''; + let bwIpAuthorized = false; try { const bwPool = require('./bandwidth-pool-agent'); const contribInfo = bwPool.isContributor(user.email); if (contribInfo.is_contributor) { bwContribActive = contribInfo.status === 'active'; + bwIpAuthorized = true; bwContribStatus = bwContribActive ? '🚀 加速已生效' : '⚠️ 已暂停'; + bwContribAuthTime = contribInfo.authorized_at || ''; } } catch { /* ignore */ } + // 读取带宽池状态 (加速池整体数据) + let bwPoolInfo = { total_contributors: 0, active_contributors: 0, total_contributed_gb: 0, pool_status: 'idle' }; + try { + bwPoolInfo = JSON.parse(fs.readFileSync(path.join(DATA_DIR, 'bandwidth-pool-status.json'), 'utf8')); + } catch { /* ignore */ } + // 读取今日流量快照 let todayGB = '—'; try { @@ -825,6 +836,9 @@ mode: direct } } catch { /* ignore */ } + // Claude专线节点检测 + const svNode = nodes.find(n => n.region === 'us-sv'); + const poolBarColor = poolPct > 90 ? '#e74c3c' : poolPct > 70 ? '#f39c12' : '#2ecc71'; // HTML转义防止XSS @@ -853,6 +867,12 @@ mode: direct .node:last-child { border-bottom: none; } .online { color: #2ecc71; } .footer { text-align: center; padding: 20px 0; color: #555; font-size: 0.75em; } + .accel-badge { display: inline-block; padding: 3px 10px; border-radius: 6px; font-size: 0.8em; font-weight: 600; } + .accel-on { background: rgba(46,204,113,0.15); color: #2ecc71; border: 1px solid rgba(46,204,113,0.3); } + .accel-off { background: rgba(241,196,15,0.1); color: #f1c40f; border: 1px solid rgba(241,196,15,0.2); } + .refresh-btn { display: inline-block; padding: 8px 16px; background: linear-gradient(135deg,#667eea,#764ba2); color: #fff; border: none; border-radius: 8px; font-size: 0.85em; font-weight: 600; cursor: pointer; text-decoration: none; } + .refresh-btn:active { opacity: 0.8; } + .sub-btn { display: block; width: 100%; padding: 12px; background: linear-gradient(135deg,#f093fb,#f5576c); color: #fff; border: none; border-radius: 10px; font-size: 0.95em; font-weight: 600; cursor: pointer; margin-top: 8px; text-decoration: none; text-align: center; } @@ -861,6 +881,20 @@ mode: direct

${esc(user.label)} 的专属仪表盘 — 冰朔开发维护

+ +
+

🔥 加速状态 ${bwContribActive ? '加速中' : '未加速'}

+
IP授权${bwIpAuthorized ? '✅ 已授权' : '❌ 未授权'}
+
带宽加速${bwContribStatus}
+
网速增强${bwContribActive ? '✅ 已开启' : '⚠️ 未开启'}
+
反向加速${boostStatus}
+
加速池人数${bwPoolInfo.active_contributors}人在线 / ${bwPoolInfo.total_contributors}人
+ ${bwContribAuthTime ? '
授权时间' + new Date(bwContribAuthTime).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }) + '
' : ''} +
+ +
+
+

📊 流量概览

今日用量${todayGB} GB
@@ -875,15 +909,28 @@ mode: direct

🔌 节点状态 (${nodes.length}个)

${nodes.map(n => `
${esc(n.name)}${n.latency_ms ? n.latency_ms + 'ms' : '在线'}
`).join('\n ')} + ${svNode ? '
🇺🇸 Claude专线可用 · 在VPN软件中选择「Claude专线」分组即可精准切换
' : ''}

⚡ 系统状态

服务版本V3.0
-
反向加速${boostStatus}
-
带宽共享${bwContribStatus}
在线用户${poolStatus.users_count}
智能选路${nodes.length > 1 ? '✅ url-test' : '单节点'}
+
Claude专线${svNode ? '✅ 硅谷节点在线' : '⚠️ 暂不可用'}
+
+ + +
+

🔄 更新VPN配置

+

+ 合并代码后,VPN配置自动更新。您只需在VPN软件中刷新订阅即可获取最新配置。 +

+
+ 📱 Shadowrocket: 首页 → 长按订阅链接 → 更新
+ 💻 Clash Verge: 订阅页 → 点击刷新图标
+ 📱 ClashMi: 配置 → 点击更新按钮 +
@@ -922,6 +969,24 @@ mode: direct var dashIdx = window.location.pathname.indexOf('/dashboard/'); var bwBasePath = dashIdx >= 0 ? window.location.pathname.substring(0, dashIdx) : ''; +// 刷新加速状态 (从带宽池API获取最新数据) +function refreshAccelStatus() { + var btn = event.target; + btn.textContent = '⏳ 刷新中...'; + btn.disabled = true; + + fetch(bwBasePath + '/bandwidth-pool-status').then(function(r) { return r.json(); }).then(function(data) { + if (data.success) { + document.getElementById('poolContributors').textContent = (data.active_contributors || 0) + '人在线 / ' + (data.total_contributors || 0) + '人'; + } + // 刷新整个页面以获取最新的用户授权状态 + window.location.reload(); + }).catch(function() { + btn.textContent = '🔄 刷新加速状态'; + btn.disabled = false; + }); +} + function bwSendCode() { var email = document.getElementById('bwEmail').value.trim().toLowerCase(); var btn = document.getElementById('bwSendBtn'); @@ -1020,16 +1085,22 @@ function bwVerifyCode() { result.style.background = '#1a3a2a'; result.style.color = '#2ecc71'; btn.textContent = '✅ 授权成功'; - // 更新系统状态中的加速状态 - var accelEl = document.getElementById('bwAccelStatus'); - if (accelEl) accelEl.textContent = '🚀 加速已生效'; + // 授权成功 → 自动更新加速状态面板 + document.getElementById('bwAccelStatus').textContent = '🚀 加速已生效'; + document.getElementById('ipAuthStatus').textContent = '✅ 已授权'; + document.getElementById('speedBoostStatus').textContent = '✅ 已开启'; + var badge = document.getElementById('accelBadge'); + if (badge) { badge.textContent = '加速中'; badge.className = 'accel-badge accel-on'; } + result.textContent = (data.message || '授权成功!') + ' 刷新页面查看完整状态'; + // 3秒后自动刷新页面,加载最新服务器状态 + setTimeout(function() { window.location.reload(); }, 3000); } else { result.style.background = '#3a1a1a'; result.style.color = '#e74c3c'; btn.disabled = false; btn.textContent = '🔑 提交验证码'; + result.textContent = data.message || '验证失败'; } - result.textContent = data.message || (data.success ? '授权成功!' : '验证失败'); }).catch(function() { btn.disabled = false; btn.textContent = '🔑 提交验证码'; @@ -2107,11 +2178,73 @@ async function submitCode(e) { return; } + // ═══════════════════════════════════════════════ + // ∞+1 公开API: /bandwidth-user-status (无需token·用户加速状态) + // 系统内部状态关联 → 用户刷新后自动展示授权/加速/网速状态 + // ═══════════════════════════════════════════════ + if (pathname === '/bandwidth-user-status' && req.method === 'POST') { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); + + let body = ''; + req.on('data', chunk => { body += chunk; if (body.length > 1024) req.destroy(); }); + req.on('end', () => { + try { + let email = ''; + if (req.headers['content-type']?.includes('application/json')) { + const json = JSON.parse(body); + email = String(json.email || '').trim().toLowerCase(); + } else { + const params = new URLSearchParams(body); + email = String(params.get('email') || '').trim().toLowerCase(); + } + + if (!email || !email.includes('@')) { + res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' }); + res.end(JSON.stringify({ success: false, message: '请输入有效的邮箱地址' })); + return; + } + + const bwPool = require('./bandwidth-pool-agent'); + const contribInfo = bwPool.isContributor(email); + const poolStatus = bwPool.getPoolStatus(); + + // 读取反向加速状态 + let bbrActive = false; + try { + const bs = JSON.parse(fs.readFileSync(path.join(DATA_DIR, 'reverse-boost-status.json'), 'utf8')); + bbrActive = !!(bs.current?.bbr?.is_bbr); + } catch { /* ignore */ } + + res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' }); + res.end(JSON.stringify({ + success: true, + ip_authorized: contribInfo.is_contributor, + bandwidth_accelerated: contribInfo.is_contributor && contribInfo.status === 'active', + speed_boosted: contribInfo.is_contributor && contribInfo.status === 'active', + bbr_active: bbrActive, + contributor_status: contribInfo.status, + authorized_at: contribInfo.authorized_at, + pool_active_contributors: poolStatus.active_contributors, + pool_total_contributors: poolStatus.total_contributors, + pool_contributed_gb: poolStatus.total_contributed_gb, + pool_status: poolStatus.pool_status + })); + } catch (err) { + res.writeHead(500, { 'Content-Type': 'application/json; charset=utf-8' }); + res.end(JSON.stringify({ success: false, message: '系统异常' })); + } + }); + return; + } + // ═══ CORS预检 (OPTIONS) 支持 ═══ if (req.method === 'OPTIONS' && ( pathname === '/bandwidth-send-code' || pathname === '/bandwidth-verify-code' || - pathname === '/bandwidth-pool-status' + pathname === '/bandwidth-pool-status' || + pathname === '/bandwidth-user-status' )) { res.writeHead(204, { 'Access-Control-Allow-Origin': '*',