dankgrinder 8.684.0 → 8.1171.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/lib/grinder.js +37 -39
- package/lib/rawLogger.js +45 -68
- package/package.json +1 -1
package/lib/grinder.js
CHANGED
|
@@ -3321,51 +3321,49 @@ async function start(apiKey, apiUrl, opts = {}) {
|
|
|
3321
3321
|
}
|
|
3322
3322
|
}
|
|
3323
3323
|
|
|
3324
|
-
// Init rawLogger
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
if (event.
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
}
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
ui.log(workers.indexOf(w), `⚠ ${event.lifesaversLeft} lifesavers left!`);
|
|
3355
|
-
}
|
|
3324
|
+
// Init rawLogger in-memory-only (Redis disabled to save $ on Railway)
|
|
3325
|
+
rawLogger.init(null, { silent: true });
|
|
3326
|
+
// Listen for DM events across all accounts — update worker state + dashboard LIVE
|
|
3327
|
+
rawLogger.onDmEvent((event, raw) => {
|
|
3328
|
+
const channelId = raw.channel_id;
|
|
3329
|
+
for (const w of workers) {
|
|
3330
|
+
const isThisWorker = w.client?.user?.dmChannel?.id === channelId;
|
|
3331
|
+
if (!isThisWorker && w.channel?.id !== channelId) continue;
|
|
3332
|
+
|
|
3333
|
+
if (event.type === 'death') {
|
|
3334
|
+
if (event.lifesaversLeft >= 0) {
|
|
3335
|
+
const prev = w._lifesavers;
|
|
3336
|
+
w._lifesavers = event.lifesaversLeft;
|
|
3337
|
+
if (event.lifesaversLeft === 0) {
|
|
3338
|
+
w.lastStatus = 'DEAD';
|
|
3339
|
+
w._alert = { type: 'death' };
|
|
3340
|
+
w.setCooldown?.('crime', 86400);
|
|
3341
|
+
w.setCooldown?.('search', 86400);
|
|
3342
|
+
sendWebhook?.('DEATH ALERT (DM)', `**${w.username}** died in DMs! **0 lifesavers!**\nCrime/search auto-disabled.`, 0xef4444);
|
|
3343
|
+
ui.log(workers.indexOf(w), `${c.red}E${c.reset} DEATH — 0 lifesavers! Crime/search disabled`);
|
|
3344
|
+
} else {
|
|
3345
|
+
w.log?.('warn', `DEATH in DMs — ${event.lifesaversLeft} lifesavers remaining`);
|
|
3346
|
+
if (prev !== event.lifesaversLeft) {
|
|
3347
|
+
w.setCooldown?.('crime', 60);
|
|
3348
|
+
w.setCooldown?.('search', 60);
|
|
3349
|
+
}
|
|
3350
|
+
if (event.lifesaversLeft <= 2) {
|
|
3351
|
+
w._alert = { type: 'lowls' };
|
|
3352
|
+
sendWebhook?.('LOW LIFESAVERS', `**${w.username}** has only **${event.lifesaversLeft}** lifesaver(s) left!`, 0xfbbf24);
|
|
3353
|
+
ui.log(workers.indexOf(w), `⚠ ${event.lifesaversLeft} lifesavers left!`);
|
|
3356
3354
|
}
|
|
3357
3355
|
}
|
|
3358
3356
|
}
|
|
3357
|
+
}
|
|
3359
3358
|
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
}
|
|
3359
|
+
if (event.type === 'levelup') {
|
|
3360
|
+
if (event.to > 0) {
|
|
3361
|
+
w._level = event.to;
|
|
3362
|
+
ui.log(workers.indexOf(w), `↑ level ${event.to}`);
|
|
3365
3363
|
}
|
|
3366
3364
|
}
|
|
3367
|
-
}
|
|
3368
|
-
}
|
|
3365
|
+
}
|
|
3366
|
+
});
|
|
3369
3367
|
|
|
3370
3368
|
// ── Phase 1: Login ─────────────────────────────────────────────
|
|
3371
3369
|
const parsedGapMin = Number.parseInt(String(process.env.LOGIN_GAP_MIN_MS || '50'), 10);
|
package/lib/rawLogger.js
CHANGED
|
@@ -1,27 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Raw Gateway Logger — intercepts ALL Dank Memer messages
|
|
3
|
-
* Captures: CV2 components, embeds, buttons, text, edits, ephemeral, cooldowns.
|
|
2
|
+
* Raw Gateway Logger — intercepts ALL Dank Memer messages (in-memory LRU cache).
|
|
4
3
|
*
|
|
5
|
-
* Redis
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* raw:ephemeral:log — list of all ephemeral messages, TTL 7d
|
|
11
|
-
* raw:all:log — list of ALL message IDs (global), TTL 7d, capped at 10000
|
|
4
|
+
* Redis is optional and disabled by default to save costs.
|
|
5
|
+
* Enable via: rawLogger.setRedisDisabled(false) after init, or pass opts.disabled: false.
|
|
6
|
+
*
|
|
7
|
+
* In-memory cache: last 256 messages per instance (LRU).
|
|
8
|
+
* Redis (if enabled): tiny 1h logs for command tracking.
|
|
12
9
|
*
|
|
13
10
|
* Usage:
|
|
14
11
|
* const rawLogger = require('./rawLogger');
|
|
15
|
-
* await rawLogger.init(
|
|
12
|
+
* await rawLogger.init(null); // memory-only (no Redis)
|
|
13
|
+
* rawLogger.setRedisDisabled(true); // explicit disable
|
|
16
14
|
* rawLogger.attachRawLogger(client);
|
|
17
|
-
* const msg = await rawLogger.getMsg('123456');
|
|
18
|
-
* const history = await rawLogger.getMsgHistory('123456');
|
|
19
|
-
* const recent = await rawLogger.getRecentForCommand('cointoss', 20);
|
|
20
15
|
*/
|
|
21
16
|
|
|
22
17
|
const LRU_SIZE = 256;
|
|
23
18
|
let redis = null;
|
|
24
19
|
let redisReady = false;
|
|
20
|
+
let redisDisabled = true; // Disabled by default — enable with setRedisDisabled(false)
|
|
25
21
|
|
|
26
22
|
// ── In-memory LRU (always available, even without Redis) ──
|
|
27
23
|
const memStore = new Map();
|
|
@@ -32,9 +28,23 @@ let _silent = false;
|
|
|
32
28
|
function _log(...args) { if (!_silent) console.log(...args); }
|
|
33
29
|
function _err(...args) { if (!_silent) console.error(...args); }
|
|
34
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Enable or disable Redis logging entirely.
|
|
33
|
+
* When disabled, rawLogger runs in memory-only mode (LRU cache, no Redis writes).
|
|
34
|
+
*/
|
|
35
|
+
function setRedisDisabled(disabled) {
|
|
36
|
+
redisDisabled = !!disabled;
|
|
37
|
+
_log(`[rawLogger] Redis logging ${redisDisabled ? 'DISABLED' : 'ENABLED'}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
// ── Redis init ──
|
|
36
41
|
async function init(redisUrl, opts = {}) {
|
|
37
42
|
if (opts.silent) _silent = true;
|
|
43
|
+
if (opts.disabled) {
|
|
44
|
+
redisDisabled = true;
|
|
45
|
+
_log('[rawLogger] Redis logging disabled via opts');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
38
48
|
if (!redisUrl) {
|
|
39
49
|
_log('[rawLogger] No Redis URL — raw logging disabled');
|
|
40
50
|
return;
|
|
@@ -427,63 +437,29 @@ async function store(d, event) {
|
|
|
427
437
|
memStore.set(d.id, parsed);
|
|
428
438
|
channelLast.set(d.channel_id, d.id);
|
|
429
439
|
|
|
430
|
-
// Redis (non-blocking, fire-and-forget)
|
|
431
|
-
if (redisReady
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
const MSG_TTL = 2592000; // 30 days
|
|
438
|
-
const LOG_TTL = 2592000; // 30 days
|
|
440
|
+
// Redis (non-blocking, fire-and-forget) — skip if disabled
|
|
441
|
+
if (redisDisabled || !redisReady || !redis || redis.status !== 'ready') {
|
|
442
|
+
return parsed;
|
|
443
|
+
}
|
|
444
|
+
try {
|
|
445
|
+
const LOG_TTL = 3600; // 1 hour
|
|
446
|
+
const MAX_LOG = 99; // tiny cap
|
|
439
447
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
pipe.
|
|
445
|
-
pipe.
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
453
|
-
// Per-account log
|
|
454
|
-
if (parsed.authorId) {
|
|
455
|
-
const accKey = `raw:channel:${d.channel_id}:log`;
|
|
456
|
-
pipe.lpush(accKey, `${d.id}:${parsed._capturedAt}:${event}:${parsed.command}`);
|
|
457
|
-
pipe.ltrim(accKey, 0, 4999);
|
|
458
|
-
pipe.expire(accKey, LOG_TTL);
|
|
459
|
-
}
|
|
460
|
-
// Track ephemeral in memory for quick access before they vanish
|
|
461
|
-
if (parsed.isEphemeral || (d.flags & 32832)) {
|
|
462
|
-
let chMap = ephemeralByChannel.get(d.channel_id);
|
|
463
|
-
if (!chMap) {
|
|
464
|
-
chMap = new Map();
|
|
465
|
-
ephemeralByChannel.set(d.channel_id, chMap);
|
|
466
|
-
}
|
|
467
|
-
chMap.set(d.id, parsed);
|
|
468
|
-
// Cap per-channel ephemeral buffer at 50
|
|
469
|
-
if (chMap.size > 50) {
|
|
470
|
-
const firstKey = chMap.keys().next().value;
|
|
471
|
-
chMap.delete(firstKey);
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
// Ephemeral log
|
|
475
|
-
if (parsed.isEphemeral || (d.flags & 32832)) {
|
|
476
|
-
pipe.lpush('raw:ephemeral:log', `${d.id}:${parsed._capturedAt}:${parsed.command}:${d.channel_id}`);
|
|
477
|
-
pipe.ltrim('raw:ephemeral:log', 0, 4999);
|
|
478
|
-
pipe.expire('raw:ephemeral:log', LOG_TTL);
|
|
479
|
-
}
|
|
480
|
-
// Global log
|
|
481
|
-
pipe.lpush('raw:all:log', `${d.id}:${parsed._capturedAt}:${event}:${parsed.command}:${d.channel_id}`);
|
|
482
|
-
pipe.ltrim('raw:all:log', 0, 49999);
|
|
483
|
-
pipe.expire('raw:all:log', LOG_TTL);
|
|
448
|
+
const pipe = redis.pipeline();
|
|
449
|
+
// Per-command log — only recent IDs, tiny cap, short TTL
|
|
450
|
+
if (parsed.command) {
|
|
451
|
+
const cmdKey = `raw:cmd:${parsed.command}:log`;
|
|
452
|
+
pipe.lpush(cmdKey, `${d.id}:${parsed._capturedAt}:${event}`);
|
|
453
|
+
pipe.ltrim(cmdKey, 0, MAX_LOG);
|
|
454
|
+
pipe.expire(cmdKey, LOG_TTL);
|
|
455
|
+
}
|
|
456
|
+
// Global log — tiny cap, short TTL
|
|
457
|
+
pipe.lpush('raw:all:log', `${d.id}:${parsed._capturedAt}:${event}:${parsed.command}:${d.channel_id}`);
|
|
458
|
+
pipe.ltrim('raw:all:log', 0, 499);
|
|
459
|
+
pipe.expire('raw:all:log', LOG_TTL);
|
|
484
460
|
|
|
485
|
-
|
|
486
|
-
|
|
461
|
+
pipe.exec().catch(() => {}); // fire and forget
|
|
462
|
+
} catch {}
|
|
487
463
|
}
|
|
488
464
|
|
|
489
465
|
return parsed;
|
|
@@ -768,6 +744,7 @@ async function getStats() {
|
|
|
768
744
|
|
|
769
745
|
module.exports = {
|
|
770
746
|
init,
|
|
747
|
+
setRedisDisabled,
|
|
771
748
|
attachRawLogger,
|
|
772
749
|
attachDmLogger,
|
|
773
750
|
onDmEvent,
|