227 lines
7.1 KiB
JavaScript
227 lines
7.1 KiB
JavaScript
var Client = require('./lib/Client.js');
|
|
|
|
global.createMPPbridge = async function createMPPbridge({room, channel, uri}) {
|
|
channel = dClient.channels.resolve(channel);
|
|
var webhooks = await channel.fetchWebhooks();
|
|
var webhook = webhooks.filter(w => w.token).first() || await channel.createWebhook("sdfadffg");
|
|
|
|
{ // discord message sending
|
|
let msgBuffer = [];
|
|
function _dSend(options) {
|
|
|
|
if (options.content?.length > 2000) {
|
|
options.attachments ||= [];
|
|
options.attachments.push(new Discord.MessageAttachment(Buffer.from(options.content), "message.txt"));
|
|
delete options.content;
|
|
}
|
|
|
|
let username = gClient.channel && gClient.channel._id || room;
|
|
if (username.length > 80) username = username.substr(0,79) + '…';
|
|
|
|
webhook.send(Object.assign(options, {username})).catch(error => {
|
|
handleError(error, `webhook fail in ${channel.id}`);
|
|
channel.send(options).catch(error => handleError(error, `send fail in ${channel.id} after webhook send fail`));
|
|
});
|
|
|
|
}
|
|
function dSend(msg, options) {
|
|
if (arguments.length == 1) options = msg;
|
|
else {
|
|
options ||= {};
|
|
options.content = msg;
|
|
}
|
|
msgBuffer.push(options);
|
|
}
|
|
setInterval(()=>{
|
|
if (msgBuffer.length == 0) return;
|
|
_dSend(msgBuffer.join('\n'));
|
|
msgBuffer = [];
|
|
}, 3000);
|
|
}
|
|
|
|
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) {
|
|
dSend(`**${error.toString()}**`);
|
|
lastError = error;
|
|
}
|
|
});
|
|
var isConnected = false; // TODO use gClient.isConnected() ?
|
|
gClient.on('connect', () => {
|
|
console.log(`[${uri}][${room}] Connected to server`);
|
|
dSend(`**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`);
|
|
dSend(`**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) {
|
|
dSend(`**Joined channel \`${msg.ch._id}\`**`);
|
|
console.log(`[${uri}][${room}] Joined channel ${msg.ch._id}`);
|
|
}
|
|
// announce channel change
|
|
else if (msg.ch._id !== lastCh) {
|
|
dSend(`**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 = escapeDiscordMentions(msg.a);
|
|
var str = `\`${id}\` **${name}:** ${content}`;
|
|
dSend(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.member.displayName}#${message.member.user.discriminator}`;
|
|
if (str.startsWith('/') || str.startsWith('\\'))
|
|
msgQueue.push(`⤹ ${aname}`);
|
|
else
|
|
str = `${aname}: ${str}`;
|
|
if (str.startsWith('\\')) str = str.slice(1);
|
|
if (message.attachments.first()) str += ' '+message.attachments.first().url;
|
|
if (str.length > 512) str = str.substr(0,511) + '…';
|
|
msgQueue.push(str);
|
|
});
|
|
setInterval(()=>{
|
|
let message = msgQueue.shift();
|
|
if (message) gClient.sendArray([{m:'a', message}]);
|
|
}, 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)
|
|
dSend(`\`${participant._id.substr(0,6)}\` ___**${sanitizeName(oldName)}** changed their name to **${sanitizeName(newName)}**___`);
|
|
} else { // is join
|
|
dSend(`\`${participant._id.substr(0,6)}\` ___**${sanitizeName(participant.name)}** entered the room.___`);
|
|
}
|
|
});
|
|
gClient.prependListener("bye", async msg => {
|
|
var participant = gClient.ppl[msg.p];
|
|
dSend(`\`${participant._id.substr(0,6)}\` ___**${sanitizeName(participant.name)}** left the room.___`);
|
|
});
|
|
|
|
|
|
|
|
// on notifications
|
|
gClient.on('notification', async msg => {
|
|
// show notification
|
|
dSend({embeds:[{
|
|
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);
|
|
dSend(`**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
|
|
{
|
|
// record raw data
|
|
let createWSMessageCollector = require("./datacollector")
|
|
gClient.on("message", createWSMessageCollector(async function(data, startDate, endDate){
|
|
var attachmentName = `${uri} ${room} raw data recording from ${startDate.toISOString()} to ${endDate.toISOString()} .txt.gz`;
|
|
await channel.send(new Discord.MessageAttachment(data, attachmentName));
|
|
}));
|
|
}
|
|
|
|
return gClient;
|
|
};
|
|
|
|
|
|
|
|
// start
|
|
(async function () {
|
|
global.bridges = require("./bridges");
|
|
for (let bridge of bridges) {
|
|
try {
|
|
bridge.client = await createMPPbridge(bridge);
|
|
} catch(e) {
|
|
handleError(error, JSON.stringify(bridge));
|
|
}
|
|
}
|
|
})(); |