lepaoProxyLogDisplay.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /**
  2. * 管理员列表:可读摘要 + Arco Tag 色号(与设计约定一致)。
  3. */
  4. function parseDetail(raw) {
  5. if (raw == null || raw === '') return {}
  6. if (typeof raw === 'object') return raw
  7. try {
  8. return JSON.parse(raw)
  9. } catch {
  10. return { _text: String(raw) }
  11. }
  12. }
  13. const EVENT_META = {
  14. fetch: { label: '提取 IP', color: 'green' },
  15. invalidate: { label: '作废缓存', color: 'orangered' },
  16. fallback_direct: { label: '回退直连', color: 'red' },
  17. config_change: { label: '配置变更', color: 'arcoblue' },
  18. proxy_self_check: { label: '代理自检', color: 'purple' },
  19. proxy_self_check_skip: { label: '自检跳过', color: 'gray' },
  20. proxy_self_check_fail: { label: '自检失败', color: 'red' }
  21. }
  22. function summarizeLogRow(record) {
  23. const event = record.event
  24. const d = parseDetail(record.detail)
  25. const lines = []
  26. if (event === 'fetch') {
  27. if (d.request_id) lines.push(`请求 ID:${d.request_id}`)
  28. if (d.code) lines.push(`接口状态:${d.code}`)
  29. } else if (event === 'invalidate') {
  30. if (d.reason) lines.push(`原因:${d.reason}`)
  31. if (d.message) lines.push(`说明:${d.message}`)
  32. if (d.code) lines.push(`错误码:${d.code}`)
  33. if (d.status) lines.push(`HTTP:${d.status}`)
  34. } else if (event === 'fallback_direct') {
  35. if (d.reason) lines.push(`触发原因:${d.reason}`)
  36. if (d.reason === 'exhausted_proxy_then_direct') {
  37. lines.push('多轮提取与经代理 POST 均未成功,已改直连接口')
  38. } else if (d.message) {
  39. lines.push(`说明:${d.message}`)
  40. }
  41. if (d.after) lines.push(`阶段:${d.after}`)
  42. if (d.code) lines.push(`错误码:${d.code}`)
  43. } else if (event === 'config_change') {
  44. lines.push(`代理开关:${d.proxy_enabled === 1 ? '开' : '关'}`)
  45. if (d.area !== undefined) lines.push(`地区 area:「${d.area || '(空)'}」`)
  46. if (d.area_ex !== undefined) lines.push(`排除 area_ex:「${d.area_ex || '(空)'}」`)
  47. if (d.isp !== undefined) lines.push(`运营商 isp:${d.isp ?? '不限'}`)
  48. if (d.distinct_extract !== undefined) lines.push(`去重提取:${d.distinct_extract ? '是' : '否'}`)
  49. if (d.invalidate_cache) lines.push('已勾选清空服务端 IP 缓存')
  50. if (d.operator) lines.push(`操作者 UUID:${d.operator}`)
  51. } else if (event === 'proxy_self_check') {
  52. if (d.proxy_ip) lines.push(`代理出口IP:${d.proxy_ip}`)
  53. if (d.http_status !== undefined) lines.push(`HTTP:${d.http_status}`)
  54. if (d.target) lines.push(`目标:${d.target}`)
  55. } else if (event === 'proxy_self_check_skip') {
  56. if (d.reason) lines.push(`原因:${d.reason}`)
  57. } else if (event === 'proxy_self_check_fail') {
  58. if (d.message) lines.push(`说明:${d.message}`)
  59. if (d.code) lines.push(`错误码:${d.code}`)
  60. if (d.status !== undefined) lines.push(`HTTP:${d.status}`)
  61. } else if (Object.keys(d).length) {
  62. if (d._text) lines.push(String(d._text))
  63. else {
  64. Object.keys(d).slice(0, 6).forEach(k => {
  65. lines.push(`${k}:${typeof d[k] === 'object' ? JSON.stringify(d[k]) : d[k]}`)
  66. })
  67. }
  68. }
  69. let summary = lines.length ? lines.join(';') : '—'
  70. const meta = EVENT_META[event] || { label: event || '未知', color: 'gray' }
  71. const serverShown = record.server ? `节点 ${record.server}` : ''
  72. return {
  73. event_label: meta.label,
  74. event_color: meta.color,
  75. summary,
  76. detail_lines: lines,
  77. server_tip: serverShown || null,
  78. ...(record.server && record.deadline ? { deadline_tip: `${record.server} · ${record.deadline}` } : {})
  79. }
  80. }
  81. /**
  82. * 青果语义下的出口 IP(proxy_ip),非代理节点 host。
  83. */
  84. function extractEgressIp(record) {
  85. const d = parseDetail(record.detail)
  86. const p = d.proxy_ip
  87. if (p === null || p === undefined || p === '') return null
  88. const s = String(p).trim()
  89. return /^(\d{1,3}\.){3}\d{1,3}$/.test(s) ? s : null
  90. }
  91. module.exports = {
  92. summarizeLogRow,
  93. parseDetail,
  94. EVENT_META,
  95. extractEgressIp
  96. }