const WebSocket = require('ws');
const BOT_TOKEN = 'MTQ3NDg4NDU0NTI3ODExNTk3MQ.GKjMUM.JhcV4FLADqE7H_1lqY0qSgs90RbOYxklz1VU6A';
const ALLOWED_USERS = ['693836830436753409'];
const CHAT_CHANNEL = '1474894225786016007';
const BRIDGE_ECHO_URL = 'http://127.0.0.1:3100/chat';
const GATEWAY_URL = 'wss://gateway.discord.gg/?v=10&encoding=json';
let ws;
let heartbeatInterval = null;
let lastSequence = null;
let sessionId = null;
let resumeGatewayUrl = null;
function log(msg) {
console.log(`[${new Date().toISOString()}] ${msg}`);
}
function sendPayload(op, d) {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ op, d }));
}
}
function heartbeat() {
sendPayload(1, lastSequence);
}
function identify() {
sendPayload(2, {
token: BOT_TOKEN,
intents: (1 << 9) | (1 << 15), properties: { os: 'linux', browser: 'echo-bridge', device: 'echo-bridge' }
});
}
async function forwardToBridge(message) {
try {
const resp = await fetch(BRIDGE_ECHO_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: message.content,
channel: 'discord',
sender: 'D',
metadata: {
discord_channel_id: message.channel_id,
},
callback: {
type: 'discord',
}
}),
});
if (resp.status === 202) {
log('Message accepted — response will be delivered via callback');
} else if (!resp.ok) {
log(`bridge-echo returned ${resp.status}`);
}
} catch (err) {
log(`Failed to forward to bridge-echo: ${err.message}`);
}
}
function connect(url) {
ws = new WebSocket(url || GATEWAY_URL);
ws.on('open', () => log('Gateway connected'));
ws.on('message', (data) => {
const payload = JSON.parse(data);
const { op, t, s, d } = payload;
if (s) lastSequence = s;
switch (op) {
case 10: const interval = d.heartbeat_interval;
log(`Heartbeat interval: ${interval}ms`);
if (heartbeatInterval) clearInterval(heartbeatInterval);
heartbeatInterval = setInterval(heartbeat, interval);
heartbeat();
if (sessionId && resumeGatewayUrl) {
log('Resuming session...');
sendPayload(6, { token: BOT_TOKEN, session_id: sessionId, seq: lastSequence });
} else {
identify();
}
break;
case 11: break;
case 7: log('Server requested reconnect');
ws.close();
break;
case 9: log('Invalid session, re-identifying...');
sessionId = null;
setTimeout(identify, 2000);
break;
case 0: if (t === 'READY') {
sessionId = d.session_id;
resumeGatewayUrl = d.resume_gateway_url;
log(`Ready! Session: ${sessionId}, User: ${d.user.username}`);
}
if (t === 'MESSAGE_CREATE') {
if (d.author.bot) break;
if (!ALLOWED_USERS.includes(d.author.id)) break;
if (d.channel_id !== CHAT_CHANNEL) break;
if (!d.content) break;
log(`Message from ${d.author.username}: ${d.content.substring(0, 50)}...`);
forwardToBridge(d);
}
break;
}
});
ws.on('close', (code, reason) => {
log(`Disconnected: ${code} ${reason}`);
if (heartbeatInterval) clearInterval(heartbeatInterval);
if (code !== 4004) {
const delay = code === 4000 ? 1000 : 5000;
log(`Reconnecting in ${delay}ms...`);
setTimeout(() => connect(resumeGatewayUrl || GATEWAY_URL), delay);
} else {
log('FATAL: Authentication failed. Check bot token.');
process.exit(1);
}
});
ws.on('error', (err) => {
log(`WebSocket error: ${err.message}`);
});
}
log('Starting Discord gateway listener...');
connect();