137 lines
3.3 KiB
JavaScript
137 lines
3.3 KiB
JavaScript
const config = require("./config.json");
|
|
const { client, xml } = require("@xmpp/client");
|
|
const fetch = require("node-fetch");
|
|
const html = require("html-entities")
|
|
const Discord = require("discord.js");
|
|
var hook;
|
|
if (config.discord.enabled) {
|
|
hook = new Discord.WebhookClient({ url: config.discord.webhook })
|
|
}
|
|
var startup = true;
|
|
const channel = config.iem.channel
|
|
// Random funcs
|
|
const parseProductID = function (product_id) {
|
|
const [timestamp, station, wmo, pil] = product_id.split("-");
|
|
return {
|
|
timestamp: convertDate(timestamp),
|
|
station,
|
|
wmo,
|
|
pil
|
|
};
|
|
}
|
|
|
|
// Convert date format 202405080131 (YYYYMMddHHmm) to iso format, hours and mins is UTC
|
|
const convertDate = function (date) {
|
|
const year = date.substring(0, 4);
|
|
const month = date.substring(4, 6);
|
|
const day = date.substring(6, 8);
|
|
const hours = date.substring(8, 10);
|
|
const mins = date.substring(10, 12);
|
|
return new Date(Date.UTC(year, month - 1, day, hours, mins));
|
|
}
|
|
|
|
|
|
|
|
|
|
const xmpp = client({
|
|
service: "xmpp://conference.weather.im",
|
|
domain: "weather.im",
|
|
resource: channel
|
|
});
|
|
|
|
//debug(xmpp, true);
|
|
|
|
xmpp.on("error", (err) => {
|
|
console.log("ERROR")
|
|
console.error(err);
|
|
xmpp.start().catch(console.error);
|
|
});
|
|
|
|
xmpp.on("offline", () => {
|
|
console.log("offline");
|
|
});
|
|
|
|
|
|
|
|
|
|
// Simple echo bot example
|
|
xmpp.on("stanza", (stanza) => {
|
|
if (startup) return;
|
|
// Get new messages and log them, ignore old messages
|
|
if (stanza.is("message") && stanza.attrs.type === "groupchat") {
|
|
if (!stanza.getChild("x")) return; // No PID, ignore it
|
|
if (!stanza.getChild("x").attrs.product_id) return;
|
|
const body = html.decode(stanza.getChildText("body"));
|
|
// get product id from "x" tag
|
|
const product_id = parseProductID(stanza.getChild("x").attrs.product_id);
|
|
|
|
// Check timestamp, if not within 2 minutes, ignore it
|
|
const now = new Date();
|
|
const diff = (now - product_id.timestamp) / 1000 / 60;
|
|
if (diff > 3) return;
|
|
|
|
// Handle NTFY
|
|
if (config.ntfy.enabled) {
|
|
ntfyBody = {
|
|
"topic": config.ntfy.topic,
|
|
"message": body,
|
|
"title": "New Alert",
|
|
"priority": config.ntfy.priority,
|
|
"tags": [`Station:${product_id.station}`, `WMO:${product_id.wmo}`, `PIL:${product_id.pil}`, `Channel:${channel}`],
|
|
}
|
|
|
|
if (stanza.getChild("x").attrs.twitter_media) {
|
|
ntfyBody.attach = stanza.getChild("x").attrs.twitter_media;
|
|
}
|
|
if (body) {
|
|
fetch(config.ntfy.server, {
|
|
method: 'POST',
|
|
body: JSON.stringify(ntfyBody)
|
|
})
|
|
}
|
|
}
|
|
|
|
// Handle Discord
|
|
if (config.discord.enabled) {
|
|
let embed = {
|
|
title: "New Alert",
|
|
description: body,
|
|
color: 0x00ff00,
|
|
timestamp: product_id.timestamp,
|
|
footer: {
|
|
text: `Station: ${product_id.station} WMO: ${product_id.wmo} PIL: ${product_id.pil} Channel: ${channel}`
|
|
}
|
|
}
|
|
if (stanza.getChild("x").attrs.twitter_media) {
|
|
embed.image = {
|
|
url: stanza.getChild("x").attrs.twitter_media
|
|
}
|
|
}
|
|
hook.send({
|
|
embeds: [embed]
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
|
|
xmpp.on("online", async (address) => {
|
|
// Makes itself available
|
|
await xmpp.send(xml("presence", { to: `${channel}@conference.weather.im/${channel}` }));
|
|
console.log("online as", address.toString());
|
|
setTimeout(() => {
|
|
startup = false;
|
|
}, 1000)
|
|
});
|
|
|
|
const start = () => {
|
|
xmpp.start().catch(() => {
|
|
console.error("start failed, trying again in a few seconds");
|
|
xmpp.stop();
|
|
setTimeout(() => {
|
|
start();
|
|
}, 5000);
|
|
});
|
|
}
|
|
start(); |