Add some docs
This commit is contained in:
parent
4c53a02d58
commit
453442d92f
95
index.js
95
index.js
|
@ -9,12 +9,38 @@ const blacklist = require("./blacklist.json")
|
||||||
const wfos = require("./wfos.json")
|
const wfos = require("./wfos.json")
|
||||||
const events = require("./events.json")
|
const events = require("./events.json")
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const markdown = require('markdown-it')();
|
||||||
|
const ejs = require('ejs');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
expressWs(app);
|
expressWs(app);
|
||||||
|
|
||||||
// Serve static files from the "public" directory
|
// Serve static files from the "public" directory
|
||||||
app.use(express.static('public'));
|
app.use(express.static('public'));
|
||||||
|
app.use(express.json());
|
||||||
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
app.set('view engine', 'ejs');
|
||||||
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
|
||||||
|
|
||||||
|
app.get("/", (req, res) => {
|
||||||
|
const markdownFilePath = path.join(__dirname, 'md', 'DOCS.md');
|
||||||
|
|
||||||
|
fs.readFile(markdownFilePath, 'utf8', (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error reading markdown file:', err);
|
||||||
|
res.status(500).send('Internal Server Error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const htmlContent = markdown.render(data);
|
||||||
|
|
||||||
|
res.render('docViewer', {title: 'Websocket Docs', htmlContent: htmlContent});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
global.wsConnections = [];
|
global.wsConnections = [];
|
||||||
var roomList = [];
|
var roomList = [];
|
||||||
// IEM WebSocket
|
// IEM WebSocket
|
||||||
|
@ -36,7 +62,13 @@ app.ws('/iem', (ws, req) => {
|
||||||
try {
|
try {
|
||||||
ws.on('message', (msg) => {
|
ws.on('message', (msg) => {
|
||||||
const data = JSON.parse(msg);
|
const data = JSON.parse(msg);
|
||||||
if (!data.type) return;
|
if (!data.type) return ws.send(JSON.stringify({
|
||||||
|
"type": "internal-response",
|
||||||
|
"code": 400,
|
||||||
|
"data": {
|
||||||
|
"error": "Invalid request."
|
||||||
|
}
|
||||||
|
}));
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case "subscribe":
|
case "subscribe":
|
||||||
const subscriptionTarget = data.channel || getWFOroom(data.wfo) || "*";
|
const subscriptionTarget = data.channel || getWFOroom(data.wfo) || "*";
|
||||||
|
@ -129,6 +161,16 @@ app.ws('/iem', (ws, req) => {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
"type": "internal-response",
|
||||||
|
"code": 400,
|
||||||
|
"data": {
|
||||||
|
"error": "Invalid request."
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -309,7 +351,7 @@ xmpp.on("offline", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
var restartTimer = null;
|
var restartTimer = null;
|
||||||
|
var sent = [];
|
||||||
xmpp.on("stanza", (stanza) => {
|
xmpp.on("stanza", (stanza) => {
|
||||||
// Debug stuff
|
// Debug stuff
|
||||||
//if (config.debug >= 2) console.log(`${colors.magenta("[DEBUG]")} Stanza: ${stanza.toString()}`);
|
//if (config.debug >= 2) console.log(`${colors.magenta("[DEBUG]")} Stanza: ${stanza.toString()}`);
|
||||||
|
@ -373,10 +415,13 @@ xmpp.on("stanza", (stanza) => {
|
||||||
const diff = (now - product_id.timestamp) / 1000 / 60;
|
const diff = (now - product_id.timestamp) / 1000 / 60;
|
||||||
if (diff > 3) return;
|
if (diff > 3) return;
|
||||||
// if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} New message from ${fromChannel}`);
|
// if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} New message from ${fromChannel}`);
|
||||||
console.log(`${colors.cyan("[INFO]")} ${getWFOByRoom(fromChannel).location} - ${evt.text} - ${product_id.timestamp}`);
|
console.log(`${colors.cyan("[INFO]")} ${getWFOByRoom(fromChannel).location} - ${product_id_raw} - ${evt.text} - ${product_id.timestamp}`);
|
||||||
messages++;
|
messages++;
|
||||||
|
textTries = 0;
|
||||||
// Handle WebSocket
|
tryGetText = () => {
|
||||||
|
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 (wsConnections.length > 0) {
|
if (wsConnections.length > 0) {
|
||||||
wsConnections.forEach((connection) => {
|
wsConnections.forEach((connection) => {
|
||||||
if (connection.subs.includes(fromChannel) || connection.subs.includes("*")) {
|
if (connection.subs.includes(fromChannel) || connection.subs.includes("*")) {
|
||||||
|
@ -392,12 +437,49 @@ xmpp.on("stanza", (stanza) => {
|
||||||
"station": product_id.station,
|
"station": product_id.station,
|
||||||
"raw": product_id_raw,
|
"raw": product_id_raw,
|
||||||
"rawBody": body,
|
"rawBody": body,
|
||||||
"image": stanza.getChild("x").attrs.twitter_media || null
|
"image": stanza.getChild("x").attrs.twitter_media || null,
|
||||||
|
"productText": text || null
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (textTries >= 3) {
|
||||||
|
console.log(`${colors.red("[ERROR]")} Failed to fetch product text, giving up... ${err}`)
|
||||||
|
if (wsConnections.length > 0) {
|
||||||
|
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,
|
||||||
|
"productText": null
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textTries++;
|
||||||
|
console.log(`${colors.red("[ERROR]")} Failed to fetch product text, retrying... ${err}`)
|
||||||
|
setTimeout(tryGetText, 100);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
tryGetText();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -528,3 +610,4 @@ app.listen(PORT, () => {
|
||||||
console.log(`Server is listening on ${PORT}`);
|
console.log(`Server is listening on ${PORT}`);
|
||||||
start();
|
start();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
187
md/DOCS.md
Normal file
187
md/DOCS.md
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
# IEM Alerter WebSocket API Documentation
|
||||||
|
|
||||||
|
WebSocket Endpoint: `/iem`
|
||||||
|
|
||||||
|
This WebSocket endpoint allows clients to subscribe to weather-related channels,
|
||||||
|
receive real-time updates, and manage their subscriptions.
|
||||||
|
|
||||||
|
## Legal Disclaimer
|
||||||
|
|
||||||
|
This system is not intended to be used for, or as a supplement for information regarding life or death situations. For critical weather-related information, please rely on official sources such as National Weather Service radio stations, local radio or news outlets, and local emergency management agencies.
|
||||||
|
|
||||||
|
## Connection
|
||||||
|
Upon connecting to the `/iem` WebSocket endpoint, the server will send a connection-info message
|
||||||
|
containing the following details:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "connection-info",
|
||||||
|
"state": true,
|
||||||
|
"uuid": "<unique-identifier>",
|
||||||
|
"host": "<server-hostname>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supported Message Types
|
||||||
|
|
||||||
|
### 1. Subscribe to a Channel
|
||||||
|
Clients can subscribe to a specific channel or all channels.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "subscribe",
|
||||||
|
"channel": "<channel-name>" // Optional, subscribe to all channels if omitted
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
- Success:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "internal-response",
|
||||||
|
"code": 200,
|
||||||
|
"data": {
|
||||||
|
"message": "Subscribed to <channel-name>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Failure (Invalid Channel):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "internal-response",
|
||||||
|
"code": 404,
|
||||||
|
"data": {
|
||||||
|
"error": "Invalid channel."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Unsubscribe from a Channel
|
||||||
|
Clients can unsubscribe from a specific channel or all channels.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "unsubscribe",
|
||||||
|
"channel": "<channel-name>" // Optional, unsubscribe from all channels if omitted
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
- Success:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "internal-response",
|
||||||
|
"code": 200,
|
||||||
|
"data": {
|
||||||
|
"message": "Unsubscribed from <channel-name>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Failure (Invalid Channel):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "internal-response",
|
||||||
|
"code": 404,
|
||||||
|
"data": {
|
||||||
|
"error": "Invalid channel."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Get Current Subscriptions
|
||||||
|
Clients can request a list of their current subscriptions.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "get-subscriptions"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "internal-response",
|
||||||
|
"code": 200,
|
||||||
|
"data": {
|
||||||
|
"subscriptions": ["<channel-name-1>", "<channel-name-2>"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Get Room List
|
||||||
|
Clients can request a list of available rooms.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "room-list"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
- Success:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "room-list",
|
||||||
|
"code": 200,
|
||||||
|
"count": <number-of-rooms>,
|
||||||
|
"data": ["<room-name-1>", "<room-name-2>"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Failure (No Rooms Available):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "room-list",
|
||||||
|
"code": 503,
|
||||||
|
"count": 0,
|
||||||
|
"data": {
|
||||||
|
"error": "Room list is currently empty. Please try again later."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Real-Time Updates
|
||||||
|
When subscribed to a channel, clients will receive real-time updates in the following format:
|
||||||
|
|
||||||
|
**Message:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "iem-message",
|
||||||
|
"data": {
|
||||||
|
"channel": {
|
||||||
|
"location": "<location-name>",
|
||||||
|
"room": "<room-name>"
|
||||||
|
},
|
||||||
|
"event": {
|
||||||
|
"name": "<event-name>",
|
||||||
|
"priority": <priority-level>,
|
||||||
|
"code": "<event-code>"
|
||||||
|
},
|
||||||
|
"body": "<message-body>",
|
||||||
|
"timestamp": "<timestamp>",
|
||||||
|
"wmo": "<wmo-code>",
|
||||||
|
"pil": "<pil-code>",
|
||||||
|
"station": "<station-name>",
|
||||||
|
"raw": "<raw-product-id>",
|
||||||
|
"rawBody": "<raw-message-body>",
|
||||||
|
"image": "<image-url>", // Optional
|
||||||
|
"productText": "<product-text>" // Optional
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The Priority level is a number from 1 to 5, 1 being the loest priority and 5 being the highest. These priority levels are defined per alert type by the developers of the IEM alerter system.
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
If an error occurs, the server will send an error response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "internal-response",
|
||||||
|
"code": 500,
|
||||||
|
"data": {
|
||||||
|
"error": "Internal server error."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
208
package-lock.json
generated
208
package-lock.json
generated
|
@ -12,9 +12,11 @@
|
||||||
"@xmpp/client": "^0.13.4",
|
"@xmpp/client": "^0.13.4",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
|
"ejs": "^3.1.10",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"express-ws": "^5.0.2",
|
"express-ws": "^5.0.2",
|
||||||
"html-entities": "^2.6.0"
|
"html-entities": "^2.6.0",
|
||||||
|
"markdown-it": "^14.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
|
@ -782,6 +784,21 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/anymatch": {
|
"node_modules/anymatch": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||||
|
@ -796,6 +813,12 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/argparse": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
|
"license": "Python-2.0"
|
||||||
|
},
|
||||||
"node_modules/array-buffer-byte-length": {
|
"node_modules/array-buffer-byte-length": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
|
||||||
|
@ -855,6 +878,12 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/async": {
|
||||||
|
"version": "3.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||||
|
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/async-function": {
|
"node_modules/async-function": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
||||||
|
@ -1091,6 +1120,22 @@
|
||||||
],
|
],
|
||||||
"license": "CC-BY-4.0"
|
"license": "CC-BY-4.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/chalk": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||||
|
@ -1143,6 +1188,24 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/colors": {
|
"node_modules/colors": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
||||||
|
@ -1408,6 +1471,21 @@
|
||||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/ejs": {
|
||||||
|
"version": "3.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
|
||||||
|
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"jake": "^10.8.5"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"ejs": "bin/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.136",
|
"version": "1.5.136",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.136.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.136.tgz",
|
||||||
|
@ -1423,6 +1501,18 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/es-abstract": {
|
"node_modules/es-abstract": {
|
||||||
"version": "1.23.9",
|
"version": "1.23.9",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz",
|
||||||
|
@ -1690,6 +1780,36 @@
|
||||||
"node": "^12.20 || >= 14.13"
|
"node": "^12.20 || >= 14.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/filelist": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"minimatch": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/filelist/node_modules/brace-expansion": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/filelist/node_modules/minimatch": {
|
||||||
|
"version": "5.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||||
|
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
@ -2001,6 +2121,15 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/has-property-descriptors": {
|
"node_modules/has-property-descriptors": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||||
|
@ -2565,6 +2694,24 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jake": {
|
||||||
|
"version": "10.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
|
||||||
|
"integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"async": "^3.2.3",
|
||||||
|
"chalk": "^4.0.2",
|
||||||
|
"filelist": "^1.0.4",
|
||||||
|
"minimatch": "^3.1.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"jake": "bin/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
@ -2610,6 +2757,15 @@
|
||||||
"integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==",
|
"integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/linkify-it": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"uc.micro": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||||
|
@ -2663,6 +2819,23 @@
|
||||||
"semver": "bin/semver"
|
"semver": "bin/semver"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/markdown-it": {
|
||||||
|
"version": "14.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
||||||
|
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"argparse": "^2.0.1",
|
||||||
|
"entities": "^4.4.0",
|
||||||
|
"linkify-it": "^5.0.0",
|
||||||
|
"mdurl": "^2.0.0",
|
||||||
|
"punycode.js": "^2.3.1",
|
||||||
|
"uc.micro": "^2.1.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"markdown-it": "bin/markdown-it.mjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
@ -2683,6 +2856,12 @@
|
||||||
"safe-buffer": "^5.1.2"
|
"safe-buffer": "^5.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mdurl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/media-typer": {
|
"node_modules/media-typer": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
||||||
|
@ -3089,6 +3268,15 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/punycode.js": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.14.0",
|
"version": "6.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||||
|
@ -3648,6 +3836,18 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
@ -3758,6 +3958,12 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uc.micro": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/unbox-primitive": {
|
"node_modules/unbox-primitive": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
|
||||||
|
|
|
@ -13,8 +13,10 @@
|
||||||
"@xmpp/client": "^0.13.4",
|
"@xmpp/client": "^0.13.4",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
|
"ejs": "^3.1.10",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"express-ws": "^5.0.2",
|
"express-ws": "^5.0.2",
|
||||||
"html-entities": "^2.6.0"
|
"html-entities": "^2.6.0",
|
||||||
|
"markdown-it": "^14.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
<!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>
|
|
||||||
const socket = new WebSocket(`ws://${window.location.host}/iem`);
|
|
||||||
socket.onopen = () => {
|
|
||||||
const newDiv = document.createElement('div');
|
|
||||||
newDiv.innerText = "WebSocket connection opened";
|
|
||||||
document.getElementById('stuff').prepend(newDiv);
|
|
||||||
|
|
||||||
};
|
|
||||||
socket.onclose = () => {
|
|
||||||
const newDiv = document.createElement('div');
|
|
||||||
newDiv.innerText = "WebSocket connection closed";
|
|
||||||
document.getElementById('stuff').prepend(newDiv);
|
|
||||||
|
|
||||||
};
|
|
||||||
socket.onmessage = (event) => {
|
|
||||||
const data = JSON.parse(event.data);
|
|
||||||
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>
|
|
46
views/docViewer.ejs
Normal file
46
views/docViewer.ejs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><%= title %></title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 20px;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #121212;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #1e90ff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
background: #1e1e1e;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow-x: auto;
|
||||||
|
color: #dcdcdc;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
background: #1e1e1e;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #dcdcdc;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="markdown-content">
|
||||||
|
<%- htmlContent %>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue