huge changes

This commit is contained in:
indifferentketchup
2026-04-07 01:43:06 -05:00
parent ca63ecbcfd
commit 69c247ed1b
37 changed files with 3468 additions and 169 deletions

View File

@@ -22,13 +22,25 @@ const { registerCommands } = require('./commands/register');
const bosscordRoutes = require('./routes/bosscord');
const { setBot } = require('./api/bosscordClient');
const { poll } = require('./gmail-poll');
const { setClient: setDebugClient } = require('./services/debugLog');
const { setClient: setDebugClient, logError, logSystem } = require('./services/debugLog');
// Re-export utilities for any external consumers
const { sendGmailReply } = require('./services/gmail');
const { getNextTicketNumber } = require('./services/tickets');
const { getCleanBody, detectGame, stripEmailQuotes, stripMobileFooter, htmlToTextWithBlocks } = require('./utils');
let gmailPollInterval = null;
/**
* Update the Gmail poll interval at runtime.
* @param {number} ms - new interval in milliseconds
*/
function setGmailPollInterval(ms) {
if (gmailPollInterval) clearInterval(gmailPollInterval);
CONFIG.GMAIL_POLL_INTERVAL_MS = ms;
gmailPollInterval = setInterval(() => poll(client), ms);
}
// --- VALIDATE CONFIG ---
if (!CONFIG.DISCORD_TOKEN) {
console.error('DISCORD_TOKEN or DISCORD_BOT_TOKEN is not set in .env');
@@ -51,7 +63,8 @@ const client = new Client({
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMembers
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildPresences // Required for staff presence detection; enable in Discord Developer Portal
],
partials: [Partials.Channel]
});
@@ -108,7 +121,18 @@ client.on('interactionCreate', async interaction => {
}
});
client.on('messageCreate', handleDiscordReply);
client.on('messageCreate', async msg => {
// Track staff last-seen for zero-staff detection fallback
if (!msg.author.bot && CONFIG.STAFF_IDS.includes(msg.author.id)) {
const { updateStaffLastSeen } = require('./services/patternStore');
updateStaffLastSeen(msg.author.id);
}
// Chat channel monitoring
const { handleChatMessage } = require('./services/chatAlertChecker');
await handleChatMessage(msg, client).catch(() => {});
// Existing ticket reply handler
await handleDiscordReply(msg);
});
client.once('ready', async () => {
if (!process.env.MONGODB_URI) {
@@ -144,7 +168,7 @@ client.once('ready', async () => {
registerCommands().catch(console.error);
setInterval(() => poll(client), 30000);
gmailPollInterval = setInterval(() => poll(client), CONFIG.GMAIL_POLL_INTERVAL_MS);
poll(client);
if (CONFIG.AUTO_CLOSE_ENABLED) {
@@ -163,7 +187,40 @@ client.once('ready', async () => {
console.log('✓ Auto-unclaim enabled: checking every hour');
}
const { runPatternChecks } = require('./services/patternChecker');
const { scheduleResets } = require('./services/patternStore');
scheduleResets();
setInterval(() => runPatternChecks(client).catch(e => console.error('runPatternChecks:', e)), CONFIG.PATTERN_CHECK_INTERVAL_MINUTES * 60 * 1000);
console.log(`✓ Pattern checks: every ${CONFIG.PATTERN_CHECK_INTERVAL_MINUTES} minutes`);
const { runSurgeChecks } = require('./services/surgeChecker');
setInterval(() => runSurgeChecks(client).catch(e => console.error('runSurgeChecks:', e)), 5 * 60 * 1000);
setTimeout(() => runSurgeChecks(client).catch(e => console.error('runSurgeChecks:', e)), 30000);
console.log('✓ Surge checks: every 5 minutes');
const { initChatMonitoring, runChatAlertChecks } = require('./services/chatAlertChecker');
initChatMonitoring(client);
setInterval(() => runChatAlertChecks(client).catch(e => console.error('runChatAlertChecks:', e)), 5 * 60 * 1000);
console.log('✓ Chat alert monitoring: every 5 minutes');
if (!CONFIG.STAFF_IDS.length) {
console.warn('[surgeChecker] STAFF_IDS is not set — zero-staff detection disabled.');
}
console.log('✓ Discord bot ready. Tag:', client.user.tag);
logSystem('Bot online', [
{ name: 'Guild', value: guild ? `${guild.name} (${guild.id})` : 'N/A' },
{ name: 'Poll interval', value: `${CONFIG.GMAIL_POLL_INTERVAL_MS / 1000}s` },
{ name: 'Auto-close', value: CONFIG.AUTO_CLOSE_ENABLED ? `enabled (${CONFIG.AUTO_CLOSE_AFTER_HOURS}h)` : 'disabled' },
{ name: 'Auto-unclaim', value: CONFIG.AUTO_UNCLAIM_ENABLED ? `enabled (${CONFIG.AUTO_UNCLAIM_AFTER_HOURS}h)` : 'disabled' },
{ name: 'Claim timeout', value: CONFIG.CLAIM_TIMEOUT_ENABLED ? `enabled (${CONFIG.CLAIM_TIMEOUT_HOURS}h)` : 'disabled' },
{ name: 'Gmail log', value: CONFIG.GMAIL_LOG_CHANNEL_ID ? 'configured' : 'not configured' },
{ name: 'Automation log', value: CONFIG.AUTOMATION_LOG_CHANNEL_ID ? 'configured' : 'not configured' },
{ name: 'Staff threads', value: CONFIG.STAFF_THREAD_ENABLED ? `enabled (name: "${CONFIG.STAFF_THREAD_NAME}")` : 'disabled' },
{ name: 'Pin initial message', value: CONFIG.PIN_INITIAL_MESSAGE_ENABLED ? 'enabled' : 'disabled' },
{ name: 'Pin escalation message', value: CONFIG.PIN_ESCALATION_MESSAGE_ENABLED ? 'enabled' : 'disabled' }
]).catch(() => {});
});
client.login(CONFIG.DISCORD_TOKEN);
@@ -177,8 +234,33 @@ app.listen(CONFIG.PORT, healthcheckHost, () => {
console.log(`Healthcheck server listening on ${healthcheckHost || '*'}:${CONFIG.PORT}`);
});
// --- Internal API for settings site ---
const internalApi = require('./routes/internalApi');
const internalApp = express();
internalApp.use('/internal', internalApi);
if (CONFIG.INTERNAL_API_SECRET) {
internalApp.listen(CONFIG.INTERNAL_API_PORT, '127.0.0.1', () => {
console.log(`[internalApi] listening on 127.0.0.1:${CONFIG.INTERNAL_API_PORT}`);
});
} else {
console.warn('[internalApi] INTERNAL_API_SECRET not set — internal API disabled.');
}
// --- Shutdown & error handlers ---
async function handleShutdown(signal) {
await Promise.race([logSystem('Bot shutting down', [{ name: 'Signal', value: signal }]), new Promise(r => setTimeout(r, 2000))]);
process.exit(0);
}
process.on('SIGTERM', () => handleShutdown('SIGTERM'));
process.on('SIGINT', () => handleShutdown('SIGINT'));
process.on('unhandledRejection', (reason) => {
logError('unhandledRejection', reason instanceof Error ? reason : new Error(String(reason))).catch(() => {});
});
module.exports = {
client,
setGmailPollInterval,
sendGmailReply,
sendTicketClosedEmail,
getNextTicketNumber,