@atmosx/event-product-parser 2.0.16 → 3.0.0

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.
Files changed (116) hide show
  1. package/README.md +4 -237
  2. package/dist/cjs/index.cjs +2233 -3105
  3. package/dist/esm/index.mjs +2233 -3108
  4. package/package.json +3 -2
  5. package/src/@building/building.clean.ts +30 -0
  6. package/src/@building/building.create.ts +42 -0
  7. package/src/@building/building.enhance.ts +56 -0
  8. package/src/@building/building.geometry.ts +42 -0
  9. package/src/@building/building.headers.ts +37 -0
  10. package/src/@building/building.office.ts +43 -0
  11. package/src/@building/building.polygon.ts +71 -0
  12. package/src/@building/building.properties.ts +89 -0
  13. package/src/@building/building.signature.ts +78 -0
  14. package/src/@building/building.tags.ts +24 -0
  15. package/src/@building/building.tracking.ts +68 -0
  16. package/src/@building/building.validate.ts +132 -0
  17. package/src/@core/core.callback.ts +39 -0
  18. package/src/@core/core.getEvents.ts +25 -0
  19. package/src/@core/core.getNodes.ts +25 -0
  20. package/src/@core/core.listener.ts +24 -0
  21. package/src/@core/core.setNode.ts +81 -0
  22. package/src/@core/core.start.ts +54 -0
  23. package/src/@core/core.stop.ts +32 -0
  24. package/src/@dictionaries/dictionaries.betterEventNames.ts +85 -0
  25. package/src/@dictionaries/dictionaries.eventActions.ts +28 -0
  26. package/src/@dictionaries/{awips.ts → dictionaries.eventAwipAbreviations.ts} +12 -6
  27. package/src/@dictionaries/dictionaries.eventCancelMessages.ts +29 -0
  28. package/src/@dictionaries/dictionaries.eventCauses.ts +36 -0
  29. package/src/@dictionaries/dictionaries.eventProducts.ts +25 -0
  30. package/src/@dictionaries/dictionaries.eventRecords.ts +25 -0
  31. package/src/@dictionaries/dictionaries.eventSeverity.ts +27 -0
  32. package/src/@dictionaries/dictionaries.eventStatus.ts +31 -0
  33. package/src/@dictionaries/{signatures.ts → dictionaries.eventTags.ts} +13 -68
  34. package/src/@dictionaries/dictionaries.eventTypes.ts +82 -0
  35. package/src/@dictionaries/dictionaries.eventsOffshore.ts +31 -0
  36. package/src/@dictionaries/dictionaries.hailStrings.ts +31 -0
  37. package/src/@dictionaries/{icao.ts → dictionaries.officeICAOs.ts} +13 -6
  38. package/src/@dictionaries/dictionaries.regExp.ts +28 -0
  39. package/src/@dictionaries/dictionaries.shapefileLinks.ts +36 -0
  40. package/src/@dictionaries/dictionaries.statusCorrelationText.ts +40 -0
  41. package/src/@dictionaries/dictionaries.test_signatures.ts +23 -0
  42. package/src/@dictionaries/dictionaries.transcribedMessageReplacements.ts +68 -0
  43. package/src/@events/events.api.ts +113 -0
  44. package/src/@events/events.text.ts +79 -0
  45. package/src/@events/events.ugc.ts +83 -0
  46. package/src/@events/events.vtec.ts +87 -0
  47. package/src/@manager/manager.mkEvent.ts +79 -0
  48. package/src/@manager/manager.rmEvent.ts +44 -0
  49. package/src/@manager/manager.setHash.ts +37 -0
  50. package/src/@manager/manager.updateNodes.ts +51 -0
  51. package/src/@modules/@database/database.cache.ts +48 -0
  52. package/src/@modules/@database/database.init.ts +45 -0
  53. package/src/@modules/@database/database.shapefiles.ts +97 -0
  54. package/src/@modules/@database/database.stanza.ts +47 -0
  55. package/src/@modules/@stanza/stanza.getAwipsType.ts +46 -0
  56. package/src/@modules/@stanza/stanza.validate.ts +50 -0
  57. package/src/@modules/@utilities/utilities.createHttp.ts +75 -0
  58. package/src/@modules/@utilities/utilities.getFormattedTime.ts +43 -0
  59. package/src/@modules/@utilities/utilities.getSettings.ts +25 -0
  60. package/src/@modules/@utilities/utilities.getShapeNearestPoint.ts +114 -0
  61. package/src/@modules/@utilities/utilities.setCronSchedule.ts +38 -0
  62. package/src/@modules/@utilities/utilities.setEventEmit.ts +41 -0
  63. package/src/@modules/@utilities/utilities.setListener.ts +30 -0
  64. package/src/@modules/@utilities/utilities.setSettings.ts +42 -0
  65. package/src/@modules/@utilities/utilities.setSleep.ts +33 -0
  66. package/src/@modules/@utilities/utilities.setTimeoutAction.ts +59 -0
  67. package/src/@modules/@utilities/utilities.setWarning.ts +34 -0
  68. package/src/@modules/@xmpp/xmpp.xDeploy.ts +58 -0
  69. package/src/@modules/@xmpp/xmpp.xError.ts +38 -0
  70. package/src/@modules/@xmpp/xmpp.xOffline.ts +38 -0
  71. package/src/@modules/@xmpp/xmpp.xOnline.ts +61 -0
  72. package/src/@modules/@xmpp/xmpp.xReconnect.ts +59 -0
  73. package/src/@modules/@xmpp/xmpp.xStanza.ts +63 -0
  74. package/src/@parsers/@hvtec/hvtec.extract.ts +40 -0
  75. package/src/@parsers/@pvtec/pvtec.expires.ts +26 -0
  76. package/src/@parsers/@pvtec/pvtec.extract.ts +50 -0
  77. package/src/@parsers/@text/text.getDescriptionFromProduct.ts +53 -0
  78. package/src/@parsers/@text/text.getPolygonFromProduct.ts +32 -0
  79. package/src/@parsers/@text/text.getTextFromProduct.ts +43 -0
  80. package/src/@parsers/@text/text.getXML.ts +61 -0
  81. package/src/@parsers/@ugc/ugc.coordinates.ts +110 -0
  82. package/src/@parsers/@ugc/ugc.expiry.ts +32 -0
  83. package/src/@parsers/@ugc/ugc.extract.ts +37 -0
  84. package/src/@parsers/@ugc/ugc.header.ts +30 -0
  85. package/src/@parsers/@ugc/ugc.locations.ts +29 -0
  86. package/src/@parsers/@ugc/ugc.zones.ts +52 -0
  87. package/src/@types/type.event.ts +67 -0
  88. package/src/@types/type.properties.ts +75 -0
  89. package/src/@types/types.attributes.ts +28 -0
  90. package/src/@types/types.compiled.ts +35 -0
  91. package/src/@types/types.hash.ts +24 -0
  92. package/src/@types/types.hvtec.ts +25 -0
  93. package/src/@types/types.pvtec.ts +29 -0
  94. package/src/@types/types.settings.ts +71 -0
  95. package/src/@types/types.stanza.ts +37 -0
  96. package/src/@types/types.ugc.ts +24 -0
  97. package/src/bootstrap.ts +82 -163
  98. package/src/index.ts +48 -216
  99. package/test.js +65 -49
  100. package/src/@dictionaries/events.ts +0 -168
  101. package/src/@parsers/@events/api.ts +0 -146
  102. package/src/@parsers/@events/cap.ts +0 -123
  103. package/src/@parsers/@events/text.ts +0 -104
  104. package/src/@parsers/@events/ugc.ts +0 -107
  105. package/src/@parsers/@events/vtec.ts +0 -76
  106. package/src/@parsers/events.ts +0 -392
  107. package/src/@parsers/hvtec.ts +0 -46
  108. package/src/@parsers/pvtec.ts +0 -72
  109. package/src/@parsers/stanza.ts +0 -97
  110. package/src/@parsers/text.ts +0 -165
  111. package/src/@parsers/ugc.ts +0 -247
  112. package/src/@submodules/database.ts +0 -201
  113. package/src/@submodules/eas.ts +0 -490
  114. package/src/@submodules/utils.ts +0 -191
  115. package/src/@submodules/xmpp.ts +0 -142
  116. package/src/types.ts +0 -259
@@ -0,0 +1,113 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeStanzaCompiled } from "../@types/types.compiled"
21
+ import { TypeEvent } from "../@types/type.event";
22
+ import { getEventTracking } from "../@building/building.tracking";
23
+ import { validateEvents } from "../@building/building.validate";
24
+ import { getEventOffice } from "../@building/building.office";
25
+ import { getEventTags } from "../@building/building.tags";
26
+ import { getTextFromProduct } from "../@parsers/@text/text.getTextFromProduct";
27
+ import { officeICAOs } from "../@dictionaries/dictionaries.officeICAOs";
28
+
29
+ export const api = async (stanza: TypeStanzaCompiled): Promise<void> => {
30
+ let processed: TypeEvent[] = [];
31
+ const messages = Object.values(JSON.parse(stanza.message).features) as any;
32
+ for (const feature of messages) {
33
+ const tick = performance.now();
34
+ const pVtec = feature?.properties?.parameters?.VTEC?.[0] ?? null
35
+ processed.push({
36
+ type: `Feature`,
37
+ geometry: {
38
+ type: `Point`,
39
+ coordinates: []
40
+ },
41
+ properties: {
42
+ event: feature?.properties?.event ?? null,
43
+ parent: feature?.properties?.event ?? null,
44
+ status: feature?.properties?.messageType ?? null,
45
+ issued: feature?.properties?.sent ? new Date(feature?.properties?.sent).toISOString() : null,
46
+ expires: feature?.properties?.expires ? new Date(feature?.properties?.expires).toISOString() : null,
47
+ locations: feature?.properties?.areaDesc ?? null,
48
+ description: feature?.properties?.description ?? null,
49
+ attributes: feature?.properties?.attributes ?? {},
50
+ geocode: {
51
+ office: {
52
+ office: pVtec ? pVtec.split(`.`)[2] : null,
53
+ name: officeICAOs[pVtec ? pVtec.split(`.`)[2] : null] ?? null,
54
+ },
55
+ organization: feature?.properties?.parameters?.WMOidentifier?.[0],
56
+ ugc: feature?.properties?.geocode?.UGC ?? [],
57
+ polygon: feature?.geometry?.coordinates.length > 0 ? Buffer.from(JSON.stringify([feature?.geometry?.coordinates[0]])).toString('base64') : null,
58
+ polygon_generated: feature?.geometry?.coordinates.length > 0 ? true : false,
59
+ },
60
+ parameters: {
61
+ tags: getEventTags(feature?.properties?.description),
62
+ instructions: feature?.properties?.instruction ?? null,
63
+ source: getTextFromProduct({ message: feature?.properties?.description, find: [`SOURCE...`], removal: [`.`]}) ?? null,
64
+ hazards: getTextFromProduct({ message: feature?.properties?.description, find: [`HAZARD...`], removal: [`.`]}) ?? null,
65
+ impacts: getTextFromProduct({ message: feature?.properties?.description, find: [`IMPACT...`], removal: [`.`]}) ?? null,
66
+ estimated_hail_size: feature?.properties?.parameters?.maxHailSize?.[0] ?? null,
67
+ estimated_wind_gusts: feature?.properties?.parameters?.maxWindGust?.[0] ?? null,
68
+ damage_threat: feature?.properties?.parameters?.thunderstormDamageThreat?.[0] ?? null,
69
+ tornado_threat: feature?.properties?.parameters?.tornadoDetection?.[0] ?? null,
70
+ flood_threat: feature?.properties?.parameters?.floodDetection?.[0] ?? null,
71
+ wind_threat: feature?.properties?.parameters?.windThreat?.[0] ?? null,
72
+ hail_threat: feature?.properties?.parameters?.hailThreat?.[0] ?? null,
73
+ },
74
+ spc_parameters: {
75
+ spc_max_tornado: getTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
76
+ spc_max_hail: getTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
77
+ spc_max_wind: getTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
78
+ spc_watch_issuance: getTextFromProduct({ message: feature?.properties?.description, find: [`Probability of Watch Issuance...`], removal: [`percent`]}) ?? null,
79
+ },
80
+ watch_parameters: {
81
+ watch_number: getTextFromProduct({ message: feature?.properties?.description, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim() ?? null,
82
+ watch_type: feature?.properties?.description.includes(`TORNADO WATCH`) ? `Tornado` : feature?.properties?.description.includes(`SEVERE`) ? `Severe` : null,
83
+ additional_tornadoes_probability: getTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
84
+ strong_tornadoes_probability: getTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
85
+ severe_wind_probability: getTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
86
+ severe_hail_probability: getTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
87
+ hail_2in_probability: getTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], removal: [`%`, `<`, `:`] }) ?? null,
88
+ combined_hail_wind_probability: getTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
89
+ max_hail_in: getTextFromProduct({ message: feature?.properties?.description, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] }) ?? null,
90
+ max_wind_surface: getTextFromProduct({ message: feature?.properties?.description, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] }) ?? null,
91
+ max_tops_x100feet: getTextFromProduct({ message: feature?.properties?.description, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] }) ?? null,
92
+ pds_watch: (getTextFromProduct({ message: feature?.properties?.description, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`)
93
+ },
94
+ metadata: {
95
+ ms: performance.now() - tick,
96
+ source: `events.api`,
97
+ tracking: getEventTracking({ type: `API`, organization: { wmoidentifier: feature?.properties?.parameters?.WMOidentifier?.[0], featureId: feature?.id}, vtec: pVtec}),
98
+ header: `ZCZC-ATMOSX-${feature?.properties?.parameters?.WMOidentifier}`,
99
+ vtec: pVtec,
100
+ hvtec: null,
101
+ history: [
102
+ {
103
+ description: feature?.properties?.description,
104
+ issued: feature?.properties?.sent ? new Date(feature?.properties?.sent).toISOString() : null,
105
+ status: feature?.properties?.messageType ?? null,
106
+ }
107
+ ]
108
+ }
109
+ }
110
+ })
111
+ }
112
+ validateEvents(processed)
113
+ }
@@ -0,0 +1,79 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeAttributes } from "../@types/types.attributes";
21
+ import { TypeStanzaCompiled } from "../@types/types.compiled"
22
+ import { TypeEvent } from "../@types/type.event";
23
+ import { properties } from "../@building/building.properties";
24
+ import { getEventHeader } from "../@building/building.headers";
25
+ import { eventsOffshore } from "../@dictionaries/dictionaries.eventsOffshore";
26
+ import { getEventTracking } from "../@building/building.tracking";
27
+ import { validateEvents } from "../@building/building.validate";
28
+
29
+ export const text = async (stanza: TypeStanzaCompiled): Promise<void> => {
30
+ let processed: TypeEvent[] = [];
31
+ const getMessages = stanza?.message
32
+ ?.split(/(?=\$\$)/g)
33
+ ?.map(message => message.trim())
34
+ ?.filter(message => message && message !== "$$");
35
+ if (!getMessages || getMessages?.length == 0 ) return;
36
+ for (const message of getMessages) {
37
+ const tick = performance.now();
38
+ const attributes = stanza?.attributes as TypeAttributes
39
+ const props = properties({ message, attributes })
40
+ const header = getEventHeader({properties: props, getType: stanza.getType})
41
+ const issued = new Date(attributes.issue)
42
+ const expires = new Date(issued.getTime() + 12 * 60 * 60 * 1000)
43
+ let event = Object.keys(eventsOffshore).find(event => message.toLowerCase().includes(event.toLowerCase()));
44
+ if (!event) {
45
+ event = stanza.getType.type.split(`-`).map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(` `)
46
+ }
47
+ processed.push({
48
+ type: `Feature`,
49
+ geometry: {
50
+ type: `Point`,
51
+ coordinates: []
52
+ },
53
+ properties: {
54
+ event: event,
55
+ parent: event,
56
+ status: `Issued`,
57
+ issued: (!isNaN(issued.getTime())) ? issued.toISOString() : new Date().toISOString(),
58
+ expires: (!isNaN(expires.getTime())) ? expires.toISOString() : new Date(Date.now() + 60 * 60 * 1000).toISOString(),
59
+ ...props,
60
+ metadata: {
61
+ ms: performance.now() - tick,
62
+ source: `events.text`,
63
+ tracking: getEventTracking({ type: `RAW`, stanza, attributes, properties: props }),
64
+ header: header,
65
+ vtec: null,
66
+ hvtec: null,
67
+ history: [
68
+ {
69
+ description: props.description,
70
+ issued: (!isNaN(issued.getTime())) ? issued.toISOString() : new Date().toISOString(),
71
+ status: `Issued`,
72
+ }
73
+ ]
74
+ }
75
+ }
76
+ })
77
+ }
78
+ validateEvents(processed)
79
+ }
@@ -0,0 +1,83 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeAttributes } from "../@types/types.attributes";
21
+ import { TypeStanzaCompiled } from "../@types/types.compiled"
22
+ import { TypeEvent } from "../@types/type.event";
23
+ import { eventsOffshore } from "../@dictionaries/dictionaries.eventsOffshore";
24
+ import { ugcExtract } from "../@parsers/@ugc/ugc.extract";
25
+ import { properties } from "../@building/building.properties";
26
+ import { getEventHeader } from "../@building/building.headers";
27
+ import { getEventTracking } from "../@building/building.tracking";
28
+ import { validateEvents } from "../@building/building.validate";
29
+
30
+ export const ugc = async (stanza: TypeStanzaCompiled): Promise<void> => {
31
+ let processed: TypeEvent[] = [];
32
+ const getMessages = stanza?.message
33
+ ?.split(/(?=\$\$)/g)
34
+ ?.map(message => message.trim())
35
+ ?.filter(message => message && message !== "$$");
36
+ if (!getMessages || getMessages?.length == 0 ) return;
37
+ for (const message of getMessages) {
38
+ const tick = performance.now();
39
+ const attributes = stanza?.attributes as TypeAttributes
40
+ const ugc = await ugcExtract(message)
41
+ if (ugc != null ) {
42
+ const props = properties({ message, attributes, ugc: ugc })
43
+ const issued = new Date(attributes.issue)
44
+ const expires = new Date(issued.getTime() + 12 * 60 * 60 * 1000)
45
+ const header = getEventHeader({properties: props, getType: stanza.getType })
46
+ let event = Object.keys(eventsOffshore).find(event => message.toLowerCase().includes(event.toLowerCase()));
47
+ if (!event) {
48
+ event = stanza.getType.type.split(`-`).map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(` `)
49
+ }
50
+ processed.push({
51
+ type: `Feature`,
52
+ geometry: {
53
+ type: `Point`,
54
+ coordinates: []
55
+ },
56
+ properties: {
57
+ event: event,
58
+ parent: event,
59
+ status: `Issued`,
60
+ issued: (!isNaN(issued.getTime())) ? issued.toISOString() : new Date().toISOString(),
61
+ expires: (!isNaN(expires.getTime())) ? expires.toISOString() : new Date(Date.now() + 60 * 60 * 1000).toISOString(),
62
+ ...props,
63
+ metadata: {
64
+ ms: performance.now() - tick,
65
+ source: `events.ugc`,
66
+ tracking: getEventTracking({ type: `RAW`, stanza, attributes, properties: props }),
67
+ header: header,
68
+ vtec: null,
69
+ hvtec: null,
70
+ history: [
71
+ {
72
+ description: props.description,
73
+ issued: (!isNaN(issued.getTime())) ? issued.toISOString() : new Date().toISOString(),
74
+ status: `Issued`
75
+ }
76
+ ]
77
+ }
78
+ }
79
+ })
80
+ }
81
+ }
82
+ validateEvents(processed)
83
+ }
@@ -0,0 +1,87 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeAttributes } from "../@types/types.attributes";
21
+ import { TypeStanzaCompiled } from "../@types/types.compiled"
22
+ import { TypeEvent } from "../@types/type.event";
23
+ import { TypePVTEC } from "../@types/types.pvtec";
24
+ import { TypeHVTEC } from "../@types/types.hvtec";
25
+ import { pvExtract } from "../@parsers/@pvtec/pvtec.extract";
26
+ import { hvExtract } from "../@parsers/@hvtec/hvtec.extract";
27
+ import { ugcExtract } from "../@parsers/@ugc/ugc.extract";
28
+ import { properties } from "../@building/building.properties";
29
+ import { getEventHeader } from "../@building/building.headers";
30
+ import { getEventTracking } from "../@building/building.tracking";
31
+ import { validateEvents } from "../@building/building.validate";
32
+
33
+ export const vtec = async (stanza: TypeStanzaCompiled): Promise<void> => {
34
+ let processed: TypeEvent[] = [];
35
+ const getMessages = stanza?.message
36
+ ?.split(/(?=\$\$)/g)
37
+ ?.map(message => message.trim())
38
+ ?.filter(message => message && message !== "$$");
39
+ if (!getMessages || getMessages?.length == 0 ) return;
40
+ for (const message of getMessages) {
41
+ const tick = performance.now();
42
+ const attributes = stanza?.attributes as TypeAttributes
43
+ const pVtec = await pvExtract(message) as TypePVTEC[];
44
+ const hVtec = await hvExtract(message) as TypeHVTEC[];
45
+ const ugc = await ugcExtract(message)
46
+ if (pVtec != null && ugc != null ) {
47
+ for (const pv of pVtec) {
48
+ const vtec = pv;
49
+ const props = properties({ message, attributes, ugc, pVtec: vtec })
50
+ const header = getEventHeader({properties: props, getType: stanza.getType, vtec: vtec})
51
+ const issued = new Date(attributes.issue)?? new Date()
52
+ const expires = new Date(vtec.expires)
53
+ processed.push({
54
+ type: `Feature`,
55
+ geometry: {
56
+ type: `Point`,
57
+ coordinates: []
58
+ },
59
+ properties: {
60
+ event: pv.event,
61
+ parent: pv.event,
62
+ status: pv.status,
63
+ issued: (!isNaN(issued.getTime())) ? issued.toISOString() : new Date().toISOString(),
64
+ expires: (!isNaN(expires.getTime())) ? expires.toISOString() : new Date(Date.now() + 60 * 60 * 1000).toISOString(),
65
+ ...props,
66
+ metadata: {
67
+ ms: performance.now() - tick,
68
+ source: `events.vtec`,
69
+ tracking: getEventTracking({ type: `VTEC`, stanza, attributes, properties: props, vtec }),
70
+ header: header,
71
+ vtec: pv.vtec,
72
+ hvtec: hVtec,
73
+ history: [
74
+ {
75
+ description: props.description,
76
+ issued: (!isNaN(issued.getTime())) ? issued.toISOString() : new Date().toISOString(),
77
+ status: pv.status
78
+ }
79
+ ]
80
+ }
81
+ }
82
+ })
83
+ }
84
+ }
85
+ }
86
+ validateEvents(processed)
87
+ }
@@ -0,0 +1,79 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
21
+ import { TypeEvent } from "../@types/type.event";
22
+ import { bootstrap } from "../bootstrap"
23
+ import { setHash } from "./manager.setHash";
24
+
25
+ export const mkEvent = async (event: TypeEvent): Promise<void> => {
26
+ const features = bootstrap.cache.events.features;
27
+ const featureMap: Map<string, typeof features[0]> = new Map();
28
+ const getHash = event.properties.metadata.hash;
29
+ const getTracking = event.properties.metadata.tracking;
30
+ features.forEach(f => f?.properties?.metadata?.tracking && featureMap.set(f?.properties?.metadata?.tracking, f));
31
+ const isEntry = bootstrap.cache.hashes?.find(hash => hash.tracking === getTracking)
32
+ const isHashed = isEntry?.hashes?.includes(getHash) ?? false;
33
+ const getFeature = featureMap.get(getTracking);
34
+ if (isHashed || event.properties.status_metadata.is_expired) return
35
+ setEventEmit({
36
+ event: `onEventStatus`,
37
+ metadata: {
38
+ type: getFeature ? `Updated` : `New`,
39
+ event: event
40
+ },
41
+ message: `[${getFeature ? 'Updated' : 'New'}] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
42
+ })
43
+ setHash(event, isEntry)
44
+ if (event.properties.status_metadata.is_issued || event.properties.status_metadata.is_updated) {
45
+ if (getFeature) {
46
+ const getIndex = features.indexOf(getFeature);
47
+ const cHistory = getFeature?.properties?.metadata?.history ?? [];
48
+ const cLocations = getFeature?.properties?.locations?.split(";").map((l: string) => l.trim()) ?? [];
49
+ const cUgc = getFeature?.properties?.geocode?.ugc ?? [];
50
+
51
+ const iHistory = event.properties?.metadata?.history ?? [];
52
+ const iLocations = event.properties?.locations?.split(";").map((l: string) => l.trim()) ?? [];
53
+ const iUgc = event.properties?.geocode?.ugc ?? [];
54
+
55
+ const mHistory = [...cHistory, ...iHistory].filter((v, i, a) => a.indexOf(v) === i);
56
+ const mLocations = [...cLocations, ...iLocations].filter((v, i, a) => a.indexOf(v) === i).join('; ');
57
+ const mUgc = [...cUgc, ...iUgc].filter((v, i, a) => a.indexOf(v) === i);
58
+
59
+ bootstrap.cache.events.features[getIndex] = {
60
+ ...event,
61
+ properties: {
62
+ ...event.properties,
63
+ metadata: {
64
+ ...event?.properties?.metadata,
65
+ history: mHistory
66
+ },
67
+ locations: mLocations,
68
+ geocode: {
69
+ ...event?.properties?.geocode,
70
+ ugc: mUgc
71
+ },
72
+ }
73
+ };
74
+ } else {
75
+ features.push(event)
76
+ featureMap.set(getTracking, event)
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,44 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
21
+ import { TypeEvent } from "../@types/type.event";
22
+ import { bootstrap } from "../bootstrap"
23
+
24
+ export const rmEvent = (event: TypeEvent): void => {
25
+ const getEvent = bootstrap.cache.events.features.find(f => f?.properties?.metadata?.tracking === event?.properties?.metadata?.tracking);
26
+ if (getEvent) {
27
+ setEventEmit({
28
+ event: `onEventStatus`,
29
+ metadata: {
30
+ type: `Removed`,
31
+ event: event
32
+ },
33
+ message: `[Removed] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
34
+ })
35
+ setEventEmit({ event: `onExpiredProduct`, metadata: event })
36
+ bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(getEvent), 1);
37
+ bootstrap.cache.hashes = bootstrap.cache.hashes.filter(hash => hash.tracking !== event.properties.metadata.tracking);
38
+ }
39
+ setEventEmit({
40
+ event: `onEventCache`,
41
+ metadata: bootstrap.cache.events,
42
+ limited: true
43
+ })
44
+ }
@@ -0,0 +1,37 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeEvent } from "../@types/type.event";
21
+ import { TypeHash } from "../@types/types.hash"
22
+ import { bootstrap } from "../bootstrap"
23
+
24
+
25
+ export const setHash = (event: TypeEvent, entry: TypeHash): void => {
26
+ if (entry) {
27
+ entry.hashes.push(event.properties.metadata.hash);
28
+ entry.expires = event.properties.expires;
29
+ } else {
30
+ bootstrap.cache.hashes.push({
31
+ tracking: event.properties.metadata.tracking,
32
+ hashes: [event.properties.metadata.hash],
33
+ expires: event.properties.expires
34
+ });
35
+ }
36
+
37
+ }
@@ -0,0 +1,51 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { getEventNodes } from "../@building/building.polygon";
21
+ import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
22
+ import { bootstrap } from "../bootstrap"
23
+
24
+
25
+ export const updateNodes = async (): Promise<void> => {
26
+ const events = bootstrap.cache.events.features;
27
+ const ttl = bootstrap.settings.GlobalSettings.NodeTTL * 1e3;
28
+ let total = 0;
29
+ await Promise.all(events.map(async (evt) => {
30
+ const lastUpdate = evt?.properties?.metadata?.nodes_updated ?? null;
31
+ if (lastUpdate != null && (Date.now() - lastUpdate) < ttl) {
32
+ return evt;
33
+ }
34
+ const node = await getEventNodes(evt);
35
+ if (node.nodes.length > 0) {
36
+ total++
37
+ }
38
+ evt.properties.metadata.nodes = node.nodes
39
+ evt.properties.metadata.filtered_proximity = node.filtered
40
+ evt.properties.metadata.nodes_updated = node.updated
41
+ }))
42
+ if (total > 0) {
43
+ setEventEmit({
44
+ event: `onNodeUpdate`,
45
+ metadata: {
46
+ type: `global-update`,
47
+ updated: total
48
+ },
49
+ })
50
+ }
51
+ }
@@ -0,0 +1,48 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeSettings } from "../../@types/types.settings"
21
+ import { bootstrap } from '../../bootstrap'
22
+ import { setWarning } from '../@utilities/utilities.setWarning';
23
+ import { createEvent } from '../../@building/building.create';
24
+
25
+ export const getCachedEvents = async (): Promise<void> => {
26
+ try {
27
+ const settings = bootstrap.settings as TypeSettings;
28
+ const tick = performance.now();
29
+ if (settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) {
30
+ const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxRetentionHistory ?? 500;
31
+ const get = await bootstrap.database.prepare(`SELECT * FROM stanzas ORDER BY rowid DESC LIMIT ?`).all(max) as { rowid: number; stanza: string }[];
32
+ setWarning({ message: `Fetched ${get.length} cached events from the database in ${Math.floor(performance.now() - tick)} ms` })
33
+ let events = get.map((row) => JSON.parse(row.stanza))
34
+ .filter(stanza => {
35
+ if (!stanza) { return }
36
+ const isSkippable = stanza.isIgnored ||
37
+ (stanza.isCapEvent) ||
38
+ (stanza.isCapEvent && !stanza.isCapAreaDescription)
39
+ return !isSkippable
40
+ });
41
+ events = events.sort((a, b) => b.issued - a.issued)
42
+ await Promise.all(events.map(event => createEvent(event)))
43
+ setWarning({ message: `Processed ${events.length} cached events in ${Math.floor(performance.now() - tick)} ms` })
44
+ }
45
+ } catch (error) {
46
+ setWarning({ message: `An error occurred while fetching cached events: ${error.message} -> ${error.stack}` })
47
+ }
48
+ }