UNPKG

clashofclans-events

Version:

A Simple JavaScript Clash Of Clan Event based library that tracks Donation, Player Join and Left, Clan Activities.

330 lines (291 loc) 9.92 kB
/* eslint-disable no-unused-vars */ /* eslint-disable no-restricted-syntax */ /* eslint-disable linebreak-style */ /* eslint-disable class-methods-use-this */ /* eslint-disable no-plusplus */ /* eslint-disable no-underscore-dangle */ /* eslint-disable no-await-in-loop */ const https = require('https'); const Events = require('events'); const { error } = require('../events/error'); const { playerJoin } = require('../events/PlayerEvent/playerJoin'); const { playerLeft } = require('../events/PlayerEvent/playerLeft'); const { donationEvent } = require('../events/DonationEvent/donationEvent'); const { playerPromote } = require('../events/PlayerEvent/playerPromote'); const { playerDemote } = require('../events/PlayerEvent/playerDemote'); const { badgeUrls, clanLevel, description, isWarLogPublic, location, requiredTrophies, type, warFrequency, warLeague, } = require('../events/ClanEvent/clanEvent'); global.COCEVENTS = new Events(); const clansData = new Map(); const Tags = []; const Role = ['member', 'admin', 'coLeader', 'leader']; /** * Trackers class * @param { Number } ratelimit * @param { String } tokens * @param { Number } sync * @param { Boolean } donationEvent * @param { Boolean } clanEvent * @param { Boolean } playerJoin * @param { Boolean } playerLeft * @param { Boolean } playerPromote * @param { Boolean } playerDemote */ class Trackers { constructor(ratelimit, tokens, sync, donationEvent, clanEvent, playerJoin, playerLeft, playerPromote, playerDemote) { this.ratelimit = ratelimit; this.tokens = tokens; this.sync = sync; this.donationEventStatus = donationEvent; this.clanEventStatus = clanEvent; this.playerJoinStatus = playerJoin; this.playerLeftStatus = playerLeft; this.playerPromoteStatus = playerPromote; this.playerDemoteStatus = playerDemote; this.upTime = new Date().toString(); } /** * @param { Number } ms */ async sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } /** * @param { String } tag */ _tag(tag) { return `${tag.toUpperCase().replace(/#/g, '').replace(/O/g, '0')}`; } /** * @param { String } path */ async _fetch(path) { const options = { hostname: 'api.clashofclans.com', path: path, method: 'GET', headers: { Authorization: `Bearer ${this.tokens[0]}`, 'Content-Type': 'application/json', }, timeout: 0, }; let raw = ''; return new Promise((resolve, reject) => { https.get(options, (req) => { req.on('data', (res) => { raw += res; }); req.on('end', () => { resolve({ statusCode: req.statusCode, statusMessage: req.statusMessage, ...JSON.parse(raw) }); }); req.on('error', (err) => { reject(err); }); }); }); } /** * @param {Array.<string>} tags */ async init(tags = []) { for (const tag of tags) { if (Tags.indexOf(this._tag(tag)) === -1) { clansData.set(this._tag(tag), undefined); Tags.push(this._tag(tag)); } } await this.reset(); } /** * Reset the timer. * @function reset() */ async reset() { const timerReset = new Date().getTime(); for (const tag of Tags) { await this.tracker(this._tag(tag)); } const newTimerReset = new Date().getTime(); await this.sleep(((this.sync * 1000) - (((newTimerReset - timerReset) > 0 && (newTimerReset - timerReset) < this.sync * 1000) ? (newTimerReset - timerReset) : (this.sync * 1000)))); await this.reset(); } /** * Add new clan to the tracker. * @param { String } tag */ async add(tag) { if (Tags.indexOf(this._tag(tag)) === -1) { clansData.set(this._tag(tag), undefined); Tags.push(this._tag(tag)); } } /** * Delete a clan tag from tracker. * @param { String } tag */ async delete(tag) { if (Tags.indexOf(this._tag(tag)) !== -1) { clansData.delete(this._tag(tag)); Tags.splice(Tags.indexOf(this._tag(tag)), 1); } } /** * @function stats reuturn details of settings */ stats(settings) { return { upTime: this.upTime, clans: Tags.length, ratelimit: settings.ratelimit, sync: settings.sync, events: { donationEvent: settings.donationEvent, clanEvent: settings.clanEvent, playerJoin: settings.playerJoin, playerLeft: settings.playerLeft, playerPromote: settings.playerPromote, playerDemote: settings.playerDemote } } } /** * Tracks all event activities of a clan. * @param { String } tag */ async tracker(tag) { try { const newData = await this._fetch(`/v1/clans/%23${this._tag(tag)}`); if (newData.statusCode !== 200) { let tempError = new Error(); tempError = { tag: this._tag(tag), statusCode: newData.statusCode, statusMessage: newData.statusMessage, }; throw tempError; } const oldData = clansData.get(this._tag(tag)); if (oldData) { // Donation Event if (this.donationEventStatus) { await donationEvent(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); } // Clan Events if (this.clanEventStatus) { await badgeUrls(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); await type(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); await isWarLogPublic(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); await description(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); await warFrequency(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); await warLeague(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); await requiredTrophies(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); await location(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); await clanLevel(COCEVENTS, oldData, newData, async (check) => { if (check) { await this.sleep(1000 / this.ratelimit); } }); } // Player Promote And Demote if (this.playerPromoteStatus || this.playerDemoteStatus) { let pd = oldData.memberList.filter((f) => newData.memberList.some((s) => (f.role !== s.role && f.tag === s.tag))); if (pd.length > 0) { pd = pd.map(async (j) => { const currentPlayer = newData.memberList.filter((m) => m.tag === j.tag)[0]; const previousPlayer = oldData.memberList.filter((m) => m.tag === j.tag)[0]; if (Role.indexOf(j.role) < Role.indexOf(newData.role)) { if (this.playerPromoteStatus) { playerPromote(COCEVENTS, oldData, newData, previousPlayer, currentPlayer); await this.sleep(1000 / this.ratelimit); } } else { // eslint-disable-next-line no-lonely-if if (this.playerDemoteStatus) { playerDemote(COCEVENTS, oldData, newData, previousPlayer, currentPlayer); await this.sleep(1000 / this.ratelimit); } } }); } } // Player Join and Left Event if (this.playerJoinStatus) { const join = newData.memberList.filter((f) => !oldData.memberList.some((d) => d.tag === f.tag)); if (join.length > 0) { for (const player of join) { await this.sleep(1000 / this.ratelimit); playerJoin(COCEVENTS, player, newData); } } } if (this.playerLeftStatus) { const left = oldData.memberList.filter((f) => !newData.memberList.some((d) => d.tag === f.tag)); if (left.length > 0) { for (const player of left) { await this.sleep(1000 / this.ratelimit); playerLeft(COCEVENTS, player, newData); } } } } clansData.set(this._tag(newData.tag), newData); await this.sleep(100); } catch (err) { if (err.statusCode === 503) { error(COCEVENTS, err); await this.sleep(1000 * 60 * 5); } else if (err.statusCode === 403) { error(COCEVENTS, err); await this.sleep(1000 * 60 * 10); } else if (err.statusCode === 429) { error(COCEVENTS, err); await this.sleep(1000); } else { error(COCEVENTS, err); await this.sleep(100); } } } } module.exports = Trackers;