atmosx-nwws-parser 1.0.17 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,6 +25,7 @@ let Client = new AtmosXWireParser({
25
25
  onlyCap: false, // Set to true to only receive CAP messages only
26
26
  betterEvents: true, // Set to true to receive better event handling
27
27
  ugcPolygons: false, // Set to true to receive UGC Polygons instead of reading from raw products.
28
+ expiryCheck: true, // Set to true to check for expired alerts and remove them from the list
28
29
  filteredAlerts: [] // Alerts you want to only log, leave empty to receive all alerts (Ex. ["Tornado Warning", "Radar Indicated Tornado Warning"])
29
30
  },
30
31
  xmpp: {
@@ -33,7 +34,7 @@ let Client = new AtmosXWireParser({
33
34
  },
34
35
  cacheSettings: {
35
36
  maxMegabytes: 2, // Maximum cache size in megabytes
36
- readCache: false, // Set to true if you wish to reupload the cache from earlier
37
+ readCache: false, // Set to true if you wish to reupload the cache from earlier (Now supports reading from CAP, SPS, and Alerts)
37
38
  cacheDir: `./cache`, // Directory for cache files
38
39
  },
39
40
  authentication: {
package/index.js CHANGED
@@ -27,8 +27,24 @@ class NoaaWeatherWireServiceCore {
27
27
 
28
28
  if (loader.settings.cacheSettings.readCache && loader.settings.cacheSettings.cacheDir) {
29
29
  let target = `${loader.settings.cacheSettings.cacheDir}/nwws-raw-category-defaults-raw-vtec.bin`;
30
- if (loader.packages.fs.existsSync(target)) {
31
- this.forwardCustomStanza(loader.packages.fs.readFileSync(target, 'utf8'), { awipsid: 'alert', category: 'default', raw: true, issue: undefined });
30
+ let targetCap = `${loader.settings.cacheSettings.cacheDir}/nwws-raw-category-defaults-cap-vtec.bin`;
31
+ let targetStatements = `${loader.settings.cacheSettings.cacheDir}/nwws-raw-category-special-weather-statements-raw.bin`;
32
+ let targetMesoscale = `${loader.settings.cacheSettings.cacheDir}/nwws-raw-category-mesoscale-discussions-raw.bin`;
33
+ let targetStormReports = `${loader.settings.cacheSettings.cacheDir}/nwws-raw-category-local-storm-reports-raw.bin`;
34
+ if (loader.packages.fs.existsSync(target) && !loader.settings.alertSettings.onlyCap) {
35
+ this.forwardCustomStanza(loader.packages.fs.readFileSync(target, 'utf8'), { awipsid: 'alert', isCap: false, raw: true, issue: undefined });
36
+ }
37
+ if (loader.packages.fs.existsSync(targetCap) && loader.settings.alertSettings.onlyCap) {
38
+ this.forwardCustomStanza(loader.packages.fs.readFileSync(targetCap, 'utf8'), { awipsid: 'alert', isCap: true, raw: false, issue: undefined });
39
+ }
40
+ if (loader.packages.fs.existsSync(targetStatements)) {
41
+ this.forwardCustomStanza(loader.packages.fs.readFileSync(targetStatements, 'utf8'), { awipsid: 'SPS001', isCap: false, raw: true, issue: undefined });
42
+ }
43
+ if (loader.packages.fs.existsSync(targetMesoscale)) {
44
+ this.forwardCustomStanza(loader.packages.fs.readFileSync(targetMesoscale, 'utf8'), { awipsid: 'SWOMCD001', isCap: false, raw: true, issue: undefined });
45
+ }
46
+ if (loader.packages.fs.existsSync(targetStormReports)) {
47
+ this.forwardCustomStanza(loader.packages.fs.readFileSync(targetStormReports, 'utf8'), { awipsid: 'LSR001', isCap: false, raw: true, issue: undefined });
32
48
  }
33
49
  }
34
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atmosx-nwws-parser",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "NOAA Weather Wire Parser",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/events.js CHANGED
@@ -72,9 +72,8 @@ class NoaaWeatherWireServiceEvents {
72
72
  }
73
73
  }
74
74
  if (loader.settings.alertSettings.filteredAlerts && loader.settings.alertSettings.filteredAlerts.length > 0) {
75
- alerts = alerts.filter(alert =>
76
- loader.settings.alertSettings.filteredAlerts.includes(alert.properties.event)
77
- );
75
+ let pSet = new Set((loader.settings.alertSettings.filteredAlerts || []).map(p => String(p).toLowerCase()));
76
+ alerts = alerts.filter(alert => pSet.has(String(alert.properties?.event || '').toLowerCase()));
78
77
  }
79
78
  if (loader.settings.alertSettings.expiryCheck) {
80
79
  alerts = alerts.filter(alert =>
@@ -93,47 +92,52 @@ class NoaaWeatherWireServiceEvents {
93
92
  */
94
93
 
95
94
  newCapEvent = async function(stanza) {
96
- let message = stanza.message.substring(stanza.message.indexOf(`<?xml version="1.0"`), stanza.message.length);
97
- let data = loader.packages.xml2js.Parser();
98
- let result = await data.parseStringPromise(message);
99
- let tracking = result.alert.info[0].parameter.find(p => p.valueName[0] == "VTEC")?.value[0] || "N/A";
100
- let action = "N/A";
101
- if (tracking !== "N/A") {
102
- let splitVTEC = tracking.split(".");
103
- tracking = `${splitVTEC[2]}-${splitVTEC[3]}-${splitVTEC[4]}-${splitVTEC[5]}`;
104
- action = loader.definitions.status[splitVTEC[1]];
105
- } else {
106
- action = result.alert.msgType[0];
107
- tracking = `${result.alert.info[0].parameter.find(p => p.valueName[0] == "WMOidentifier")?.value[0]}-${result.alert.info[0].area[0].geocode.filter(g => g.valueName[0] == "UGC").map(g => g.value[0]).join("-")}`;
108
- }
109
- let alert = {
110
- id: `Wire-${tracking}`,
111
- tracking: tracking,
112
- action: action,
113
- history: [{ description: result.alert.info[0].description[0], action: action, issued: new Date(stanza.attributes.issue) }],
114
- properties: {
115
- areaDesc: result.alert.info[0].area[0].areaDesc[0],
116
- expires: new Date(result.alert.info[0].expires[0]),
117
- sent: new Date(result.alert.sent[0]),
118
- messageType: action,
119
- event: result.alert.info[0].event[0],
120
- sender: result.alert.sender[0],
121
- senderName: result.alert.info[0].senderName[0],
122
- description: result.alert.info[0].description[0],
123
- geocode: { UGC: result.alert.info[0].area[0].geocode.filter(g => g.valueName[0] == "UGC").map(g => g.value[0]) },
124
- parameters: {
125
- WMOidentifier: [result.alert.info[0].parameter.find(p => p.valueName[0] == "WMOidentifier")?.value[0] || "N/A"],
126
- tornadoDetection: result.alert.info[0].parameter.find(p => p.valueName[0] == "tornadoDetection")?.value[0] || result.alert.info[0].parameter.find(p => p.valueName[0] == "waterspoutDetection")?.value[0] || "N/A",
127
- maxHailSize: result.alert.info[0].parameter.find(p => p.valueName[0] == "maxHailSize")?.value[0] || "N/A",
128
- maxWindGust: result.alert.info[0].parameter.find(p => p.valueName[0] == "maxWindGust")?.value[0] || "N/A",
129
- thunderstormDamageThreat: [result.alert.info[0].parameter.find(p => p.valueName[0] == "thunderstormDamageThreat")?.value[0] || result.alert.info[0].parameter.find(p => p.valueName[0] == "tornadoDamageThreat")?.value[0] || "N/A"],
95
+ let message = stanza.message.match(/<\?xml[\s\S]*?<\/alert>/g) ?.map(xml => xml.trim()) || [];
96
+ let alerts = []
97
+ for (let msg of message) {
98
+ msg = msg.substring(msg.indexOf(`<?xml version="1.0"`), msg.lastIndexOf(`>`) + 1);
99
+ let data = loader.packages.xml2js.Parser();
100
+ let result = await data.parseStringPromise(msg);
101
+ let tracking = result.alert.info[0].parameter.find(p => p.valueName[0] == "VTEC")?.value[0] || "N/A";
102
+ let action = "N/A";
103
+ if (tracking !== "N/A") {
104
+ let splitVTEC = tracking.split(".");
105
+ tracking = `${splitVTEC[2]}-${splitVTEC[3]}-${splitVTEC[4]}-${splitVTEC[5]}`;
106
+ action = loader.definitions.status[splitVTEC[1]];
107
+ } else {
108
+ action = result.alert.msgType[0];
109
+ tracking = `${result.alert.info[0].parameter.find(p => p.valueName[0] == "WMOidentifier")?.value[0]}-${result.alert.info[0].area[0].geocode.filter(g => g.valueName[0] == "UGC").map(g => g.value[0]).join("-")}`;
110
+ }
111
+ let alert = {
112
+ id: `Wire-${tracking}`,
113
+ tracking: tracking,
114
+ action: action,
115
+ history: [{ description: result.alert.info[0].description[0], action: action, issued: new Date(stanza.attributes.issue) }],
116
+ properties: {
117
+ areaDesc: result.alert.info[0].area[0].areaDesc[0],
118
+ expires: new Date(result.alert.info[0].expires[0]),
119
+ sent: new Date(result.alert.sent[0]),
120
+ messageType: action,
121
+ event: result.alert.info[0].event[0],
122
+ sender: result.alert.sender[0],
123
+ senderName: result.alert.info[0].senderName[0],
124
+ description: result.alert.info[0].description[0],
125
+ geocode: { UGC: result.alert.info[0].area[0].geocode.filter(g => g.valueName[0] == "UGC").map(g => g.value[0]) },
126
+ parameters: {
127
+ WMOidentifier: [result.alert.info[0].parameter.find(p => p.valueName[0] == "WMOidentifier")?.value[0] || "N/A"],
128
+ tornadoDetection: result.alert.info[0].parameter.find(p => p.valueName[0] == "tornadoDetection")?.value[0] || result.alert.info[0].parameter.find(p => p.valueName[0] == "waterspoutDetection")?.value[0] || "N/A",
129
+ maxHailSize: result.alert.info[0].parameter.find(p => p.valueName[0] == "maxHailSize")?.value[0] || "N/A",
130
+ maxWindGust: result.alert.info[0].parameter.find(p => p.valueName[0] == "maxWindGust")?.value[0] || "N/A",
131
+ thunderstormDamageThreat: [result.alert.info[0].parameter.find(p => p.valueName[0] == "thunderstormDamageThreat")?.value[0] || result.alert.info[0].parameter.find(p => p.valueName[0] == "tornadoDamageThreat")?.value[0] || "N/A"],
132
+ },
130
133
  },
131
- },
132
- };
133
- if (result.alert.info[0].area[0].polygon) {
134
- alert.geometry = { type: "Polygon", coordinates: [result.alert.info[0].area[0].polygon[0].split(" ").map(coord => { let [lat, lon] = coord.split(",").map(parseFloat); return [lon, lat]; })] };
134
+ };
135
+ if (result.alert.info[0].area[0].polygon) {
136
+ alert.geometry = { type: "Polygon", coordinates: [result.alert.info[0].area[0].polygon[0].split(" ").map(coord => { let [lat, lon] = coord.split(",").map(parseFloat); return [lon, lat]; })] };
137
+ }
138
+ alerts.push(alert);
135
139
  }
136
- this.onFinished([alert]);
140
+ this.onFinished(alerts);
137
141
  }
138
142
 
139
143
  /**
package/src/stanza.js CHANGED
@@ -28,7 +28,7 @@ class NoaaWeatherWireServiceStanza {
28
28
  if (isDebug != false) {
29
29
  let message = isDebug.stanza
30
30
  let attributes = isDebug.attrs;
31
- let isCap = message.includes(`<?xml version="1.0"`)
31
+ let isCap = isDebug.isCap || message.includes(`<?xml version="1.0"`);
32
32
  let hasCapArea = message.includes(`<areaDesc>`);
33
33
  let hasVtec = message.match(loader.definitions.expressions.vtec) != null;
34
34
  let getId = this.getAwipsType(attributes)