A decentralized music tracking and discovery platform built on AT Protocol 🎵
rocksky.app
spotify
atproto
lastfm
musicbrainz
scrobbling
listenbrainz
1#!/usr/bin/env -S deno run --allow-net
2
3const WS_URL = Deno.env.get("WS_URL") || "ws://localhost:2481";
4const SLOW_MODE = Deno.env.get("SLOW_MODE") === "true"; // Set SLOW_MODE=true to slow down
5
6console.log(`🔌 Connecting to ${WS_URL}...`);
7if (SLOW_MODE) {
8 console.log(`🐌 SLOW MODE enabled - will process messages slowly`);
9}
10
11const ws = new WebSocket(WS_URL);
12
13let messageCount = 0;
14let startTime = Date.now();
15let lastMessageTime = Date.now();
16
17ws.onopen = () => {
18 console.log("✅ WebSocket connection opened");
19 console.log(` readyState: ${ws.readyState}`);
20 console.log(` Time: ${new Date().toISOString()}`);
21
22 // Send ping immediately
23 console.log("📤 Sending ping...");
24 ws.send("ping");
25
26 // Send ping every 30 seconds (less frequent to not interfere with fast streaming)
27 setInterval(() => {
28 if (ws.readyState === WebSocket.OPEN) {
29 const now = Date.now();
30 const timeSinceLastMessage = now - lastMessageTime;
31 console.log(
32 `📤 Sending ping... (${timeSinceLastMessage}ms since last message)`,
33 );
34 ws.send("ping");
35 }
36 }, 30000);
37};
38
39ws.onmessage = async (event) => {
40 messageCount++;
41 lastMessageTime = Date.now();
42 const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
43
44 try {
45 const data = JSON.parse(event.data);
46
47 // Handle batched messages (array of events)
48 if (Array.isArray(data)) {
49 messageCount += data.length;
50 if (messageCount % 500 === 0 || messageCount <= 50) {
51 console.log(
52 `📨 [${elapsed}s] Batch received: ${data.length} events (total: ${messageCount})`,
53 );
54 }
55 }
56 // Handle single messages
57 else if (data.type === "connected") {
58 console.log(`📨 [${elapsed}s] Connection confirmed: ${data.message}`);
59 } else if (data.type === "heartbeat") {
60 console.log(`💓 [${elapsed}s] Heartbeat received`);
61 } else if (data.type === "error") {
62 console.log(`❌ [${elapsed}s] Error: ${data.message}`);
63 } else {
64 if (messageCount % 100 === 0 || messageCount <= 10) {
65 console.log(`📨 [${elapsed}s] Message #${messageCount}:`, data);
66 }
67 }
68 } catch {
69 // Not JSON, just log as text
70 console.log(`📨 [${elapsed}s] Message #${messageCount}: ${event.data}`);
71 }
72
73 if (messageCount % 500 === 0) {
74 const rate = (messageCount / parseFloat(elapsed)).toFixed(2);
75 console.log(
76 `📊 Progress: ${messageCount} events received in ${elapsed}s (${rate} events/s)`,
77 );
78 }
79
80 // In slow mode, add delay to simulate slow client
81 if (SLOW_MODE && messageCount % 10 === 0) {
82 await new Promise((resolve) => setTimeout(resolve, 10));
83 }
84};
85
86ws.onerror = (error) => {
87 console.error("❌ WebSocket error occurred");
88 console.error(" Error:", error);
89 console.error(" Time:", new Date().toISOString());
90 console.error(" Messages received so far:", messageCount);
91};
92
93ws.onclose = (event) => {
94 const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
95 const rate =
96 messageCount > 0 ? (messageCount / parseFloat(elapsed)).toFixed(2) : "0";
97
98 console.log(`\n❌ WebSocket closed after ${elapsed}s`);
99 console.log(` Code: ${event.code}`);
100 console.log(` Reason: ${event.reason || "No reason provided"}`);
101 console.log(` Clean: ${event.wasClean}`);
102 console.log(` Total messages received: ${messageCount}`);
103 console.log(` Average rate: ${rate} messages/second`);
104 console.log(` Time: ${new Date().toISOString()}`);
105
106 if (event.code === 1006) {
107 console.error(`\n⚠️ ERROR 1006: Abnormal Closure`);
108 console.error(
109 ` This means the connection dropped without proper close frame.`,
110 );
111 console.error(` Last message was ${Date.now() - lastMessageTime}ms ago`);
112 console.error(` Possible causes:`);
113 console.error(` - Server sent messages too fast (backpressure)`);
114 console.error(` - Server crashed or panicked`);
115 console.error(` - Network timeout or interruption`);
116 console.error(` - Client couldn't keep up with message rate`);
117 console.error(
118 `\n Try running with: SLOW_MODE=true deno run --allow-net scripts/test-client.ts`,
119 );
120 }
121
122 Deno.exit(event.wasClean ? 0 : 1);
123};
124
125// Handle Ctrl+C gracefully
126Deno.addSignalListener("SIGINT", () => {
127 console.log("\n🛑 Closing connection...");
128 ws.close();
129});
130
131console.log("⏳ Waiting for messages... (Press Ctrl+C to exit)");