// % import nodejs dependencies const WebSocket = require('ws'); const fs = require('fs'); const path = require('path'); // % get arguments const args = process.argv.slice(2); const mode = args[0] || 'custom'; const channel = args[1]; // % set nickname for twitch testing const nick = 'justinfan' + Math.floor(Math.random() * 100000); // % declare external websocket urls and set mode const customUrl = channel || 'wss://echo.websocket.org'; const twitchUrl = 'wss://irc-ws.chat.twitch.tv:443'; const url = mode === 'twitch' ? twitchUrl : customUrl; console.log(`▶ Using ${mode} endpoint: ${url}`); // $ establish new websocket connection const ws = new WebSocket(url); // % configure websocket settings let lastPingTimestamp = null; let testCount = 0; let logBuffer = []; let pingTimeout = null; // % configure logging const logDir = path.join(__dirname, 'logs'); if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true }); const logFile = path.join(logDir, `wslog_${mode}_${Date.now()}.txt`); // $ push log buffer function addLog(entry) { logBuffer.push(entry); } // $ finalize testing script function finalizeAndExit() { // % clear ping timeout if exists if (pingTimeout) clearTimeout(pingTimeout); // ~ write log file fs.writeFileSync(logFile, `=== WebSocket Log (${mode}) at ${new Date().toISOString()} ===\n` + logBuffer.join('\n')); // ~ Log success to console console.log(`\n📂 Log file created: ${logFile}`); console.log(`✅ Program will close in 3 seconds...`); // ~ close the tester setTimeout(() => process.exit(0), 3000); } // $ activate ping requests function scheduleTestPing() { // ~ end script after tester ran 5 times if (testCount >= 5) return finalizeAndExit(); // ~ set a timeout for pings of 5 seconds pingTimeout = setTimeout(() => { // % create last ping timestamp lastPingTimestamp = Date.now(); // % create reference for a message let msg; // ~ send a websocket message to a server if (mode === 'twitch') { msg = 'PING :tmi.twitch.tv'; ws.send(msg); } else { msg = 'PING'; ws.send(msg); } // % create a log message const logMsg = `${new Date().toISOString()} ➡️ Sent ${msg}`; // ~ log in console and file console.log(logMsg); addLog(logMsg); // ~ add a count of +1 to testCount variable testCount++; // ~ run test ping again till counter exceeds 5 scheduleTestPing(); }, 5000); } // $ websocket configuration when connection opens ws.on('open', () => { // ~ console logging of connection console.log(`${new Date().toISOString()} ✅ Connected to ${mode}`); // ~ configure websocket authentication to twitch if (mode === 'twitch') { ws.send('PASS SCHMOOPIIE'); ws.send(`NICK ${nick}`); ws.send(`JOIN ${channel}`); console.log(`${new Date().toISOString()} ➡️ Logged in as ${nick}, Channel: ${channel}`); } // ~ run test ping scheduleTestPing(); }); // $ websocket configuration on receiving a message ws.on('message', (data) => { // % convert message to string and get timestamp const msg = data.toString(); const now = new Date().toISOString(); // § check active run mode if (mode === 'custom') { // § check if a ping arrives if (msg.toLowerCase().includes('ping')) { // ~ send a pong ws.send('PONG'); // ~ log message to console and file const logMsg = `${now} ⬅️ Echo PING received → PONG sent`; console.log(logMsg); addLog(logMsg); // ~ log receive duration to console and file const rtt = Date.now() - lastPingTimestamp; const rttMsg = `${now} ⬅️ PONG received (RTT: ${rtt} ms)`; console.log(rttMsg); addLog(rttMsg); } } else { // ~ log everything on twitch mode to console and file const logMsg = `${now} ⬅️ ${msg.trim()}`; console.log(logMsg); addLog(logMsg); } }); // $ websocket configuration on error ws.on('error', (err) => { // ~ log error to console and file const msg = `${new Date().toISOString()} ❌ Error: ${err.message}`; console.error(msg); addLog(msg); }); // $ websocket configuration on close ws.on('close', () => { // ~ log closing to console and file const msg = `${new Date().toISOString()} ⚠️ Connection closed`; console.log(msg); addLog(msg); });