一、项目背景
本项目用于调研 DexScreener 平台的数据。DexScreener 提供 WebSocket 接口,对外推送代币资料(Token Profiles)、广告消耗(Ads)、Boost 消耗(Boosts)等实时数据。
通过本地部署本监控服务,可以:
- 持续接收并落库上述三类推送数据,便于离线分析与审计;
- 在仪表盘中按时间范围、链、地址等维度查看与统计;
- 对推送内容做 MD5 去重,只保留「有变化」的更新,减少冗余。
数据来源均为 DexScreener 官方 WebSocket,仅做采集与展示,不修改原始内容。
二、项目架构
整体为单进程:HTTP 服务 + 3 个 WebSocket 客户端 + SQLite。执行 npm run monitor 会同时启动监控面板与所有采集端。
2.1 入口与 HTTP
- 入口:
server.js(Node.js HTTP 服务,默认端口 3000)。 - 路由:
/重定向到/dashboard;/dashboard、/index.html提供 SPA;/api/*为数据接口;/docs为本文档;其余为静态资源(如/logo.png)。 - 前端:
public/index.html单页应用,含 Dashboard、Profiles 更新记录、Ads/Boosts 更新与消耗追踪等 Tab。
2.2 WebSocket 采集
三个独立模块,各连一个 DexScreener WebSocket,连接即订阅,无需发送 subscribe 消息:
| 名称 | URL | 实现文件 |
|---|---|---|
| Token Profiles | wss://api.dexscreener.com/token-profiles/latest/v1 | src/ws-profiles.js |
| Ads | wss://api.dexscreener.com/ads/latest/v1 | src/ws-ads.js |
| Boosts | wss://api.dexscreener.com/token-boosts/latest/v1 | src/ws-boosts.js |
断线后约 5 秒自动重连。
2.3 数据层
- 数据库:
src/db.js,better-sqlite3,库文件data/monitor.db。 - 表:
messages:原始 WebSocket 消息(channel、received_at、raw_json),三条通道均写一份,用于回放与 fallback。profile_pushes/ads_pushes/boosts_pushes:按 chain+address 拆分的去重推送(含raw_json_md5),所有对外统计均基于这三张表。ads_tracking/boosts_tracking:按 chain+token_address 的消耗追踪(impressions/amount、consumed 等),用于 Ads/Boosts 消耗 Tab。
2.4 去重与写入
每条 WebSocket 消息会:
- 写入
messages一行(channel + received_at + raw_json)。 - 按业务拆成多条(如一条消息含多 chain/address)后,对每条用
raw_json的 MD5 查是否已存在(同 chain+address+md5);存在则不再写入 push 表,实现按内容去重。
因此 profile_pushes / ads_pushes / boosts_pushes 中仅保留「有变化的」推送记录。
三、统计逻辑
所有统计均以去重后的 push 表为准,时间统一为 UTC,展示格式 YYYY-MM-DD HH:mm UTC。
3.1 时间范围
- 前端默认 24 小时:
from= 当前 UTC 时间 − 24h,to= 当前 UTC 时间(带Z传给接口)。 - 服务端
getTimeRange(query)解析query.from/query.to(或period=1h|24h|7d|all),得到fromISO、toISO,用于所有按时间过滤的查询。
3.2 Dashboard 与 API 统计
- Dashboard 概览(下方三张卡片):
/api/dashboard,按fromISO ~ toISO从profile_pushes、ads_pushes、boosts_pushes分别COUNT,得到「24h 去重更新数」及按小时分桶;统计区间以小字展示在卡片下方。 - Profiles / Ads / Boosts 更新记录 Tab:
/api/profiles、/api/ads-messages、/api/boosts-messages均从对应 push 表按时间范围查询,并做filterRowsByMd5Change(同 key 下按 received_at 排序后只保留 MD5 变化的行);列表最多返回 100 条,Total 为去重后条数。 - Profiles Duplicates:
/api/profiles-duplicates从profile_pushes取同一 (chain, address) 出现次数 > 1 的行,列表同样最多 100 条。
3.3 状态卡片(顶部)
顶部 Profiles / Ads / Boosts 状态卡片来自 /api/ws-status,展示「最后收到」与「最近1分钟」条数;若请求带 from/to(与 dashboard 一致),则 24h 相关统计与下方 dashboard 使用同一时间区间,保证口径一致。
3.4 消耗统计(Ads / Boosts Tab)
按 ads_tracking / boosts_tracking 的 chain + token_address 聚合:展示 initial、current、consumed、状态等;历史记录表内时间列格式为 YYYY-MM-DD HH:mm UTC。
3.5 搜索
/api/search?q=:Profiles 从 profile_pushes 按 address/chain LIKE 查询(去重口径);Ads/Boosts 从对应 tracking 表查询。
文档路径:public/docs.html,访问 /docs 或 /docs.html。