77 lines
1.9 KiB
JavaScript
77 lines
1.9 KiB
JavaScript
const { Pool } = require('pg');
|
|
|
|
const cache = {
|
|
global: [],
|
|
byGuild: new Map(), // guildId -> rows[]
|
|
ready: false
|
|
};
|
|
|
|
function inWindow(row, now = new Date()) {
|
|
if (row.starts_at && now < new Date(row.starts_at)) return false;
|
|
if (row.ends_at && now > new Date(row.ends_at)) return false;
|
|
return true;
|
|
}
|
|
|
|
function pickWeighted(list) {
|
|
if (!list.length) return null;
|
|
const total = list.reduce((a, r) => a + (r.weight || 1), 0);
|
|
let rnd = Math.random() * total;
|
|
for (const r of list) {
|
|
rnd -= (r.weight || 1);
|
|
if (rnd <= 0) return r;
|
|
}
|
|
return list[0];
|
|
}
|
|
|
|
async function loadAll(pool) {
|
|
const { rows } = await pool.query(
|
|
`SELECT id, name, activity_type, enabled, weight, scope, guild_id, starts_at, ends_at
|
|
FROM bot_statuses
|
|
WHERE enabled = TRUE`
|
|
);
|
|
|
|
const now = new Date();
|
|
cache.global = rows.filter(r => r.scope === 'global' && inWindow(r, now));
|
|
cache.byGuild.clear();
|
|
for (const r of rows) {
|
|
if (r.scope === 'guild' && inWindow(r, now) && r.guild_id) {
|
|
const arr = cache.byGuild.get(r.guild_id) || [];
|
|
arr.push(r);
|
|
cache.byGuild.set(r.guild_id, arr);
|
|
}
|
|
}
|
|
cache.ready = true;
|
|
}
|
|
|
|
async function initStatusCache(pool) {
|
|
await loadAll(pool);
|
|
|
|
// Live refresh when table changes (if you created the trigger)
|
|
const client = await pool.connect();
|
|
await client.query('LISTEN status_change');
|
|
client.on('notification', async () => {
|
|
try {
|
|
await loadAll(pool);
|
|
console.log('[status] cache refreshed via NOTIFY');
|
|
} catch (e) {
|
|
console.error('[status] refresh error:', e);
|
|
}
|
|
});
|
|
|
|
// Safety: periodic refresh in case NOTIFY is missed
|
|
setInterval(() => loadAll(pool).catch(() => {}), 5 * 60 * 1000);
|
|
}
|
|
|
|
function getNextStatus(guildId) {
|
|
const rows = (guildId && cache.byGuild.get(guildId))?.length
|
|
? cache.byGuild.get(guildId)
|
|
: cache.global;
|
|
|
|
return pickWeighted(rows || []);
|
|
}
|
|
|
|
module.exports = {
|
|
initStatusCache,
|
|
getNextStatus
|
|
};
|