dankgrinder 8.25.0 → 8.31.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 +53 -39
- package/package.json +1 -1
package/lib/grinder.js
CHANGED
|
@@ -88,14 +88,13 @@ async function sendWebhook(title, description, color = 0x5865f2) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// ── Terminal Colors & ANSI ───────────────────────────────────
|
|
91
|
-
// All colors stripped — plain text output only
|
|
92
91
|
const c = {
|
|
93
|
-
reset: '', bold: '', dim: '', italic: '',
|
|
94
|
-
green: '', red: '', yellow: '', cyan: '',
|
|
95
|
-
magenta: '', white: '', blue: '',
|
|
96
|
-
bgGreen: '', bgRed: '', bgYellow: '', bgCyan: '',
|
|
97
|
-
bgMagenta: '', bgBlue: '', bgWhite: '',
|
|
98
|
-
// Cursor control
|
|
92
|
+
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', italic: '\x1b[3m',
|
|
93
|
+
green: '\x1b[32m', red: '\x1b[31m', yellow: '\x1b[33m', cyan: '\x1b[36m',
|
|
94
|
+
magenta: '\x1b[35m', white: '\x1b[37m', blue: '\x1b[34m',
|
|
95
|
+
bgGreen: '\x1b[42m', bgRed: '\x1b[41m', bgYellow: '\x1b[43m', bgCyan: '\x1b[46m',
|
|
96
|
+
bgMagenta: '\x1b[45m', bgBlue: '\x1b[44m', bgWhite: '\x1b[47m',
|
|
97
|
+
// Cursor control
|
|
99
98
|
clearLine: '\x1b[2K',
|
|
100
99
|
cursorUp: (n) => `\x1b[${n}A`,
|
|
101
100
|
cursorTo: (col) => `\x1b[${col}G`,
|
|
@@ -230,17 +229,29 @@ async function filterClaimableAccounts(accounts) {
|
|
|
230
229
|
return claimable;
|
|
231
230
|
}
|
|
232
231
|
|
|
233
|
-
// ── Truecolor gradient helpers
|
|
234
|
-
function rgb(r, g, b) { return
|
|
235
|
-
function bgRgb(r, g, b) { return
|
|
232
|
+
// ── Truecolor gradient helpers ─────────────────────────────────
|
|
233
|
+
function rgb(r, g, b) { return `\x1b[38;2;${r};${g};${b}m`; }
|
|
234
|
+
function bgRgb(r, g, b) { return `\x1b[48;2;${r};${g};${b}m`; }
|
|
236
235
|
function lerp(a, b, t) { return Math.round(a + (b - a) * t); }
|
|
237
236
|
|
|
238
237
|
function gradientLine(text, from, to) {
|
|
239
|
-
|
|
238
|
+
// from/to are [r,g,b] arrays
|
|
239
|
+
const fr = Array.isArray(from) ? from[0] : 128;
|
|
240
|
+
const fg = Array.isArray(from) ? from[1] : 128;
|
|
241
|
+
const fb = Array.isArray(from) ? from[2] : 128;
|
|
242
|
+
const tr = Array.isArray(to) ? to[0] : 255;
|
|
243
|
+
const tg = Array.isArray(to) ? to[1] : 255;
|
|
244
|
+
const tb = Array.isArray(to) ? to[2] : 255;
|
|
245
|
+
let out = '';
|
|
246
|
+
for (let i = 0; i < text.length; i++) {
|
|
247
|
+
const t = text.length <= 1 ? 0 : i / (text.length - 1);
|
|
248
|
+
out += `\x1b[38;2;${lerp(fr, tr, t)};${lerp(fg, tg, t)};${lerp(fb, tb, t)}m${text[i]}`;
|
|
249
|
+
}
|
|
250
|
+
return out + c.reset;
|
|
240
251
|
}
|
|
241
252
|
|
|
242
253
|
function gradientText(text, from, to) {
|
|
243
|
-
return text;
|
|
254
|
+
return gradientLine(text, from, to);
|
|
244
255
|
}
|
|
245
256
|
|
|
246
257
|
function colorBanner() {
|
|
@@ -2931,64 +2942,67 @@ async function start(apiKey, apiUrl, opts = {}) {
|
|
|
2931
2942
|
} catch {}
|
|
2932
2943
|
}, 10_000);
|
|
2933
2944
|
|
|
2934
|
-
let
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2945
|
+
let shutdownInProgress = false;
|
|
2946
|
+
|
|
2947
|
+
async function gracefulShutdown(signal) {
|
|
2948
|
+
if (shutdownInProgress) return;
|
|
2949
|
+
shutdownInProgress = true;
|
|
2938
2950
|
shutdownCalled = true;
|
|
2939
2951
|
setDashboardActive(false);
|
|
2940
|
-
process.stdout.write(c.show);
|
|
2952
|
+
process.stdout.write(c.show + '\n');
|
|
2941
2953
|
|
|
2942
2954
|
console.log('');
|
|
2943
|
-
console.log(
|
|
2955
|
+
console.log(`${c.yellow}[${signal}] Shutting down...${c.reset}`);
|
|
2944
2956
|
|
|
2945
|
-
// Collect stats from all workers
|
|
2957
|
+
// Collect stats from all workers
|
|
2946
2958
|
let finalCoins = 0;
|
|
2947
2959
|
let finalCmds = 0;
|
|
2948
2960
|
for (const wk of workers) {
|
|
2949
2961
|
const rate = wk.stats.commands > 0 ? ((wk.stats.successes / wk.stats.commands) * 100).toFixed(0) : 0;
|
|
2950
|
-
console.log(` ${
|
|
2962
|
+
console.log(` ${c.dim}${wk.username || '?'}${c.reset} ${c.green}+⏣${wk.stats.coins.toLocaleString()}${c.reset} ${wk.stats.commands}cmds ${rate}%ok`);
|
|
2951
2963
|
finalCoins += wk.stats.coins || 0;
|
|
2952
2964
|
finalCmds += wk.stats.commands || 0;
|
|
2953
2965
|
}
|
|
2954
2966
|
|
|
2955
2967
|
const memFinal = Math.round((process.memoryUsage?.rss?.() ?? process.memoryUsage().rss) / 1048576);
|
|
2956
|
-
const avgEarn = globalEarningsEMA.get();
|
|
2957
2968
|
const cpm = globalCmdRate.getRate().toFixed(1);
|
|
2958
|
-
console.log(
|
|
2959
|
-
console.log('');
|
|
2969
|
+
console.log(`${c.bold}Total:${c.reset} +⏣${finalCoins.toLocaleString()} in ${formatUptime()} | ${finalCmds}cmds | ~${cpm}cmd/m | ${memFinal}MB`);
|
|
2960
2970
|
|
|
2961
|
-
//
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2971
|
+
// Stop workers — max 1s per worker so one hung client doesn't block shutdown
|
|
2972
|
+
await Promise.all(workers.map(wk => Promise.race([
|
|
2973
|
+
new Promise(resolve => { wk.stop(); resolve(true); }),
|
|
2974
|
+
new Promise(resolve => setTimeout(() => resolve(false), 1000)),
|
|
2975
|
+
])));
|
|
2966
2976
|
workerMap.clear();
|
|
2967
2977
|
|
|
2968
|
-
//
|
|
2978
|
+
// Release cluster claims
|
|
2979
|
+
await Promise.allSettled(workers.map(wk => releaseClaim(wk.account.id)));
|
|
2980
|
+
|
|
2981
|
+
// Remove heartbeat
|
|
2969
2982
|
if (redis && CLUSTER_ENABLED) {
|
|
2970
|
-
|
|
2983
|
+
await Promise.allSettled([redis.del(`${CLUSTER_PREFIX}node:${NODE_ID}`)]);
|
|
2971
2984
|
}
|
|
2972
2985
|
|
|
2973
2986
|
const totalRecoveries = workers.reduce((sum, wk) => sum + (wk._totalRecoveries || 0), 0);
|
|
2974
2987
|
const totalDisconnects = workers.reduce((sum, wk) => sum + (wk._disconnectCount || 0), 0);
|
|
2975
2988
|
const totalRateLimits = workers.reduce((sum, wk) => sum + (wk._rateLimitHits || 0), 0);
|
|
2976
2989
|
|
|
2990
|
+
if (totalRecoveries > 0 || totalDisconnects > 0) {
|
|
2991
|
+
console.log(` ${c.dim}${totalRecoveries} recoveries, ${totalDisconnects} disconnects, ${totalRateLimits} rate-limits${c.reset}`);
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2977
2994
|
const webhookMsg = `+⏣ ${finalCoins.toLocaleString()} | ${finalCmds} cmds | ${formatUptime()}` +
|
|
2978
2995
|
(totalRecoveries > 0 ? ` | ${totalRecoveries} auto-recoveries` : '') +
|
|
2979
2996
|
(CLUSTER_ENABLED ? ` | node: ${NODE_ID.substring(0, 12)}` : '');
|
|
2980
2997
|
sendWebhook('Session Ended', webhookMsg, 0x8b5cf6);
|
|
2981
2998
|
|
|
2982
|
-
if (
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
console.log(` ${c.dim}Cluster node: ${NODE_ID} — claims released${c.reset}`);
|
|
2987
|
-
}
|
|
2999
|
+
if (redis) { redis.disconnect().catch(() => {}); }
|
|
3000
|
+
console.log(`${c.green}Goodbye!${c.reset}\n`);
|
|
3001
|
+
process.exit(0);
|
|
3002
|
+
}
|
|
2988
3003
|
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
});
|
|
3004
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
3005
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
2992
3006
|
}
|
|
2993
3007
|
|
|
2994
3008
|
// ══════════════════════════════════════════════════════════════
|