Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ bot.command('help', (ctx: Context) => {
return ctx.reply(
`*AlphaFi ASIR Bot — Available Commands*\n\n` +
`\`/alert <description>\` — Trigger the Better Stack escalation policy and phone the on-call team.\n` +
`\`/status\` — Check if the bot is running and connected to Better Stack.\n` +
`\`/help\` — Show this message.\n\n` +
`*Notes:*\n` +
`• Only authorized users can trigger alerts.\n` +
Expand All @@ -188,6 +189,71 @@ bot.command('help', (ctx: Context) => {
);
});

bot.command('status', async (ctx: Context) => {
const userId = ctx.from!.id.toString();
const rawUserLabel = ctx.from!.username ? `@${ctx.from!.username}` : ctx.from!.first_name;

if (ALLOWED_USERS.length > 0 && !ALLOWED_USERS.includes(userId)) {
log.warn({ userId, userLabel: rawUserLabel }, 'Unauthorized /status access attempt');
return ctx.reply('🚫 Error: You are not authorized to use this command.');
}

const lastCheck = cooldowns.get(`status:${userId}`);
const now = Date.now();
if (lastCheck && now - lastCheck < COOLDOWN_MS) {
const remainingSeconds = Math.ceil((COOLDOWN_MS - (now - lastCheck)) / 1000);
return ctx.reply(`⏳ Slow down! You can check status again in ${remainingSeconds}s.`);
}
cooldowns.set(`status:${userId}`, now);

const statusMsg = await ctx.reply('⏳ Checking Better Stack connectivity...');

try {
const response = await axios.get(`${BETTER_STACK_URL}?per_page=1`, {
headers: HEADERS,
timeout: 10000,
});

const authLine = ALLOWED_USERS.length === 0
? '⚠️ *Auth:* No allowlist set — all users can trigger alerts'
: `🔒 *Auth:* Allowlist active (${ALLOWED_USERS.length} user${ALLOWED_USERS.length === 1 ? '' : 's'})`;

const policyLine = `📋 *Policy ID:* \`${POLICY_ID}\``;

log.info({ userId, httpStatus: response.status }, '/status check passed');

await ctx.telegram.editMessageText(
ctx.chat!.id,
statusMsg.message_id,
undefined,
`✅ *ASIR Bot Status*\n\n` +
`🤖 *Bot:* Running\n` +
`🌐 *Better Stack API:* Connected (HTTP ${response.status})\n` +
`${policyLine}\n` +
`${authLine}`,
{ parse_mode: 'Markdown' },
);
} catch (error) {
const axiosError = error as { response?: { status?: number }; message?: string };
const detail = axiosError.response?.status
? `HTTP ${axiosError.response.status}`
: axiosError.message;

log.error({ userId, detail }, '/status check failed');

await ctx.telegram.editMessageText(
ctx.chat!.id,
statusMsg.message_id,
undefined,
`❌ *ASIR Bot Status*\n\n` +
`🤖 *Bot:* Running\n` +
`🌐 *Better Stack API:* Unreachable (${escapeMarkdown(detail ?? '')})\n\n` +
`_The bot cannot trigger alerts until connectivity is restored._`,
{ parse_mode: 'Markdown' },
);
}
});

bot.catch((err: unknown, ctx: Context) => {
log.error({ updateType: ctx.updateType, err }, 'Unhandled bot error');
});
Expand Down
Loading