dankgrinder 8.651.0 → 8.844.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 +36 -59
- 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,59 +437,25 @@ 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
|
-
pipe.set(key, json, 'EX', MSG_TTL);
|
|
443
|
-
// History (all versions)
|
|
444
|
-
pipe.rpush(histKey, json);
|
|
445
|
-
pipe.expire(histKey, MSG_TTL);
|
|
446
|
-
// Per-command log (including 'unknown' so we can track detection gaps)
|
|
448
|
+
const pipe = redis.pipeline();
|
|
449
|
+
// Per-command log — only recent IDs, tiny cap, short TTL
|
|
447
450
|
if (parsed.command) {
|
|
448
451
|
const cmdKey = `raw:cmd:${parsed.command}:log`;
|
|
449
452
|
pipe.lpush(cmdKey, `${d.id}:${parsed._capturedAt}:${event}`);
|
|
450
|
-
pipe.ltrim(cmdKey, 0,
|
|
453
|
+
pipe.ltrim(cmdKey, 0, MAX_LOG);
|
|
451
454
|
pipe.expire(cmdKey, LOG_TTL);
|
|
452
455
|
}
|
|
453
|
-
//
|
|
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
|
|
456
|
+
// Global log — tiny cap, short TTL
|
|
481
457
|
pipe.lpush('raw:all:log', `${d.id}:${parsed._capturedAt}:${event}:${parsed.command}:${d.channel_id}`);
|
|
482
|
-
pipe.ltrim('raw:all:log', 0,
|
|
458
|
+
pipe.ltrim('raw:all:log', 0, 499);
|
|
483
459
|
pipe.expire('raw:all:log', LOG_TTL);
|
|
484
460
|
|
|
485
461
|
pipe.exec().catch(() => {}); // fire and forget
|
|
@@ -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,
|