var Client = require('./lib/Client.js'); var WebSocketMessageCollector = require("./lib/datacollector"); var DiscordMessageSender = require("./lib/DiscordMessageSender"); global.createMPPbridge = async function createMPPbridge({room, channel, uri}) { channel = dClient.channels.resolve(channel); var d = new DiscordMessageSender(channel); const gClient = new Client(uri); if (uri == "wss://mppclone.com:8443") gClient.token = config.mpc_token; //todo hmm gClient.setChannel(room, {visible:false}); gClient.start(); // maintain the client's presence in the channel gClient.channelCorrectorInterval = setInterval(()=>{ // if client is connected and not in a channel (meaning setChannel failed due to ratelimit because another client joined a channel with the same user within the last second) OR client is in a channel but it is not the right channel… if ((gClient.isConnected() && !gClient.channel) || (gClient.channel && gClient.channel._id != room)) // …set the channel! gClient.setChannel(room, {visible:false}); }, 1000); let lastError; gClient.on("error", error => { //handleError(error, `[${uri}][${room}]`); error = error.toString(); if (lastError != error) { d.send(`**${error.toString()}**`); lastError = error; } }); var isConnected = false; // TODO use gClient.isConnected() ? gClient.on('connect', () => { console.log(`[${uri}][${room}] Connected to server`); d.send(`**Connected to server; joining channel…**`); isConnected = true; lastError = undefined; }); gClient.on('hi', ()=>{ console.log(`[${uri}][${room}] Received greeting`); if (!testmode) { gClient.sendArray([{m: "userset", set: {name: config.mppname }}]); } gClient.sendArray([{m:'m',x:Math.floor(Math.random()*100),y:Math.floor(Math.random()*100)}]) }); gClient.on('disconnect', () => { if (isConnected) { console.log(`[${uri}][${room}] Disconnected from server`); d.send(`**Disconnected from server**`); isConnected = false; } }); /*gClient.on('status', status => { console.log(`[${uri}] [${room}] ${status}`); });*/ // on channel change { let lastCh; gClient.on('ch', async msg => { // announce channel join if (!lastCh) { d.send(`**Joined channel \`${msg.ch._id}\`**`); console.log(`[${uri}][${room}] Joined channel ${msg.ch._id}`); } // announce channel change else if (msg.ch._id !== lastCh) { d.send(`**Channel changed from \`${lastCh}\` to \`${msg.ch._id}\`**`); console.log(`[${uri}][${room}] Channel changed from ${lastCh} to ${msg.ch._id}`); } lastCh = msg.ch._id; }); gClient.on("disconnect", () => lastCh = undefined); } // MPP to Discord gClient.on('a', async msg => { if (msg.p._id == gClient.getOwnParticipant()._id) return; var id = msg.p._id.substr(0,6); var name = sanitizeName(msg.p.name); var content = msg.a; var str = `\`${id}\` **${name}:** ${content}`; d.send(str); }); // Discord to MPP { let msgQueue = []; dClient.on('message', async message => { if (message.channel.id !== channel.id || message.author.id == dClient.user.id || !message.member /*|| message.content.startsWith('!')*/) return; var str = message.cleanContent; var aname = message.author.tag; if (str.startsWith('/') || str.startsWith('\\')) msgQueue.push(`⤹ ${aname}`); else str = `${aname}: ${str}`; if (str.startsWith('\\')) str = str.slice(1); if (message.attachments.size > 0) str += ' ' + message.attachments.map(a => a.url).join(' '); if (str.length > 512) { str = str.substr(0,511) + '…'; message.react('⚠'); } msgQueue.push(str); }); setInterval(()=>{ let message = msgQueue.shift(); if (message) gClient.sendArray([{m:'a', message}]); //todo wait moment to see if message got through then react warning if didnt }, 1600); // just about fastest without exceeding quota; I figured quota is 4 messages per 6 seconds in lobbies } // announce join/leave/rename gClient.prependListener("p", async participant => { if (gClient.ppl[participant.id]) { // is update let oldName = gClient.ppl[participant.id].name, newName = participant.name; if (newName != oldName) d.send(`\`${participant._id.substr(0,6)}\` ___**${sanitizeName(oldName)}** changed their name to **${sanitizeName(newName)}**___`); } else { // is join d.send(`\`${participant._id.substr(0,6)}\` ___**${sanitizeName(participant.name)}** entered the room.___`); } }); gClient.prependListener("bye", async msg => { var participant = gClient.ppl[msg.p]; if (!participant) return; d.send(`\`${participant._id.substr(0,6)}\` ___**${sanitizeName(participant.name)}** left the room.___`); }); // on notifications gClient.on('notification', async msg => { // show notification d.sendEmbed({ title: msg.title, description: msg.text || msg.html }); // handle bans if (msg.text && (msg.text.startsWith('Banned from "'+room+'"') || msg.text.startsWith('Currently banned from "'+room+'"'))) { // Banned from "{room}" for {n} minutes. // Currently banned from "{room}" for {n} minutes. let arr = msg.text.split(' '); arr.pop(); let minutes = arr.pop(); gClient.stop(); setTimeout(()=>{ gClient.setChannel(room); gClient.start(); }, minutes*60*1000+3000); d.send(`**Attempting to rejoin in ${minutes} minutes.**`); } }); // make room invisible when nobody else is in it gClient.on("ch", async function(msg){ if (gClient.isOwner()) { if (gClient.countParticipants() <= 1) { gClient.sendArray([{m:'chset', set: { visible: false }}]) } else { gClient.sendArray([{m:'chset', set: { visible: true }}]) } } }); // addons var wsc = new WebSocketMessageCollector(async function(data, startDate, endDate) { var attachmentName = `${uri} ${room} raw data recording from ${startDate.toISOString()} to ${endDate.toISOString()} .txt.gz`; await channel.send({files:[{ attachment: data, name: attachmentName }]}); }); gClient.on("message", wsc.collect.bind(wsc)); return gClient; }; // start dClient.once("ready", async function () { global.bridges = require("./bridges"); for (let bridge of bridges) { try { bridge.client = await createMPPbridge(bridge); } catch(e) { handleError(error, JSON.stringify(bridge)); } } });