worldstate-emitter 2.2.13 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +252 -60
- package/dist/index.d.mts +56 -0
- package/dist/index.mjs +14645 -0
- package/package.json +43 -18
- package/.babelrc.json +0 -4
- package/.commitlintrc.yml +0 -5
- package/.eslintignore +0 -5
- package/.eslintrc.yml +0 -9
- package/.husky/commit-msg +0 -1
- package/.husky/pre-commit +0 -1
- package/.lintstagedrc.yml +0 -9
- package/.mocharc.yml +0 -3
- package/.nvmrc +0 -1
- package/.nycrc.yml +0 -4
- package/.prettierrc +0 -1
- package/.releaserc.yml +0 -1
- package/SECURITY.md +0 -17
- package/handlers/RSS.js +0 -66
- package/handlers/Twitter.js +0 -169
- package/handlers/Worldstate.js +0 -154
- package/handlers/events/arrayLike.js +0 -27
- package/handlers/events/checkOverrides.js +0 -17
- package/handlers/events/cycleLike.js +0 -38
- package/handlers/events/eKeyOverrides.js +0 -40
- package/handlers/events/kuva.js +0 -31
- package/handlers/events/nightwave.js +0 -35
- package/handlers/events/objectLike.js +0 -17
- package/handlers/events/parse.js +0 -82
- package/index.js +0 -96
- package/nodemon.json +0 -9
- package/resources/config.js +0 -8
- package/resources/rssFeeds.json +0 -129
- package/resources/tweeters.json +0 -17
- package/utilities/Cache.js +0 -69
- package/utilities/WSCache.js +0 -96
- package/utilities/env.js +0 -10
- package/utilities/index.js +0 -79
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { logger } from '../../utilities/index.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* External mission data retrieved from https://10o.io/kuvalog.json
|
|
5
|
-
* @typedef {Object} ExternalMission
|
|
6
|
-
* @property {Date} activation start time
|
|
7
|
-
* @property {Date} expiry end timer
|
|
8
|
-
* @property {string} node formatted node name with planet
|
|
9
|
-
* @property {string} enemy Enemy on tile
|
|
10
|
-
* @property {string} type Mission type of node
|
|
11
|
-
* @property {boolean} archwing whether or not the tile requires archwing
|
|
12
|
-
* @property {boolean} sharkwing whether or not the tile requires
|
|
13
|
-
* sumbersible archwing
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
export const fissures = (fissure) => `fissures.t${fissure.tierNum}.${(fissure.missionType || '').toLowerCase()}`;
|
|
17
|
-
export const enemies = (acolyte) => ({
|
|
18
|
-
eventKey: `enemies${acolyte.isDiscovered ? '' : '.departed'}`,
|
|
19
|
-
activation: acolyte.lastDiscoveredAt,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Parse an arbitration for its key
|
|
24
|
-
* @param {ExternalMission} arbi arbitration data to parse
|
|
25
|
-
* @returns {string}
|
|
26
|
-
*/
|
|
27
|
-
export const arbitration = (arbi) => {
|
|
28
|
-
if (!arbi?.enemy) return '';
|
|
29
|
-
|
|
30
|
-
let k;
|
|
31
|
-
try {
|
|
32
|
-
k = `arbitration.${arbi.enemy.toLowerCase()}.${arbi.type.replace(/\s/g, '').toLowerCase()}`;
|
|
33
|
-
} catch (e) {
|
|
34
|
-
logger.error(`Unable to parse arbitraion: ${JSON.stringify(arbi)}\n${e}`);
|
|
35
|
-
}
|
|
36
|
-
return k;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const events = 'operations';
|
|
40
|
-
export const persistentEnemies = 'enemies';
|
package/handlers/events/kuva.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { logger, groupBy } from '../../utilities/index.js';
|
|
2
|
-
|
|
3
|
-
import objectLike from './objectLike.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Process kuva fields
|
|
7
|
-
* @param {Deps} deps dependencies for processing
|
|
8
|
-
* @param {Object[]} packets packets to emit
|
|
9
|
-
* @returns {Object|Object[]} object(s) to emit from kuva stuff
|
|
10
|
-
*/
|
|
11
|
-
export default (deps, packets) => {
|
|
12
|
-
if (!deps.data) {
|
|
13
|
-
logger.error('no kuva data');
|
|
14
|
-
return undefined;
|
|
15
|
-
}
|
|
16
|
-
const data = groupBy(deps.data, 'type');
|
|
17
|
-
Object.keys(data).forEach((type) => {
|
|
18
|
-
deps = {
|
|
19
|
-
...deps,
|
|
20
|
-
data: data[type],
|
|
21
|
-
id: `kuva.${data[type][0].type.replace(/\s/g, '').toLowerCase()}`,
|
|
22
|
-
activation: data[type][0].activation,
|
|
23
|
-
expiry: data[type][0].expiry,
|
|
24
|
-
};
|
|
25
|
-
const p = objectLike(deps.data, deps);
|
|
26
|
-
if (p) {
|
|
27
|
-
packets.push(p);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
return packets.filter((p) => p);
|
|
31
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import objectLike from './objectLike.js';
|
|
2
|
-
|
|
3
|
-
export default (nightwave, deps) => {
|
|
4
|
-
const groups = {
|
|
5
|
-
daily: [],
|
|
6
|
-
weekly: [],
|
|
7
|
-
elite: [],
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
(nightwave.activeChallenges || []).forEach((challenge) => {
|
|
11
|
-
if (challenge.isDaily) {
|
|
12
|
-
groups.daily.push(challenge);
|
|
13
|
-
} else if (challenge.isElite) {
|
|
14
|
-
groups.elite.push(challenge);
|
|
15
|
-
} else {
|
|
16
|
-
groups.weekly.push(challenge);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const packets = [];
|
|
21
|
-
Object.keys(groups).forEach((group) => {
|
|
22
|
-
const p = objectLike(
|
|
23
|
-
{
|
|
24
|
-
...nightwave,
|
|
25
|
-
activeChallenges: groups[group],
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
...deps,
|
|
29
|
-
id: `nightwave.${group}`,
|
|
30
|
-
}
|
|
31
|
-
);
|
|
32
|
-
packets.push(p);
|
|
33
|
-
});
|
|
34
|
-
return packets;
|
|
35
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { between, lastUpdated } from '../../utilities/index.js';
|
|
2
|
-
|
|
3
|
-
export default (data, deps) => {
|
|
4
|
-
if (!data) return undefined;
|
|
5
|
-
const last = new Date(lastUpdated[deps.platform][deps.language]);
|
|
6
|
-
const activation = new Date(data.activation);
|
|
7
|
-
const start = new Date(deps.cycleStart);
|
|
8
|
-
if (between(last, activation, start)) {
|
|
9
|
-
const p = {
|
|
10
|
-
...deps,
|
|
11
|
-
data,
|
|
12
|
-
id: deps.id || deps.key,
|
|
13
|
-
};
|
|
14
|
-
return p;
|
|
15
|
-
}
|
|
16
|
-
return undefined;
|
|
17
|
-
};
|
package/handlers/events/parse.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { lastUpdated } from '../../utilities/index.js';
|
|
2
|
-
|
|
3
|
-
import checkOverrides from './checkOverrides.js';
|
|
4
|
-
import kuvaProcessing from './kuva.js';
|
|
5
|
-
import arrayLike from './arrayLike.js';
|
|
6
|
-
import objectLike from './objectLike.js';
|
|
7
|
-
import nightwave from './nightwave.js';
|
|
8
|
-
import cycleLike from './cycleLike.js';
|
|
9
|
-
import * as eKeyOverrides from './eKeyOverrides.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {Object} Deps
|
|
13
|
-
* @property {string} key event key being parsed
|
|
14
|
-
* @property {string} platform platform the event is on
|
|
15
|
-
* @property {string} language language the event is in
|
|
16
|
-
* @property {Date} cycleStart start of the current cycle
|
|
17
|
-
* @property {Object|Array} data data to parse
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Set up current cycle start if it's not been initiated
|
|
22
|
-
* @param {Deps} deps dependencies for processing
|
|
23
|
-
*/
|
|
24
|
-
const initCycleStart = (deps) => {
|
|
25
|
-
if (!lastUpdated[deps.platform][deps.language]) {
|
|
26
|
-
lastUpdated[deps.platform][deps.language] = deps.cycleStart;
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Parse new events from the provided worldstate
|
|
32
|
-
* @param {Deps} deps dependencies to parse out events
|
|
33
|
-
* @returns {Packet|Packet[]} packet(s) to emit
|
|
34
|
-
*/
|
|
35
|
-
export default (deps) => {
|
|
36
|
-
initCycleStart(deps);
|
|
37
|
-
|
|
38
|
-
// anything in the eKeyOverrides goes first, then anything uniform
|
|
39
|
-
const packets = [];
|
|
40
|
-
switch (deps.key) {
|
|
41
|
-
case 'kuva':
|
|
42
|
-
return kuvaProcessing(deps, packets);
|
|
43
|
-
case 'events':
|
|
44
|
-
deps = {
|
|
45
|
-
...deps,
|
|
46
|
-
id: eKeyOverrides[deps.key],
|
|
47
|
-
};
|
|
48
|
-
case 'alerts':
|
|
49
|
-
case 'conclaveChallenges':
|
|
50
|
-
case 'dailyDeals':
|
|
51
|
-
case 'flashSales':
|
|
52
|
-
case 'fissures':
|
|
53
|
-
case 'globalUpgrades':
|
|
54
|
-
case 'invasions':
|
|
55
|
-
case 'syndicateMissions':
|
|
56
|
-
case 'weeklyChallenges':
|
|
57
|
-
packets.push(...arrayLike(deps, packets));
|
|
58
|
-
break;
|
|
59
|
-
case 'cetusCycle':
|
|
60
|
-
case 'earthCycle':
|
|
61
|
-
case 'vallisCycle':
|
|
62
|
-
packets.push(cycleLike(deps.data, deps));
|
|
63
|
-
break;
|
|
64
|
-
case 'persistentEnemies':
|
|
65
|
-
deps = {
|
|
66
|
-
...deps,
|
|
67
|
-
...checkOverrides(deps.key, deps.data),
|
|
68
|
-
};
|
|
69
|
-
case 'sortie':
|
|
70
|
-
case 'voidTrader':
|
|
71
|
-
case 'arbitration':
|
|
72
|
-
case 'sentientOutposts':
|
|
73
|
-
deps.id = checkOverrides(deps.key, deps.data);
|
|
74
|
-
packets.push(objectLike(deps.data, deps));
|
|
75
|
-
case 'nightwave':
|
|
76
|
-
packets.push(nightwave(deps.data, deps));
|
|
77
|
-
default:
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return packets;
|
|
82
|
-
};
|
package/index.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import EventEmitter from 'node:events';
|
|
2
|
-
|
|
3
|
-
import RSS from './handlers/RSS.js';
|
|
4
|
-
import Worldstate from './handlers/Worldstate.js';
|
|
5
|
-
import Twitter from './handlers/Twitter.js';
|
|
6
|
-
import { logger } from './utilities/index.js';
|
|
7
|
-
import { FEATURES } from './resources/config.js';
|
|
8
|
-
|
|
9
|
-
export default class WorldstateEmitter extends EventEmitter {
|
|
10
|
-
#locale;
|
|
11
|
-
#worldstate;
|
|
12
|
-
#twitter;
|
|
13
|
-
#rss;
|
|
14
|
-
|
|
15
|
-
static async make({ locale, features } = { locale: undefined, features: [] }) {
|
|
16
|
-
const emitter = new WorldstateEmitter({ locale });
|
|
17
|
-
await emitter.#init(features?.length ? features : FEATURES);
|
|
18
|
-
return emitter;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Pull in and instantiate emitters
|
|
23
|
-
* @param {string} locale language to restrict events to
|
|
24
|
-
*/
|
|
25
|
-
constructor({ locale } = { locale: undefined }) {
|
|
26
|
-
super();
|
|
27
|
-
this.#locale = locale;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async #init(/** @type {string[]} */ features) {
|
|
31
|
-
if (features.includes('rss')) {
|
|
32
|
-
this.#rss = new RSS(this);
|
|
33
|
-
}
|
|
34
|
-
if (features.includes('worldstate')) {
|
|
35
|
-
this.#worldstate = new Worldstate(this, this.#locale);
|
|
36
|
-
await this.#worldstate.init();
|
|
37
|
-
}
|
|
38
|
-
if (features.includes('twitter')) {
|
|
39
|
-
this.#twitter = new Twitter(this);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
logger.silly('hey look, i started up...');
|
|
43
|
-
this.setupLogging();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Set up internal logging
|
|
48
|
-
* @private
|
|
49
|
-
*/
|
|
50
|
-
setupLogging() {
|
|
51
|
-
this.on('error', logger.error);
|
|
52
|
-
|
|
53
|
-
this.on('rss', (body) => logger.silly(`emitted: ${body.id}`));
|
|
54
|
-
this.on('ws:update:raw', (body) => logger.silly(`emitted raw: ${body.platform}`));
|
|
55
|
-
this.on('ws:update:parsed', (body) => logger.silly(`emitted parsed: ${body.platform} in ${body.language}`));
|
|
56
|
-
this.on('ws:update:event', (body) =>
|
|
57
|
-
logger.silly(`emitted event: ${body.id} ${body.platform} in ${body.language}`)
|
|
58
|
-
);
|
|
59
|
-
this.on('tweet', (body) => logger.silly(`emitted: ${body.id}`));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Get current rss feed items
|
|
64
|
-
* @returns {Object} [description]
|
|
65
|
-
*/
|
|
66
|
-
getRss() {
|
|
67
|
-
if (!this.#rss) return undefined;
|
|
68
|
-
return this.#rss.feeder.list.map((i) => ({ url: i.url, items: i.items }));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get a specific worldstate, defaulting to 'pc' for the platform and 'en' for the language
|
|
73
|
-
* @param {string} [language='en'] locale/languate to fetch
|
|
74
|
-
* @returns {Object} Requested worldstate
|
|
75
|
-
*/
|
|
76
|
-
getWorldstate(language = 'en') {
|
|
77
|
-
if (!this.#worldstate) return undefined;
|
|
78
|
-
return this.#worldstate?.get(language);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
get debug() {
|
|
82
|
-
return {
|
|
83
|
-
rss: FEATURES.includes('rss') ? this.getRss() : undefined,
|
|
84
|
-
worldstate: FEATURES.includes('worldstate') ? this.#worldstate?.get() : undefined,
|
|
85
|
-
twitter: this.#twitter?.clientInfoValid ? this.#twitter.getData() : undefined,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get Twitter data
|
|
91
|
-
* @returns {Promise} promised twitter data
|
|
92
|
-
*/
|
|
93
|
-
async getTwitter() {
|
|
94
|
-
return this.#twitter?.clientInfoValid ? this.twitter.getData() : undefined;
|
|
95
|
-
}
|
|
96
|
-
}
|
package/nodemon.json
DELETED
package/resources/config.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export const worldstateUrl = process.env.WORLDSTATE_URL ?? 'https://api.warframe.com/cdn/worldState.php';
|
|
2
|
-
export const kuvaUrl = process.env.KUVA_URL ?? 'https://10o.io/arbitrations.json';
|
|
3
|
-
export const sentientUrl = process.env.SENTIENT_URL ?? 'https://semlar.com/anomaly.json';
|
|
4
|
-
|
|
5
|
-
export const worldstateCron = process.env.WORLDSTATE_CRON ?? '25 */5 * * * *';
|
|
6
|
-
export const externalCron = process.env.WS_EXTERNAL_CRON ?? '0 */10 * * * *';
|
|
7
|
-
|
|
8
|
-
export const FEATURES = process.env.WS_EMITTER_FEATURES ? process.env.WS_EMITTER_FEATURES.split(',') : [];
|
package/resources/rssFeeds.json
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"url": "https://forums.warframe.com/forum/38-players-helping-players.xml",
|
|
4
|
-
"key": "players_helping_players",
|
|
5
|
-
"defaultAttach": "https://i.imgur.com/cuk4ro9.png"
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"url": "https://forums.warframe.com/forum/3-pc-update-notes.xml",
|
|
9
|
-
"key": "forum.updates.pc",
|
|
10
|
-
"defaultAttach": "https://i.imgur.com/eY1NkzO.png"
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"url": "https://forums.warframe.com/forum/170-announcements-events.xml",
|
|
14
|
-
"key": "forum.news",
|
|
15
|
-
"defaultAttach": "https://i.imgur.com/CNrsc7V.png"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"url": "https://forums.warframe.com/forum/123-developer-workshop-update-notes.xml",
|
|
19
|
-
"key": "forum.workshop"
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
"url": "https://forums.warframe.com/discover/837.xml",
|
|
23
|
-
"key": "forum.staff.megan",
|
|
24
|
-
"author": {
|
|
25
|
-
"name": "[DE]Megan",
|
|
26
|
-
"url": "https://forums.warframe.com/profile/384139-demegan/",
|
|
27
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2017_06/ezgif.com-crop.thumb.gif.e510920610e8489a54dd5dbe8b9fd4db.gif"
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"url": "https://forums.warframe.com/discover/839.xml",
|
|
32
|
-
"key": "forum.staff.rebecca",
|
|
33
|
-
"author": {
|
|
34
|
-
"name": "[DE]Rebecca",
|
|
35
|
-
"url": "https://forums.warframe.com/profile/4-derebecca/",
|
|
36
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/pages_media/1_PlayerAvatarsInkary.png"
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
"url": "https://forums.warframe.com/discover/840.xml",
|
|
41
|
-
"key": "forum.staff.danielle",
|
|
42
|
-
"author": {
|
|
43
|
-
"name": "[DE]Danielle",
|
|
44
|
-
"url": "https://forums.warframe.com/profile/869879-dedanielle/",
|
|
45
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2018_04/profile.thumb.jpg.fe072e16d5b54892b95030ea410264e7.jpg"
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"url": "https://forums.warframe.com/discover/841.xml",
|
|
50
|
-
"key": "forum.staff.drew",
|
|
51
|
-
"author": {
|
|
52
|
-
"name": "[DE]Drew",
|
|
53
|
-
"url": "https://forums.warframe.com/profile/488958-dedrew/",
|
|
54
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2016_06/576c323f14e92_AnimatedAvatarMirrored.thumb.gif.f12f2373d0d4b91363647f35b30026e0.gif"
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"url": "https://forums.warframe.com/discover/842.xml",
|
|
59
|
-
"key": "forum.staff.glen",
|
|
60
|
-
"author": {
|
|
61
|
-
"name": "[DE]Glen",
|
|
62
|
-
"url": "https://forums.warframe.com/profile/10-deglen/",
|
|
63
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2016_05/57474a4312a72_GlensHorse.thumb.png.7b47cb0660f5af2e6101ed84d3192c03.png"
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"url": "https://forums.warframe.com/discover/1171.xml",
|
|
68
|
-
"key": "forum.staff.taylor",
|
|
69
|
-
"author": {
|
|
70
|
-
"name": "[DE]taylor",
|
|
71
|
-
"url": "https://forums.warframe.com/profile/1943322-detaylor/",
|
|
72
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2017_07/596ceb9b4e182_6FUC4s3%281%29.thumb.png.7045d25fc7b057c70ddcffe14cd1f43e.png"
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"url": "https://forums.warframe.com/discover/1777.xml",
|
|
77
|
-
"key": "forum.staff.steve",
|
|
78
|
-
"author": {
|
|
79
|
-
"name": "[DE]Steve",
|
|
80
|
-
"url": "https://forums.warframe.com/profile/24-desteve/",
|
|
81
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2016_06/575f13eaf3080_Pastedimageat2016_06_1304_11PM.thumb.png.fb98af24931a1820d00293a55c05baef.png"
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"url": "https://forums.warframe.com/discover/1291.xml",
|
|
86
|
-
"key": "forum.staff.helen",
|
|
87
|
-
"author": {
|
|
88
|
-
"name": "[DE]Helen",
|
|
89
|
-
"url": "https://forums.warframe.com/profile/2522846-dehelen/",
|
|
90
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2017_06/590e937e598f2_Helen-Icon.jpg.0ac6d3d86c1d48f3f3e1a035344ab87a.thumb.jpg.d2225fb0dcd980f081ddddbf46458072.jpg"
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"url": "https://forums.warframe.com/discover/1294.xml",
|
|
95
|
-
"key": "forum.staff.saske",
|
|
96
|
-
"author": {
|
|
97
|
-
"name": "[DE]Saske",
|
|
98
|
-
"url": "https://forums.warframe.com/profile/4513168-nswdesaske/",
|
|
99
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/pages_media/1_TennoCon2018Glyph.png"
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"url": "https://forums.warframe.com/discover/1295.xml",
|
|
104
|
-
"key": "forum.staff.syncrasis",
|
|
105
|
-
"author": {
|
|
106
|
-
"name": "[DE]Syncrasis",
|
|
107
|
-
"url": "https://forums.warframe.com/profile/2514676-desyncrasis//",
|
|
108
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2017_02/aladv.thumb.jpg.a06cbfa091579eb9ce2ae96eb0b42e34.jpg"
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"url": "https://forums.warframe.com/discover/1299.xml",
|
|
113
|
-
"key": "forum.staff.pablo",
|
|
114
|
-
"author": {
|
|
115
|
-
"name": "[DE]Pablo",
|
|
116
|
-
"url": "https://forums.warframe.com/profile/217656-depablo/",
|
|
117
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2016_05/Pablo.thumb.png.35bb0384ef7b88e807d55ffc31af0896.png"
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
"url": "https://forums.warframe.com/discover/1779.xml",
|
|
122
|
-
"key": "forum.staff.marcus",
|
|
123
|
-
"author": {
|
|
124
|
-
"name": "[DE]Marcus",
|
|
125
|
-
"url": "https://forums.warframe.com/profile/3443485-demarcus/",
|
|
126
|
-
"icon_url": "https://content.invisioncic.com/Mwarframe/monthly_2018_01/5a55278d71caa_MarcusIIPrint.thumb.jpg.16cb689d778112333cffb6fe546b89ec.jpg"
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
]
|
package/resources/tweeters.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{ "acc_name": "@playwarframe", "plain": "warframe" },
|
|
3
|
-
{ "acc_name": "@digitalextremes", "plain": "digitalextremes" },
|
|
4
|
-
{ "acc_name": "@PabloMakes", "plain": "pablo" },
|
|
5
|
-
{ "acc_name": "@Cam_Rogers", "plain": "cameron" },
|
|
6
|
-
{ "acc_name": "@rebbford", "plain": "rebecca" },
|
|
7
|
-
{ "acc_name": "@sj_sinclair", "plain": "steve" },
|
|
8
|
-
{ "acc_name": "@soelloo", "plain": "danielle" },
|
|
9
|
-
{ "acc_name": "@moitoi", "plain": "megan" },
|
|
10
|
-
{ "acc_name": "@GameSoundDesign", "plain": "george" },
|
|
11
|
-
{ "acc_name": "@msinilo", "plain": "maciej" },
|
|
12
|
-
{ "acc_name": "@sheldoncarter", "plain": "sheldon" },
|
|
13
|
-
{ "acc_name": "@MarcusKretz", "plain": "marcus" },
|
|
14
|
-
{ "acc_name": "@Helen_Heikkila", "plain": "helen" },
|
|
15
|
-
{ "acc_name": "@tobitenno", "plain": "tobiah" },
|
|
16
|
-
{ "acc_name": "@wfdiscord", "plain": "wfdiscord" }
|
|
17
|
-
]
|
package/utilities/Cache.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:events';
|
|
2
|
-
|
|
3
|
-
import { CronJob } from 'cron';
|
|
4
|
-
|
|
5
|
-
import { logger } from './index.js';
|
|
6
|
-
|
|
7
|
-
export default class CronCache extends EventEmitter {
|
|
8
|
-
#url = undefined;
|
|
9
|
-
#pattern = '0 */10 * * * *'; // default: every 10 minutes
|
|
10
|
-
#job /** @type {CronJob} */ = undefined;
|
|
11
|
-
/** @type string */ #data = '';
|
|
12
|
-
#updating = undefined;
|
|
13
|
-
#logger = logger;
|
|
14
|
-
|
|
15
|
-
static async make(url, pattern) {
|
|
16
|
-
const cache = new CronCache(url, pattern);
|
|
17
|
-
await cache.#update();
|
|
18
|
-
return cache;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
constructor(/** @type string */ url, /** @type string */ pattern) {
|
|
22
|
-
super();
|
|
23
|
-
this.#url = url;
|
|
24
|
-
if (pattern) this.#pattern = pattern;
|
|
25
|
-
this.#job = new CronJob(this.#pattern, this.#update.bind(this), undefined, true);
|
|
26
|
-
this.#job.start();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async #update() {
|
|
30
|
-
this.#updating = this.#fetch();
|
|
31
|
-
this.#logger.debug(`update starting for ${this.#url}`);
|
|
32
|
-
let error;
|
|
33
|
-
try {
|
|
34
|
-
this.#data = await this.#updating;
|
|
35
|
-
return this.#updating;
|
|
36
|
-
} catch (e) {
|
|
37
|
-
this.#data = undefined;
|
|
38
|
-
error = e;
|
|
39
|
-
} finally {
|
|
40
|
-
if (this.#data) {
|
|
41
|
-
this.emit('update', this.#data);
|
|
42
|
-
this.#logger.debug(`update done for ${this.#url}`);
|
|
43
|
-
} else {
|
|
44
|
-
this.#logger.debug(`update failed for ${this.#url} : ${error}`);
|
|
45
|
-
}
|
|
46
|
-
this.#updating = undefined;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async #fetch() {
|
|
51
|
-
logger.silly(`fetching... ${this.#url}`);
|
|
52
|
-
const updated = await fetch(this.#url);
|
|
53
|
-
this.#data = await updated.text();
|
|
54
|
-
return this.#data;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async get() {
|
|
58
|
-
if (this.#updating) {
|
|
59
|
-
logger.silly('returning in-progress update promise');
|
|
60
|
-
return this.#updating;
|
|
61
|
-
}
|
|
62
|
-
if (!this.#data) {
|
|
63
|
-
logger.silly('returning new update promise');
|
|
64
|
-
return this.#update();
|
|
65
|
-
}
|
|
66
|
-
logger.silly('returning cached data');
|
|
67
|
-
return this.#data;
|
|
68
|
-
}
|
|
69
|
-
}
|
package/utilities/WSCache.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import WorldState from 'warframe-worldstate-parser';
|
|
2
|
-
|
|
3
|
-
import { logger } from './index.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Warframe WorldState Cache - store and retrieve current worldstate data
|
|
7
|
-
*/
|
|
8
|
-
export default class WSCache {
|
|
9
|
-
#inner;
|
|
10
|
-
#kuvaCache;
|
|
11
|
-
#sentientCache;
|
|
12
|
-
#logger = logger;
|
|
13
|
-
#emitter;
|
|
14
|
-
/** @type string */ #platform = 'pc';
|
|
15
|
-
/** @type string */ #language;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Set up a cache checking for data and updates to a specific worldstate set
|
|
19
|
-
* @param {string} language Language/translation to track
|
|
20
|
-
* @param {Cache} kuvaCache Cache of kuva data, provided by Semlar
|
|
21
|
-
* @param {Cache} sentientCache Cache of sentient outpost data, provided by Semlar
|
|
22
|
-
* @param {EventEmitter} eventEmitter Emitter to push new worldstate updates to
|
|
23
|
-
*/
|
|
24
|
-
constructor({ language, kuvaCache, sentientCache, eventEmitter }) {
|
|
25
|
-
this.#inner = undefined;
|
|
26
|
-
this.#kuvaCache = kuvaCache;
|
|
27
|
-
this.#sentientCache = sentientCache;
|
|
28
|
-
this.#language = language;
|
|
29
|
-
this.#emitter = eventEmitter;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Update the current data with new data
|
|
34
|
-
* @param {string} newData updated worldstate data
|
|
35
|
-
* @returns {Promise<void>}
|
|
36
|
-
*/
|
|
37
|
-
#update = async (newData) => {
|
|
38
|
-
const deps = {
|
|
39
|
-
locale: this.#language,
|
|
40
|
-
kuvaData: {},
|
|
41
|
-
sentientData: {},
|
|
42
|
-
};
|
|
43
|
-
try {
|
|
44
|
-
deps.kuvaData = JSON.parse(await this.#kuvaCache.get());
|
|
45
|
-
} catch (err) {
|
|
46
|
-
logger.debug(`Error parsing kuva data for ${this.#language}: ${err}`);
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
deps.sentientData = JSON.parse(await this.#sentientCache.get());
|
|
50
|
-
} catch (err) {
|
|
51
|
-
logger.warn(`Error parsing sentient data for ${this.#language}: ${err}`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let t;
|
|
55
|
-
try {
|
|
56
|
-
t = await WorldState.build(newData, deps);
|
|
57
|
-
if (!t.timestamp) return;
|
|
58
|
-
} catch (err) {
|
|
59
|
-
this.#logger.warn(`Error parsing worldstate data for ${this.#language}: ${err}`);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
this.#inner = t;
|
|
64
|
-
this.#emitter.emit('ws:update:parsed', {
|
|
65
|
-
language: this.#language,
|
|
66
|
-
platform: this.#platform,
|
|
67
|
-
data: t,
|
|
68
|
-
});
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get the latest worldstate data from this cache
|
|
73
|
-
* @returns {Object} Current worldstate data
|
|
74
|
-
*/
|
|
75
|
-
get data() {
|
|
76
|
-
return this.#inner;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Set the current data, aslso parses and emits data
|
|
81
|
-
* @param {string} newData New string data to parse
|
|
82
|
-
*/
|
|
83
|
-
set data(newData) {
|
|
84
|
-
logger.debug(`got new data for ${this.#language}, parsing...`);
|
|
85
|
-
this.#update(newData);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Set the current twitter data for the worldstate
|
|
90
|
-
* @param {Object} newTwitter twitter data
|
|
91
|
-
*/
|
|
92
|
-
set twitter(newTwitter) {
|
|
93
|
-
if (!(newTwitter && newTwitter.length)) return;
|
|
94
|
-
this.#inner.twitter = newTwitter;
|
|
95
|
-
}
|
|
96
|
-
}
|
package/utilities/env.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line import/prefer-default-export
|
|
2
|
-
export const LOG_LEVEL = process?.env?.LOG_LEVEL || 'error';
|
|
3
|
-
|
|
4
|
-
export const twiClientInfo = {
|
|
5
|
-
consumer_key: process?.env?.TWITTER_KEY,
|
|
6
|
-
consumer_secret: process?.env?.TWITTER_SECRET,
|
|
7
|
-
bearer_token: process?.env?.TWITTER_BEARER_TOKEN,
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const TWITTER_TIMEOUT = process?.env?.TWITTER_TIMEOUT || 60000;
|