fix/retry-sending-failed-msgs (#1)
Some checks are pending
ptero-push / build (push) Waiting to run
Some checks are pending
ptero-push / build (push) Waiting to run
Reviewed-on: #1 Co-authored-by: ChrisChrome <chris@chrischro.me> Co-committed-by: ChrisChrome <chris@chrischro.me>
This commit is contained in:
parent
6706ab2809
commit
f865daaf3b
|
|
@ -297,5 +297,19 @@
|
||||||
"required": false
|
"required": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "devtest",
|
||||||
|
"description": "[BOT OWNER ONLY] Test the bot with a sample message",
|
||||||
|
"default_member_permissions": 0,
|
||||||
|
"type": 1,
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "randstr",
|
||||||
|
"description": "override random string in test message for testing",
|
||||||
|
"type": 3,
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
100
index.js
100
index.js
|
|
@ -358,6 +358,14 @@ Image and product text are optional, but if they exist, they will be in the data
|
||||||
var sent = {}
|
var sent = {}
|
||||||
|
|
||||||
const handleDiscord = function (data, randStr) {
|
const handleDiscord = function (data, randStr) {
|
||||||
|
/*
|
||||||
|
Example data object:
|
||||||
|
{
|
||||||
|
type: 'iem-message',
|
||||||
|
data: {
|
||||||
|
channel: { room: 'botstalk', location: 'All_Bots_Talk' },
|
||||||
|
*/
|
||||||
|
|
||||||
const rawBody = data.data.body;
|
const rawBody = data.data.body;
|
||||||
const text = data.data.productText;
|
const text = data.data.productText;
|
||||||
const product_id_raw = data.data.raw
|
const product_id_raw = data.data.raw
|
||||||
|
|
@ -448,59 +456,34 @@ const handleDiscord = function (data, randStr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 10 * 60 * 1000);
|
}, 10 * 60 * 1000);
|
||||||
|
let errCount = 0;
|
||||||
|
function sendMessage() {
|
||||||
channel.send(thisMsg).catch((err) => {
|
channel.send(thisMsg).catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}).then((msg) => {
|
}).then((msg) => {
|
||||||
if (msg.channel.type === Discord.ChannelType.GuildAnnouncement) msg.crosspost();
|
if (msg.channel.type === Discord.ChannelType.GuildAnnouncement) msg.crosspost();
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
console.log(`${colors.yellow("[WARN]")} Failed to send message to ${channel.guild.name}/${channel.name} (${channel.guild.id}/${channel.id})`);
|
console.log(`${colors.yellow("[WARN]")} Failed to send message to ${channel.guild.name}/${channel.name} (${channel.guild.id}/${channel.id})`);
|
||||||
|
if (errCount < 3) {
|
||||||
|
errCount++;
|
||||||
|
setTimeout(sendMessage, 5000); // Retry after 5 seconds
|
||||||
|
} else {
|
||||||
const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
|
const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
|
||||||
logChannel.send({
|
logChannel.send({
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
title: "Failed to send message",
|
title: "Failed to send message",
|
||||||
description: `There is likely an issue with permissions. Please notify the server owner if possible.
|
description: `Failed to send message after 3 attempts, skipping for now. Channel may be deleted or bot may have lost access.\n
|
||||||
Guild: ${channel.guild.name} (${channel.guild.id})
|
Channel: ${channel.guild.name}/${channel.name} (${channel.guild.id}/${channel.id})
|
||||||
Channel: ${channel.name} (${channel.id})
|
|
||||||
Guild Owner: <@${channel.guild.ownerId}> (${channel.guild.ownerId})
|
|
||||||
Sub Info: \`\`\`json\n${JSON.stringify(row)}\`\`\``,
|
Sub Info: \`\`\`json\n${JSON.stringify(row)}\`\`\``,
|
||||||
color: 0xff0000
|
color: 0xff0000
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
discord.users.fetch(channel.guild.ownerId).then((user) => {
|
|
||||||
user.send({
|
|
||||||
embeds: [
|
|
||||||
{
|
|
||||||
title: "Issue with your subscribed channel.",
|
|
||||||
description: `There is likely an issue with permissions. Please check that I can send messages in <#${channel.id}>\nYour subscription has been removed, and you will need to resubscribe to get alerts.`,
|
|
||||||
color: 0xff0000,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "Guild",
|
|
||||||
value: `${channel.guild.name} (${channel.guild.id})`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Channel",
|
|
||||||
value: `${channel.name} (${channel.id})`
|
|
||||||
}
|
}
|
||||||
]
|
});
|
||||||
}
|
}
|
||||||
]
|
sendMessage()
|
||||||
}).catch((err) => {
|
|
||||||
console.log(`${colors.red("[ERROR]")} Failed to send message to ${channel.guild.ownerId}`);
|
|
||||||
}).then(() => {
|
|
||||||
if (channel.guildId == config.discord.mainGuild) return;
|
|
||||||
db.run(`DELETE FROM channels WHERE channelid = ? AND iemchannel = ?`, [channel.id, fromChannel], (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err.message);
|
|
||||||
}
|
|
||||||
console.log(`${colors.cyan("[INFO]")} Deleted channel ${channel.id} from database`);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -548,8 +531,15 @@ const handleDiscord = function (data, randStr) {
|
||||||
if (!filters.some((filter) => body.string.toLowerCase().includes(filter)) && !filters.some((filter) => text.toLowerCase().includes(filter))) return;
|
if (!filters.some((filter) => body.string.toLowerCase().includes(filter)) && !filters.some((filter) => text.toLowerCase().includes(filter))) return;
|
||||||
thisMsg = JSON.parse(JSON.stringify(discordMsg));
|
thisMsg = JSON.parse(JSON.stringify(discordMsg));
|
||||||
thisMsg.content = row.custommessage || null;
|
thisMsg.content = row.custommessage || null;
|
||||||
|
let errCount = 0;
|
||||||
|
|
||||||
|
function sendMessage() {
|
||||||
user.send(thisMsg).catch((err) => {
|
user.send(thisMsg).catch((err) => {
|
||||||
console.log(`${colors.yellow("[WARN]")} Failed to send message to ${user.tag} (${user.id})`);
|
console.log(`${colors.yellow("[WARN]")} Failed to send message to ${user.tag} (${user.id})`);
|
||||||
|
if (errCount < 3) {
|
||||||
|
errCount++;
|
||||||
|
setTimeout(sendMessage, 5000); // Retry after 5 seconds
|
||||||
|
} else {
|
||||||
const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
|
const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
|
||||||
logChannel.send({
|
logChannel.send({
|
||||||
embeds: [
|
embeds: [
|
||||||
|
|
@ -561,14 +551,11 @@ const handleDiscord = function (data, randStr) {
|
||||||
color: 0xff0000
|
color: 0xff0000
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
|
||||||
db.run(`DELETE FROM userAlerts WHERE userid = ?`, [row.userid], (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err.message);
|
|
||||||
}
|
|
||||||
console.log(`${colors.cyan("[INFO]")} Deleted all subs for user ${user.id} from database`);
|
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sendMessage();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -1436,6 +1423,35 @@ discord.on("interactionCreate", async (interaction) => {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "devtest":
|
||||||
|
if (interaction.user.id !== config.discord.owner) return interaction.reply({ content: "You are not the bot owner.", ephemeral: true });
|
||||||
|
// Test suite;
|
||||||
|
let output = "Dev Test Started:\n";
|
||||||
|
await interaction.reply({ content: output, ephemeral: true });
|
||||||
|
//1. Add current channel to db with a fake room (discordtest)
|
||||||
|
db.run(`INSERT INTO channels (channelid, iemchannel) VALUES (?, ?)`, [interaction.channel.id, "discordtest"], async (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err.message);
|
||||||
|
await interaction.editReply({ content: output + "Failed to add channel to database.", ephemeral: true });
|
||||||
|
return; // Stop the test. grr
|
||||||
|
} else {
|
||||||
|
output += "Added channel to database.\n";
|
||||||
|
interaction.editReply({ content: output, ephemeral: true });
|
||||||
|
|
||||||
|
//2. directly trigger handleDiscord with a fake message for the fake room.
|
||||||
|
|
||||||
|
let randStr = interaction.options.getString("randstr") || Math.random().toString(36).substring(2, 15)
|
||||||
|
handleDiscord(require("./testmsg.json"), randStr);
|
||||||
|
output += "Triggered handleDiscord with test message.\n";
|
||||||
|
interaction.editReply({ content: output, ephemeral: true });
|
||||||
|
setTimeout(() => {
|
||||||
|
// 3. At this point the dev needs to verify that the message sent, or didnt send if testing retry code. Just end at this point.
|
||||||
|
output += "Dev Test Completed. Please verify the message was sent correctly.";
|
||||||
|
interaction.editReply({ content: output, ephemeral: true });
|
||||||
|
}, 2500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Discord.InteractionType.MessageComponent:
|
case Discord.InteractionType.MessageComponent:
|
||||||
if (!interaction.customId) return;
|
if (!interaction.customId) return;
|
||||||
|
|
|
||||||
35
testmsg.json
Normal file
35
testmsg.json
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"type": "iem-message",
|
||||||
|
"data": {
|
||||||
|
"channel": {
|
||||||
|
"room": "discordtest",
|
||||||
|
"location": "Discord Test Room"
|
||||||
|
},
|
||||||
|
"fromChannel": "discordtest",
|
||||||
|
"event": {
|
||||||
|
"text": "Severe Thunderstorm Warning",
|
||||||
|
"priority": 4,
|
||||||
|
"code": "SVR"
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"string": "!!!DISCORD TEST MESSAGE!!! DMX issues Severe Thunderstorm Warning (SVR) for Polk County until Jun 12, 16:15 UTC ",
|
||||||
|
"url": "https://mesonet.agron.iastate.edu/vtec/f/2026-O-NEW-KDMX-SV-W-0123_2026-06-12T1545Z"
|
||||||
|
},
|
||||||
|
"timestamp": "2026-06-12T15:45:00.000Z",
|
||||||
|
"wmo": "WUUS53",
|
||||||
|
"pil": "SVRDMX",
|
||||||
|
"station": "KDMX",
|
||||||
|
"product_data": {
|
||||||
|
"timestamp": "2026-06-12T15:45:00.000Z",
|
||||||
|
"originalTimestamp": "202606121545",
|
||||||
|
"station": "KDMX",
|
||||||
|
"wmo": "WUUS53",
|
||||||
|
"pil": "SVRDMX"
|
||||||
|
},
|
||||||
|
"raw": "202606121545-KDMX-WUUS53-SVRDMX",
|
||||||
|
"rawBody": "!!!DISCORD TEST MESSAGE!!! DMX issues Severe Thunderstorm Warning (SVR) for Polk County until Jun 12, 16:15 UTC https://mesonet.agron.iastate.edu/vtec/f/2026-O-NEW-KDMX-SV-W-0123_2026-06-12T1545Z",
|
||||||
|
"image": "https://mesonet.agron.iastate.edu/plotting/auto/plot/208/network:WFO::wfo:DMX::year:2026::phenomenav:SV::significancev:W::etn:123::valid:2026-06-12%201545::_r:86.png",
|
||||||
|
"productText": "!!!DISCORD TEST MESSAGE!!!\n\n796 \nWUUS53 KDMX 121545\nSVRDMX\nIAC153-121615-\n/O.NEW.KDMX.SV.W.0123.260612T1545Z-260612T1615Z/\nBULLETIN - IMMEDIATE BROADCAST REQUESTED\nSevere Thunderstorm Warning\nNational Weather Service Des Moines IA\n1045 AM CDT Fri Jun 12 2026\n\nThe National Weather Service in Des Moines has issued a\n\n* Severe Thunderstorm Warning for...\n Polk County in central Iowa...\n\n* Until 1115 AM CDT.\n\n* At 1045 AM CDT, a severe thunderstorm was located near Ankeny,\n moving east at 35 mph.\n\n* HAZARD...60 mph wind gusts and quarter size hail.\n\n$$\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
33
wstest.js
Normal file
33
wstest.js
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
const WebSocket = require('ws');
|
||||||
|
const config = require('./config.json');
|
||||||
|
|
||||||
|
const ws = new WebSocket(
|
||||||
|
config.WS_URL || "wss://iembot.dev/iem",
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"user-agent": "IEM-Alerter-DiscordBot/1.0 (+https://git.chrischro.me/iem-alerter/discord-bot; contact: me@ko4wal.radio)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ws.on('open', () => {
|
||||||
|
console.log('Connected to WebSocket');
|
||||||
|
ws.send(JSON.stringify({ type: 'subscribe', channel: '*' }));
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('message', (rawData) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(rawData);
|
||||||
|
console.log(JSON.stringify(data, null, 2));
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Raw (non-JSON):', rawData.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('close', () => {
|
||||||
|
console.log('WebSocket connection closed.');
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('error', (err) => {
|
||||||
|
console.error('WebSocket error:', err);
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue