'use strict';
const net = require('node:net');
function sendMetaCommand(socket, line) {
return new Promise((resolve, reject) => {
let buf = Buffer.alloc(0);
const onData = (chunk) => {
buf = Buffer.concat([buf, chunk]);
const nl = buf.indexOf(0x0d);
if (nl === -1) return;
const header = buf.subarray(0, nl).toString('utf8');
const parts = header.split(' ');
const code = parts[0];
if (code === 'VA') {
const byteLen = Number(parts[1]);
const totalNeeded = nl + 2 + byteLen + 2;
if (buf.length < totalNeeded) return;
cleanup();
const flags = new Set(parts.slice(2));
const body = buf.subarray(nl + 2, nl + 2 + byteLen).toString('utf8');
resolve({ status: 'VA', flags, body });
} else {
cleanup();
resolve({ status: code, flags: new Set(parts.slice(1)), body: null });
}
};
const onErr = (err) => { cleanup(); reject(err); };
const cleanup = () => {
socket.off('data', onData);
socket.off('error', onErr);
};
socket.on('data', onData);
socket.on('error', onErr);
socket.write(line + '\r\n');
});
}
async function getWithStampedeGuard(socket, key, ttlSec, loaderFn) {
const res = await sendMetaCommand(socket, `mg ${key} v t N20 R15`);
const wonRecacheLock = res.flags.has('W');
const isStaleOrStub = res.flags.has('X') || res.body === '' || res.body === null;
if (res.status === 'VA' && !isStaleOrStub) {
if (wonRecacheLock) {
Promise.resolve(loaderFn()).then((fresh) => {
const payload = JSON.stringify(fresh);
return sendMetaCommand(socket, `ms ${key} ${Buffer.byteLength(payload)} T${ttlSec}\r\n${payload}`);
}).catch(() => {});
}
return JSON.parse(res.body);
}
if (wonRecacheLock) {
const fresh = await loaderFn();
const payload = JSON.stringify(fresh);
await sendMetaCommand(socket, `ms ${key} ${Buffer.byteLength(payload)} T${ttlSec}\r\n${payload}`);
return fresh;
}
await new Promise((r) => setTimeout(r, 35 + Math.floor(Math.random() * 25)));
const retry = await sendMetaCommand(socket, `mg ${key} v`);
return retry.status === 'VA' && retry.body ? JSON.parse(retry.body) : loaderFn();
}
module.exports = { sendMetaCommand, getWithStampedeGuard };