Done some stuff

This commit is contained in:
Christopher Cookman 2025-04-15 18:39:32 -06:00
parent fe5ac6073a
commit 94d5930cf4
2 changed files with 126 additions and 198 deletions

297
index.js
View file

@ -28,14 +28,59 @@ app.ws('/iem', (ws, req) => {
"uuid": curUUID,
"host": hostname
}));
wsConnections.push(ws);
sock = wsConnections.push({ ws, req, subs: [] });
ws.on('close', () => {
console.log(`disconnected from ${req.ip}`);
wsConnections = wsConnections.filter((conn) => conn !== ws);
wsConnections = wsConnections.filter((conn) => conn.ws !== ws);
});
ws.on('message', (msg) => {
if (msg === "ping") {
ws.send("pong")
const data = JSON.parse(msg);
if (!data.type) return;
switch (data.type) {
case "subscribe":
if (data.channel) {
if (!wsConnections[sock - 1].subs.includes(data.channel)) {
wsConnections[sock - 1].subs.push(data.channel);
ws.send(JSON.stringify({
"type": "internal-response",
"code": 200,
"data": {
"message": `Subscribed to ${data.channel}`
}
}));
} else {
ws.send(JSON.stringify({
"type": "internal-response",
"code": 409,
"data": {
"error": "Already subscribed to this channel."
}
}));
}
}
break;
case "unsubscribe":
if (data.channel) {
if (wsConnections[sock - 1].subs.includes(data.channel)) {
wsConnections[sock - 1].subs = wsConnections[sock - 1].subs.filter((sub) => sub !== data.channel);
ws.send(JSON.stringify({
"type": "internal-response",
"code": 200,
"data": {
"message": `Unsubscribed from ${data.channel}`
}
}));
} else {
ws.send(JSON.stringify({
"type": "internal-response",
"code": 404,
"data": {
"error": "Not subscribed to this channel."
}
}));
}
}
break;
}
});
});
@ -228,13 +273,6 @@ xmpp.on("stanza", (stanza) => {
}
// Get new messages and log them, ignore old messages
if (stanza.is("message") && stanza.attrs.type === "groupchat") {
clearTimeout(restartTimer)
restartTimer = setTimeout(() => {
console.log(`${colors.yellow("[WARN]")} Restarting XMPP connection...`);
xmpp.disconnect().then(() => {
xmpp.start();
});
}, 10000)
// Stops spam from getting old messages
if (startup) return;
// Get channel name
@ -254,7 +292,6 @@ xmpp.on("stanza", (stanza) => {
if (!evt) {
evt = { name: "Unknown", priority: 3 }
console.log(`${colors.red("[ERROR]")} Unknown event type: ${product_id.pil.substring(0, 3)}. Fix me`);
console.log(`${colors.magenta("[DEBUG]")} ${bodyData.string}`)
const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
logChannel.send({
embeds: [
@ -276,193 +313,68 @@ xmpp.on("stanza", (stanza) => {
console.log(`${colors.cyan("[INFO]")} ${getWFOByRoom(fromChannel).location} - ${evt.text} - ${product_id.timestamp}`);
messages++;
// // Handle NTFY
// if (config.ntfy.enabled) {
// //if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} Sending NTFY for ${config.ntfy.prefix}${fromChannel}`)
// ntfyBody = {
// "topic": `${config.ntfy.prefix}${fromChannel}`,
// "message": bodyData.string,
// "tags": [`Timestamp: ${product_id.timestamp}`, `Station: ${product_id.station}`, `WMO: ${product_id.wmo}`, `PIL: ${product_id.pil}`, `Channel: ${fromChannel}`],
// "priority": evt.priority,
// "actions": [{ "action": "view", "label": "Product", "url": bodyData.url }, { "action": "view", "label": "Product Text", "url": `https://mesonet.agron.iastate.edu/api/1/nwstext/${product_id_raw}` }]
// }
// if (stanza.getChild("x").attrs.twitter_media) {
// ntfyBody.attach = stanza.getChild("x").attrs.twitter_media;
// }
// fetch(config.ntfy.server, {
// method: 'POST',
// body: JSON.stringify(ntfyBody),
// headers: {
// 'Authorization': `Bearer ${config.ntfy.token}`
// }
// }).then((res) => {
// //if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} NTFY sent for ${config.ntfy.prefix}${fromChannel} with status ${res.status} ${res.statusText}`);
// if (res.status !== 200) console.log(`${colors.red("[ERROR]")} NTFY failed for ${config.ntfy.prefix}${fromChannel} with status ${res.status} ${res.statusText}`);
// }).catch((err) => {
// console.error(err)
// })
// }
// Send discord msg
// let embed = {
// description: `<t:${product_id.timestamp / 1000}:T> <t:${product_id.timestamp / 1000}:R> ${bodyData.string}`,
// color: parseInt(config.priorityColors[evt.priority].replace("#", ""), 16) || 0x000000,
// timestamp: product_id.timestamp,
// footer: {
// text: `Station: ${product_id.station} PID: ${product_id_raw} Channel: ${fromChannel}`
// }
// }
// if (stanza.getChild("x").attrs.twitter_media) {
// embed.image = {
// url: stanza.getChild("x").attrs.twitter_media
// }
// }
// let discordMsg = {
// embeds: [embed],
// components: [
// {
// type: 1,
// components: [
// {
// type: 2,
// label: "Product",
// style: 5,
// url: bodyData.url
// },
// {
// type: 2,
// style: 1,
// custom_id: `product|${product_id_raw}`,
// label: "Product Text",
// emoji: {
// name: "📄"
// }
// }
// ]
// }
// ]
// }
// // Discord Channel Handling
// db.all(`SELECT * FROM channels WHERE iemchannel = ?`, [fromChannel], (err, rows) => {
// if (err) {
// console.log(`${colors.red("[ERROR]")} ${err.message}`);
// }
// if (!rows) return; // No channels to alert
// rows.forEach(async (row) => {
// // Get Filters as arrays
// if (!row.filterEvt) row.filterEvt = "";
// if (!row.filter) row.filter = "";
// let filterEvt = row.filterEvt.toLowerCase().split(",");
// let filters = row.filter.toLowerCase().split(",");
// if (evt.priority < row.minPriority) return;
// // If the event type is not in th filter, ignore it. Make sure filterEvt isnt null
// if (!filterEvt[0]) filterEvt = [];
// if (!filterEvt.includes(evt.code.toLowerCase()) && !filterEvt.length == 0) return;
// let channel = discord.channels.cache.get(row.channelid);
// if (!channel) return console.log(`${colors.red("[ERROR]")} Channel ${row.channelid} not found`);
// // fetch the product text
// trySend = () => {
// fetch(`https://mesonet.agron.iastate.edu/api/1/nwstext/${product_id_raw}`).then((res) => {
// // If neither the body nor the product text contains the filter, ignore it
// res.text().then((text) => {
// if (!filters.some((filter) => body.toLowerCase().includes(filter)) && !filters.some((filter) => text.toLowerCase().includes(filter))) return;
// thisMsg = JSON.parse(JSON.stringify(discordMsg));
// thisMsg.content = row.custommessage || null;
// channel.send(thisMsg).catch((err) => {
// console.error(err);
// }).then((msg) => {
// if (msg.channel.type === Discord.ChannelType.GuildAnnouncement) msg.crosspost();
// }).catch((err) => {
// console.log(`${colors.yellow("[WARN]")} Failed to send message to ${channel.guild.name}/${channel.name} (${channel.guild.id}/${channel.id})`);
// const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
// logChannel.send({
// embeds: [
// {
// title: "Failed to send message",
// description: `There is likely an issue with permissions. Please notify the server owner if possible.
// Guild: ${channel.guild.name} (${channel.guild.id})
// Channel: ${channel.name} (${channel.id})
// Guild Owner: <@${channel.guild.ownerId}> (${channel.guild.ownerId})
// Sub Info: \`\`\`json\n${JSON.stringify(row)}\`\`\``,
// 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})`
// }
// ]
// }
// ]
// }).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`);
// });
// })
// });
// });
// });
// }).catch((err) => {
// setTimeout(() => {
// console.log(`${colors.red("[ERROR]")} Failed to fetch product text, retrying... ${err}`)
// trySend();
// })
// });
// }
// trySend();
// });
// });
// Handle WebSocket
if (wsConnections.length > 0) {
wsConnections.forEach((ws) => {
ws.send(JSON.stringify({
"type": "iem-message",
"data": {
"channel": getWFOByRoom(fromChannel),
"event": evt,
"body": bodyData.string,
"timestamp": product_id.timestamp,
"wmo": product_id.wmo,
"pil": product_id.pil,
"station": product_id.station,
"raw": product_id_raw,
"rawBody": body,
"image": stanza.getChild("x").attrs.twitter_media || null
}
}));
wsConnections.forEach((connection) => {
if (connection.subs.includes(fromChannel) || connection.subs.includes("*")) {
connection.ws.send(JSON.stringify({
"type": "iem-message",
"data": {
"channel": getWFOByRoom(fromChannel),
"event": evt,
"body": bodyData.string,
"timestamp": product_id.timestamp,
"wmo": product_id.wmo,
"pil": product_id.pil,
"station": product_id.station,
"raw": product_id_raw,
"rawBody": body,
"image": stanza.getChild("x").attrs.twitter_media || null
}
}));
}
});
}
}
});
xmpp.on("status", (status) => {
console.log(`${colors.cyan("[INFO]")} XMPP Status: ${status}`);
// Broadcast a message to all connected WebSocket clients
wsConnections.forEach((connection) => {
if (connection.ws.readyState === 1) { // Ensure the socket is open
connection.ws.send(JSON.stringify({
"type": "xmpp-status",
"status": status
}));
}
});
});
xmpp.reconnect.on("reconnecting", () => {
console.log(`${colors.yellow("[WARN]")} XMPP Reconnecting...`);
wsConnections.forEach((connection) => {
if (connection.ws.readyState === 1) { // Ensure the socket is open
connection.ws.send(JSON.stringify({
"type": "xmpp-reconnect",
"status": "reconnecting"
}));
}
});
})
xmpp.reconnect.on("reconnected", () => {
console.log(`${colors.green("[INFO]")} XMPP Reconnected`);
wsConnections.forEach((connection) => {
if (connection.ws.readyState === 1) { // Ensure the socket is open
connection.ws.send(JSON.stringify({
"type": "xmpp-reconnect",
"status": "reconnected"
}));
}
});
})
const createDiscordEmbed = (data) => {
const embed = {
description: `<t:${Math.floor(data.timestamp / 1000)}:T> <t:${Math.floor(data.timestamp / 1000)}:R> ${data.body}`,
@ -541,7 +453,6 @@ xmpp.on("close", () => {
const start = () => {
startup = true;
xmpp.start().catch((err) => {
console.log("BWUH")
console.log(`${colors.red("[ERROR]")} XMPP failed to start: ${err}.`);
setTimeout(start, 5000);
});

View file

@ -1,10 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="stuff"></div>
<script>
@ -23,13 +25,28 @@
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
const explanation = `Event: ${JSON.stringify(data.event)}, Channel: ${JSON.stringify(data.channel)}, Station: ${data.station}`;
console.log(explanation);
const newDiv = document.createElement('div');
newDiv.innerText = explanation;
document.getElementById('stuff').prepend(newDiv);
if (!data.type) return;
switch (data.type) {
case "iem-message":
const explanation = `Event: ${JSON.stringify(data.event)}, Channel: ${JSON.stringify(data.channel)}, Station: ${data.station}`;
console.log(explanation);
const newDiv = document.createElement('div');
newDiv.innerText = explanation;
document.getElementById('stuff').prepend(newDiv);
break;
case "internal-response":
const messageBox = document.createElement('textarea');
messageBox.value = data.data.message;
messageBox.style.width = "100%";
messageBox.style.height = "100px";
document.getElementById('stuff').prepend(messageBox);
break;
}
};
socket.send(JSON.stringify({ type: "subscribe", channel: "*" }));
</script>
</body>
</html>