Refactor
This commit is contained in:
parent
c215778860
commit
d0ee41b512
4 changed files with 166 additions and 65 deletions
|
@ -2,7 +2,8 @@
|
|||
"Username": "",
|
||||
"Password": "",
|
||||
"PNSLToken": "",
|
||||
"AdminID": "",
|
||||
"Users": [],
|
||||
"Prefix": "!!",
|
||||
"MaxConnections": 30,
|
||||
"MaxChunkSize": 2000,
|
||||
"DelayPerChunk": 30e3
|
||||
|
|
196
index.js
196
index.js
|
@ -1,12 +1,15 @@
|
|||
const {extend: createGotClient} = require('got');
|
||||
const {ChatClient} = require('dank-twitch-irc');
|
||||
const {ConnectionError, SayError, ChatClient} = require('dank-twitch-irc');
|
||||
const chalk = require('chalk');
|
||||
const WS = require('ws');
|
||||
const Config = require('./config.json');
|
||||
|
||||
const clients = [];
|
||||
let banChunks = [];
|
||||
const banChunks = [];
|
||||
const pingInterval = 60e3;
|
||||
let lastIndex = 0;
|
||||
const uuidRegex = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
|
||||
const msgRegex = /[\u034f\u2800\u{E0000}\u180e\ufeff\u2000-\u200d\u206D]/gu;
|
||||
|
||||
const pnslClient = createGotClient({
|
||||
prefixUrl: 'https://bot.tetyys.com/api/v1',
|
||||
|
@ -16,6 +19,71 @@ const pnslClient = createGotClient({
|
|||
},
|
||||
});
|
||||
|
||||
const fetchList = async (listID) => {
|
||||
if (!uuidRegex.test(listID)) {
|
||||
throw new Error('Invalid List ID!');
|
||||
}
|
||||
|
||||
const {body: listMetaBody, statusCode} = await pnslClient('BotLists/Properties', {searchParams: {Guid: listID}});
|
||||
if (statusCode === 404) {
|
||||
throw new Error('List was not found.');
|
||||
}
|
||||
|
||||
if (statusCode === 401) {
|
||||
throw new Error('Authorization token is invalid');
|
||||
}
|
||||
|
||||
if (statusCode !== 200) {
|
||||
throw new Error('Unexpected error occurred!');
|
||||
}
|
||||
|
||||
const listData = await pnslClient(`BotLists/${listID}`);
|
||||
|
||||
const listMeta = JSON.parse(listMetaBody);
|
||||
return {listMeta, listData};
|
||||
};
|
||||
|
||||
const runList = async (listData, listID, channel) => {
|
||||
const banArr = listData.split('\n');
|
||||
|
||||
if (banArr.length > Config.MaxChunkSize) {
|
||||
while (banArr.length > 0) {
|
||||
banChunks.push(banArr.splice(0, Config.MaxChunkSize));
|
||||
}
|
||||
|
||||
for (const [i, chunk] of banChunks.entries()) {
|
||||
const promises = [];
|
||||
|
||||
for (const entry of chunk) {
|
||||
if (entry === '') continue;
|
||||
[, user, ...reason] = entry.split(' ');
|
||||
promises.push(getConnection().ban(channel, user, reason.join(' ')));
|
||||
}
|
||||
|
||||
await Promise.allSettled(promises);
|
||||
|
||||
banChunks.shift();
|
||||
|
||||
if (banChunks.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
clients[0].say(Config.Username, `Chunk ${Number(i) + 1} of ${listID} executed successfully on channel ${channel}`);
|
||||
await sleep(Config.DelayPerChunk);
|
||||
}
|
||||
} else {
|
||||
const promises = [];
|
||||
|
||||
for (const entry of banArr) {
|
||||
if (entry === '') continue;
|
||||
[, user, ...reason] = entry.split(' ');
|
||||
promises.push(getConnection().ban(channel, user, reason.join(' ')));
|
||||
}
|
||||
|
||||
await Promise.allSettled(promises);
|
||||
}
|
||||
};
|
||||
|
||||
const sleep = (ms) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
};
|
||||
|
@ -28,70 +96,100 @@ const createTwitchClient = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const sendPong = () => {
|
||||
for (const [i, client] of Object.entries(clients)) {
|
||||
client.say(Config.Username, `Pong from client ${Number(i) + 1}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getConnection = () => {
|
||||
return clients[++lastIndex % clients.length];
|
||||
const readyClients = clients.filter((i) => i.ready);
|
||||
return readyClients[++lastIndex % readyClients.length];
|
||||
};
|
||||
|
||||
(() => {
|
||||
[...Array(Config.MaxConnections)].map((_, i) => {
|
||||
const pnslWebSocket = new WS('wss://bot.tetyys.com/api/wss', [], {headers: {Authorization: `Bearer ${Config.PNSLToken}`}});
|
||||
|
||||
pnslWebSocket.on('open', () => {
|
||||
console.log(`${chalk.green('[P&SL]')} || Connected to P&SL Websocket server`);
|
||||
});
|
||||
|
||||
pnslWebSocket.on('message', async (data) => {
|
||||
const {o: type, p: payload} = JSON.parse(data);
|
||||
switch (type) {
|
||||
case 0: {
|
||||
const {listMeta} = await fetchList(payload.LatestBotList);
|
||||
console.log(`${chalk.green('[P&SL]')} || Latest Botlist: ${payload.LatestBotList} [${listMeta.name}] (${listMeta.count})`);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
console.log(`${chalk.green('[P&SL]')} || New Botlist: ${payload.Guid} [${payload.Name}] (${payload.Count}) (${payload.Tags.join(' ')})`);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
console.log(`${chalk.green('[P&SL]')} || New False Positive: ${payload.UserTwitchId} [${payload.BotListGuid}]`);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
(async () => {
|
||||
await Promise.all([...Array(Config.MaxConnections)].map(async (_, i) => {
|
||||
clients[i] = createTwitchClient();
|
||||
clients[i].connect();
|
||||
clients[i].on('ready', async () => {
|
||||
console.log(`${chalk.green('[CONNECTED]')} || Client ${Number(i) + 1} Connected to twitch.`);
|
||||
await clients[i].join(Config.Username);
|
||||
});
|
||||
clients[i].on('error', (error) => {
|
||||
if (error instanceof SayError) return;
|
||||
if (error instanceof ConnectionError) {
|
||||
if (clients[i].ready) {
|
||||
return;
|
||||
}
|
||||
clients[i].connect();
|
||||
return console.error(`Error in client ${i} -> ${error.name} || ${error.message}`);
|
||||
}
|
||||
console.error(error);
|
||||
});
|
||||
return await new Promise((resolve) => clients[i].on('ready', () => resolve()));
|
||||
}));
|
||||
|
||||
clients[0].on('PRIVMSG', async (msg) => {
|
||||
if (msg.messageText === '=mbping' && msg.senderUserID === Config.AdminID) {
|
||||
sendPong();
|
||||
} else if (msg.messageText.startsWith('=mbrun') && msg.senderUserID === Config.AdminID) {
|
||||
const listID = msg.messageText.split(' ')[1];
|
||||
const channel = msg.messageText.split(' ')[2];
|
||||
if (!uuidRegex.test(listID)) {
|
||||
return clients[0].say(msg.channelName, 'Invalid List ID!');
|
||||
}
|
||||
const {body, statusCode} = await pnslClient(`BotLists/${listID}`);
|
||||
console.log(`${chalk.green('[TWITCH]')} || ${clients.filter((i) => i.ready).length} Clients connected`);
|
||||
|
||||
if (statusCode === 404) {
|
||||
return clients[0].say(msg.channelName, 'List was not found.');
|
||||
clients[0].on('PRIVMSG', async ({messageText, senderUserID, channelName}) => {
|
||||
if (!Config.Users.includes(senderUserID)) return;
|
||||
|
||||
const message = messageText.replace(msgRegex, '').trimRight();
|
||||
if (!message.startsWith(Config.Prefix)) return;
|
||||
const content = message.split(/\s+/g);
|
||||
const command = content[0].slice(Config.Prefix.length);
|
||||
const args = content.slice(1);
|
||||
|
||||
if (command === 'ping') {
|
||||
const channel = args[0];
|
||||
return clients[0].say(channel || channelName, `${clients.filter((i) => i.ready).length} Clients from total of ${clients.length} are operational`);
|
||||
}
|
||||
|
||||
if (statusCode === 401) {
|
||||
return clients[0].say(msg.channelName, 'Authorization token is invalid');
|
||||
}
|
||||
if (command === 'runlist') {
|
||||
const listID = args[0];
|
||||
const channel = args[1];
|
||||
|
||||
if (statusCode !== 200) {
|
||||
return clients[0].say(msg.channelName, 'Unexpected error occurred.');
|
||||
}
|
||||
if (!listID) return clients[0].say(Config.Username, 'No list ID provided!');
|
||||
|
||||
const banArr = body.split('\n');
|
||||
|
||||
if (banArr.length > Config.MaxChunkSize) {
|
||||
while (banArr.length > 0) {
|
||||
banChunks.push(banArr.splice(0, Config.MaxChunkSize));
|
||||
try {
|
||||
if (channel) {
|
||||
const mods = await clients[0].getMods(channel);
|
||||
if (!mods.includes(Config.Username)) return clients[0].say(Config.Username, `I am not a moderator in channel ${channel}!`);
|
||||
}
|
||||
|
||||
for (const chunk of banChunks) {
|
||||
for (const entry of chunk) {
|
||||
getConnection().privmsg(channel || msg.channelName, entry);
|
||||
}
|
||||
await sleep(Config.DelayPerChunk);
|
||||
}
|
||||
clients[0].say(msg.channelName, `List ${listID} ran successfully on channel ${channel || msg.channelName}`);
|
||||
banChunks = [];
|
||||
} else {
|
||||
for (const entry of banArr) {
|
||||
getConnection().privmsg(channel || msg.channelName, entry);
|
||||
}
|
||||
clients[0].say(msg.channelName, `List ${listID} ran successfully on channel ${channel || msg.channelName}`);
|
||||
const data = await fetchList(listID);
|
||||
await runList(data.listData, listID, channel || channelName);
|
||||
clients[0].say(Config.Username, `List ${listID} executed successfully on channel ${channel}`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return clients[0].say(Config.Username, `Error Occurred! ${error.message}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
for (const client of clients) {
|
||||
client.ping();
|
||||
}
|
||||
}, pingInterval);
|
||||
})();
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0",
|
||||
"dank-twitch-irc": "^4.2.0",
|
||||
"got": "^11.8.1"
|
||||
"dank-twitch-irc": "^4.3.0",
|
||||
"got": "^11.8.1",
|
||||
"ws": "^7.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yarnpkg/pnpify": "^2.4.0",
|
||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -667,9 +667,9 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dank-twitch-irc@npm:^4.2.0":
|
||||
version: 4.2.0
|
||||
resolution: "dank-twitch-irc@npm:4.2.0"
|
||||
"dank-twitch-irc@npm:^4.3.0":
|
||||
version: 4.3.0
|
||||
resolution: "dank-twitch-irc@npm:4.3.0"
|
||||
dependencies:
|
||||
"@types/debug": ^4.1.5
|
||||
"@types/duplexify": ^3.6.0
|
||||
|
@ -679,13 +679,13 @@ __metadata:
|
|||
lodash.camelcase: ^4.3.0
|
||||
lodash.pickby: ^4.6.0
|
||||
make-error-cause: ^2.3.0
|
||||
ms: ^2.1.2
|
||||
ms: ^2.1.3
|
||||
randomstring: ^1.1.5
|
||||
semaphore-async-await: ^1.5.1
|
||||
simple-websocket: ^9.0.0
|
||||
split2: ^3.2.1
|
||||
ts-toolbelt: ^8.0.3
|
||||
checksum: 2f8e2df4b52a10977fcab0241583f0c0619aabf6e1e5988d8f6e9e4feed397b866981b359aefae1f50d279e6c9a05d8a28316c9412c20b6bf0fd220a36667814
|
||||
checksum: b3310781c72ba2d2efc65adc8a4ead17c1736eb10859d67fdc2123bd1194c1a23f94c4c27f6aaa33929b1577320f6d07726288d18cf535f7933d2f5e3377d487
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -1475,10 +1475,11 @@ __metadata:
|
|||
dependencies:
|
||||
"@yarnpkg/pnpify": ^2.4.0
|
||||
chalk: ^4.1.0
|
||||
dank-twitch-irc: ^4.2.0
|
||||
dank-twitch-irc: ^4.3.0
|
||||
eslint: ^7.15.0
|
||||
eslint-config-google: ^0.14.0
|
||||
got: ^11.8.1
|
||||
ws: ^7.4.1
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
|
@ -1554,7 +1555,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ms@npm:^2.1.2":
|
||||
"ms@npm:^2.1.3":
|
||||
version: 2.1.3
|
||||
resolution: "ms@npm:2.1.3"
|
||||
checksum: 6e721e648a544154d5de4c114b32f573d8027ca8ec505cf6c1105e505986d6ac46934a1256735aa0eece8eb2f5b2a1230503b2dddd3b100f9f016fd8a4f15f33
|
||||
|
@ -2201,7 +2202,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ws@npm:^7.0.0":
|
||||
"ws@npm:^7.0.0, ws@npm:^7.4.1":
|
||||
version: 7.4.1
|
||||
resolution: "ws@npm:7.4.1"
|
||||
peerDependencies:
|
||||
|
|
Loading…
Reference in a new issue