110 lines
3.4 KiB
JavaScript
110 lines
3.4 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
const WebSocket = require('ws');
|
||
|
|
const https = require('https');
|
||
|
|
|
||
|
|
const ROOM_CODE = process.argv[2] || 'LSBN';
|
||
|
|
const PLAYER_NAME = process.argv[3] || 'PROBE_WS';
|
||
|
|
const ROLE = process.argv[4] || 'player'; // 'player' or 'audience'
|
||
|
|
const USER_ID = `probe-${Date.now()}`;
|
||
|
|
|
||
|
|
function getRoomInfo(code) {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
https.get(`https://ecast.jackboxgames.com/api/v2/rooms/${code}`, res => {
|
||
|
|
let data = '';
|
||
|
|
res.on('data', c => data += c);
|
||
|
|
res.on('end', () => {
|
||
|
|
try {
|
||
|
|
const json = JSON.parse(data);
|
||
|
|
if (json.ok) resolve(json.body);
|
||
|
|
else reject(new Error(json.error || 'Room not found'));
|
||
|
|
} catch (e) { reject(e); }
|
||
|
|
});
|
||
|
|
}).on('error', reject);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function ts() {
|
||
|
|
return new Date().toISOString().slice(11, 23);
|
||
|
|
}
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
console.log(`[${ts()}] Fetching room info for ${ROOM_CODE}...`);
|
||
|
|
const room = await getRoomInfo(ROOM_CODE);
|
||
|
|
console.log(`[${ts()}] Room: ${room.appTag}, host: ${room.host}, locked: ${room.locked}`);
|
||
|
|
|
||
|
|
let wsUrl;
|
||
|
|
if (ROLE === 'audience') {
|
||
|
|
wsUrl = `wss://${room.audienceHost}/api/v2/audience/${ROOM_CODE}/play`;
|
||
|
|
} else {
|
||
|
|
wsUrl = `wss://${room.host}/api/v2/rooms/${ROOM_CODE}/play?role=${ROLE}&name=${encodeURIComponent(PLAYER_NAME)}&userId=${USER_ID}&format=json`;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(`[${ts()}] Connecting: ${wsUrl}`);
|
||
|
|
|
||
|
|
const ws = new WebSocket(wsUrl, ['ecast-v0'], {
|
||
|
|
headers: {
|
||
|
|
'Origin': 'https://jackbox.tv',
|
||
|
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
let msgCount = 0;
|
||
|
|
|
||
|
|
ws.on('open', () => {
|
||
|
|
console.log(`[${ts()}] CONNECTED`);
|
||
|
|
});
|
||
|
|
|
||
|
|
ws.on('message', (raw) => {
|
||
|
|
msgCount++;
|
||
|
|
try {
|
||
|
|
const msg = JSON.parse(raw.toString());
|
||
|
|
const summary = summarize(msg);
|
||
|
|
console.log(`[${ts()}] RECV #${msgCount} | pc:${msg.pc} | opcode:${msg.opcode} | ${summary}`);
|
||
|
|
if (process.env.VERBOSE === 'true') {
|
||
|
|
console.log(JSON.stringify(msg, null, 2));
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
console.log(`[${ts()}] RECV #${msgCount} | raw: ${raw.toString().slice(0, 200)}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
ws.on('close', (code, reason) => {
|
||
|
|
console.log(`[${ts()}] CLOSED code=${code} reason=${reason}`);
|
||
|
|
process.exit(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
ws.on('error', (err) => {
|
||
|
|
console.error(`[${ts()}] ERROR: ${err.message}`);
|
||
|
|
});
|
||
|
|
|
||
|
|
process.on('SIGINT', () => {
|
||
|
|
console.log(`\n[${ts()}] Closing (${msgCount} messages received)`);
|
||
|
|
ws.close();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function summarize(msg) {
|
||
|
|
if (msg.opcode === 'client/welcome') {
|
||
|
|
const r = msg.result || {};
|
||
|
|
const hereIds = r.here ? Object.keys(r.here) : [];
|
||
|
|
const entityKeys = r.entities ? Object.keys(r.entities) : [];
|
||
|
|
return `id=${r.id} name=${r.name} reconnect=${r.reconnect} here=[${hereIds}] entities=[${entityKeys}]`;
|
||
|
|
}
|
||
|
|
if (msg.opcode === 'object') {
|
||
|
|
const r = msg.result || {};
|
||
|
|
const valKeys = r.val ? Object.keys(r.val).slice(0, 5).join(',') : 'null';
|
||
|
|
return `key=${r.key} v${r.version} from=${r.from} val=[${valKeys}...]`;
|
||
|
|
}
|
||
|
|
if (msg.opcode === 'client/connected') {
|
||
|
|
const r = msg.result || {};
|
||
|
|
return `id=${r.id} userId=${r.userId} name=${r.name} role=${r.role}`;
|
||
|
|
}
|
||
|
|
if (msg.opcode === 'client/disconnected') {
|
||
|
|
const r = msg.result || {};
|
||
|
|
return `id=${r.id} role=${r.role}`;
|
||
|
|
}
|
||
|
|
return JSON.stringify(msg.result || msg).slice(0, 150);
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch(e => { console.error(e); process.exit(1); });
|