@atmosx/event-product-parser 2.0.16 → 3.0.1

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 (136) hide show
  1. package/README.md +248 -187
  2. package/dist/cjs/index.cjs +12218 -3139
  3. package/dist/esm/index.mjs +12401 -3327
  4. package/dist/index.d.mts +235 -0
  5. package/dist/index.d.ts +235 -0
  6. package/package.json +6 -4
  7. package/src/@building/building.clean.ts +30 -0
  8. package/src/@building/building.create.ts +42 -0
  9. package/src/@building/building.enhance.ts +56 -0
  10. package/src/@building/building.geometry.ts +48 -0
  11. package/src/@building/building.headers.ts +37 -0
  12. package/src/@building/building.office.ts +43 -0
  13. package/src/@building/building.polygon.ts +71 -0
  14. package/src/@building/building.properties.ts +89 -0
  15. package/src/@building/building.signature.ts +61 -0
  16. package/src/@building/building.tags.ts +24 -0
  17. package/src/@building/building.tracking.ts +68 -0
  18. package/src/@building/building.validate.ts +147 -0
  19. package/src/@core/core.getEvents.ts +25 -0
  20. package/src/@core/core.getNodes.ts +25 -0
  21. package/src/@core/core.getRandomEvent.ts +25 -0
  22. package/src/@core/core.getVersion.ts +25 -0
  23. package/src/@core/core.listener.ts +24 -0
  24. package/src/@core/core.setNode.ts +81 -0
  25. package/src/@core/core.start.ts +59 -0
  26. package/src/@core/core.stop.ts +32 -0
  27. package/src/@dictionaries/dictionaries.betterEventNames.ts +89 -0
  28. package/src/@dictionaries/dictionaries.eventActions.ts +28 -0
  29. package/src/@dictionaries/{awips.ts → dictionaries.eventAwipAbreviations.ts} +13 -7
  30. package/src/@dictionaries/dictionaries.eventCancelMessages.ts +30 -0
  31. package/src/@dictionaries/dictionaries.eventCauses.ts +36 -0
  32. package/src/@dictionaries/dictionaries.eventProducts.ts +25 -0
  33. package/src/@dictionaries/dictionaries.eventRecords.ts +25 -0
  34. package/src/@dictionaries/dictionaries.eventSeverity.ts +27 -0
  35. package/src/@dictionaries/dictionaries.eventStatus.ts +31 -0
  36. package/src/@dictionaries/{signatures.ts → dictionaries.eventTags.ts} +13 -68
  37. package/src/@dictionaries/dictionaries.eventTypes.ts +82 -0
  38. package/src/@dictionaries/dictionaries.eventsOffshore.ts +31 -0
  39. package/src/@dictionaries/dictionaries.hailStrings.ts +33 -0
  40. package/src/@dictionaries/{icao.ts → dictionaries.officeICAOs.ts} +13 -6
  41. package/src/@dictionaries/dictionaries.regExp.ts +28 -0
  42. package/src/@dictionaries/dictionaries.shapefileLinks.ts +36 -0
  43. package/src/@dictionaries/dictionaries.statusCorrelationText.ts +40 -0
  44. package/src/@dictionaries/dictionaries.testSignatures.ts +24 -0
  45. package/src/@dictionaries/dictionaries.transcribedMessageReplacements.ts +68 -0
  46. package/src/@events/events.api.ts +113 -0
  47. package/src/@events/events.text.ts +79 -0
  48. package/src/@events/events.ugc.ts +83 -0
  49. package/src/@events/events.vtec.ts +87 -0
  50. package/src/@manager/manager.mkEvent.ts +95 -0
  51. package/src/@manager/manager.rmEvent.ts +46 -0
  52. package/src/@manager/manager.setHash.ts +37 -0
  53. package/src/@manager/manager.updateNodes.ts +55 -0
  54. package/src/@manager/manager.updateWebhooks.ts +50 -0
  55. package/src/@modules/@database/database.cache.ts +48 -0
  56. package/src/@modules/@database/database.init.ts +45 -0
  57. package/src/@modules/@database/database.shapefiles.ts +96 -0
  58. package/src/@modules/@database/database.stanza.ts +48 -0
  59. package/src/@modules/@eas/eas.getFloatPCM16.ts +29 -0
  60. package/src/@modules/@eas/eas.getMergedPCM16.ts +32 -0
  61. package/src/@modules/@eas/eas.getPCM16.ts +52 -0
  62. package/src/@modules/@eas/eas.getPCMToFloat.ts +26 -0
  63. package/src/@modules/@eas/eas.getSampledPCM16.ts +36 -0
  64. package/src/@modules/@eas/eas.getWavPCM16.ts +52 -0
  65. package/src/@modules/@eas/eas.setAFSK.ts +52 -0
  66. package/src/@modules/@eas/eas.setAsciiToBits.ts +32 -0
  67. package/src/@modules/@eas/eas.setAttentionTone.ts +40 -0
  68. package/src/@modules/@eas/eas.setEasTone.ts +137 -0
  69. package/src/@modules/@eas/eas.setNoise.ts +31 -0
  70. package/src/@modules/@eas/eas.setRadioEffect.ts +49 -0
  71. package/src/@modules/@eas/eas.setSameHeader.ts +45 -0
  72. package/src/@modules/@stanza/stanza.getAwipsType.ts +46 -0
  73. package/src/@modules/@stanza/stanza.validate.ts +50 -0
  74. package/src/@modules/@utilities/utilities.createHttp.ts +85 -0
  75. package/src/@modules/@utilities/utilities.createWebhook.ts +100 -0
  76. package/src/@modules/@utilities/utilities.getFormattedTime.ts +43 -0
  77. package/src/@modules/@utilities/utilities.getSettings.ts +25 -0
  78. package/src/@modules/@utilities/utilities.getShapeNearestPoint.ts +114 -0
  79. package/src/@modules/@utilities/utilities.setCronSchedule.ts +65 -0
  80. package/src/@modules/@utilities/utilities.setEventEmit.ts +41 -0
  81. package/src/@modules/@utilities/utilities.setListener.ts +30 -0
  82. package/src/@modules/@utilities/utilities.setSettings.ts +42 -0
  83. package/src/@modules/@utilities/utilities.setSleep.ts +33 -0
  84. package/src/@modules/@utilities/utilities.setTimeoutAction.ts +59 -0
  85. package/src/@modules/@utilities/utilities.setWarning.ts +34 -0
  86. package/src/@modules/@xmpp/xmpp.xDeploy.ts +58 -0
  87. package/src/@modules/@xmpp/xmpp.xError.ts +29 -0
  88. package/src/@modules/@xmpp/xmpp.xOffline.ts +38 -0
  89. package/src/@modules/@xmpp/xmpp.xOnline.ts +45 -0
  90. package/src/@modules/@xmpp/xmpp.xReconnect.ts +64 -0
  91. package/src/@modules/@xmpp/xmpp.xStanza.ts +63 -0
  92. package/src/@parsers/@hvtec/hvtec.extract.ts +40 -0
  93. package/src/@parsers/@pvtec/pvtec.expires.ts +26 -0
  94. package/src/@parsers/@pvtec/pvtec.extract.ts +49 -0
  95. package/src/@parsers/@text/text.getDescriptionFromProduct.ts +53 -0
  96. package/src/@parsers/@text/text.getPolygonFromProduct.ts +32 -0
  97. package/src/@parsers/@text/text.getTextFromProduct.ts +43 -0
  98. package/src/@parsers/@text/text.getXML.ts +61 -0
  99. package/src/@parsers/@ugc/ugc.coordinates.ts +110 -0
  100. package/src/@parsers/@ugc/ugc.expiry.ts +32 -0
  101. package/src/@parsers/@ugc/ugc.extract.ts +37 -0
  102. package/src/@parsers/@ugc/ugc.header.ts +30 -0
  103. package/src/@parsers/@ugc/ugc.locations.ts +29 -0
  104. package/src/@parsers/@ugc/ugc.zones.ts +52 -0
  105. package/src/@types/type.event.ts +67 -0
  106. package/src/@types/type.properties.ts +75 -0
  107. package/src/@types/types.attributes.ts +28 -0
  108. package/src/@types/types.compiled.ts +35 -0
  109. package/src/@types/types.hash.ts +24 -0
  110. package/src/@types/types.hvtec.ts +25 -0
  111. package/src/@types/types.pvtec.ts +30 -0
  112. package/src/@types/types.settings.ts +76 -0
  113. package/src/@types/types.stanza.ts +37 -0
  114. package/src/@types/types.ugc.ts +24 -0
  115. package/src/@types/types.webhook.ts +26 -0
  116. package/src/bootstrap.ts +85 -163
  117. package/src/index.ts +47 -216
  118. package/test.js +78 -51
  119. package/tsup.config.ts +1 -0
  120. package/src/@dictionaries/events.ts +0 -168
  121. package/src/@parsers/@events/api.ts +0 -146
  122. package/src/@parsers/@events/cap.ts +0 -123
  123. package/src/@parsers/@events/text.ts +0 -104
  124. package/src/@parsers/@events/ugc.ts +0 -107
  125. package/src/@parsers/@events/vtec.ts +0 -76
  126. package/src/@parsers/events.ts +0 -392
  127. package/src/@parsers/hvtec.ts +0 -46
  128. package/src/@parsers/pvtec.ts +0 -72
  129. package/src/@parsers/stanza.ts +0 -97
  130. package/src/@parsers/text.ts +0 -165
  131. package/src/@parsers/ugc.ts +0 -247
  132. package/src/@submodules/database.ts +0 -201
  133. package/src/@submodules/eas.ts +0 -490
  134. package/src/@submodules/utils.ts +0 -191
  135. package/src/@submodules/xmpp.ts +0 -142
  136. package/src/types.ts +0 -259
@@ -0,0 +1,83 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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, & 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 = pvExtract(message) as TypePVTEC[];
44
+ const hVtec = 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() : ugc.expires ?? new Date(issued.getTime() + 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,
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,95 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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
+ import { updateWebhooks } from "./manager.updateWebhooks";
25
+ import { updateNode } from "./manager.updateNodes";
26
+ import { TypeSettings } from "../@types/types.settings";
27
+
28
+ export const mkEvent = async (event: TypeEvent): Promise<void> => {
29
+ const settings = bootstrap.settings as TypeSettings;
30
+ const features = bootstrap.cache.events.features;
31
+ const map = new Map<string, typeof features[0]>();
32
+
33
+ for (const f of features) {
34
+ const key = f?.properties?.metadata?.tracking;
35
+ if (!key) continue;
36
+ map.set(key, f);
37
+ }
38
+
39
+ const getHash = event.properties.metadata.hash;
40
+ const getTracking = event.properties.metadata.tracking;
41
+ const isEntry = bootstrap.cache.hashes?.find(hash => hash.tracking === getTracking)
42
+ const isHashed = isEntry?.hashes?.includes(getHash) ?? false;
43
+ const getFeature = map.get(getTracking);
44
+
45
+ if (isHashed || event.properties.status_metadata.is_expired) return
46
+ await setHash(event, isEntry)
47
+ const isFilteredLocation = await updateNode(event).then(() => event.properties.metadata.filtered_proximity);
48
+ if (!isFilteredLocation && settings.GlobalSettings.EventFiltering.NodeLocationFiltering) { return }
49
+
50
+ setEventEmit({
51
+ event: `onEventStatus`,
52
+ metadata: {
53
+ type: getFeature ? `Updated` : `New`,
54
+ event: event
55
+ },
56
+ message: `[${getFeature ? 'Updated' : 'New'}] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
57
+ })
58
+ if (settings.GlobalSettings.EventManagement) {
59
+ if (event.properties.status_metadata.is_issued || event.properties.status_metadata.is_updated) {
60
+ if (getFeature) {
61
+ const getIndex = features.indexOf(getFeature);
62
+ const cHistory = getFeature?.properties?.metadata?.history ?? [];
63
+ const cLocations = getFeature?.properties?.locations?.split(";").map((l: string) => l.trim()) ?? [];
64
+ const cUgc = getFeature?.properties?.geocode?.ugc ?? [];
65
+
66
+ const iHistory = event.properties?.metadata?.history ?? [];
67
+ const iLocations = event.properties?.locations?.split(";").map((l: string) => l.trim()) ?? [];
68
+ const iUgc = event.properties?.geocode?.ugc ?? [];
69
+
70
+ const mHistory = [...cHistory, ...iHistory].filter((v, i, a) => a.indexOf(v) === i);
71
+ const mLocations = [...cLocations, ...iLocations].filter((v, i, a) => a.indexOf(v) === i).join('; ');
72
+ const mUgc = [...cUgc, ...iUgc].filter((v, i, a) => a.indexOf(v) === i);
73
+
74
+ bootstrap.cache.events.features[getIndex] = {
75
+ ...event,
76
+ properties: {
77
+ ...event.properties,
78
+ metadata: {
79
+ ...event?.properties?.metadata,
80
+ history: mHistory
81
+ },
82
+ locations: mLocations,
83
+ geocode: {
84
+ ...event?.properties?.geocode,
85
+ ugc: mUgc
86
+ },
87
+ }
88
+ };
89
+ } else {
90
+ features.push(event)
91
+ }
92
+ }
93
+ }
94
+ updateWebhooks(event)
95
+ }
@@ -0,0 +1,46 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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 { updateWebhooks } from "./manager.updateWebhooks";
24
+
25
+ export const rmEvent = (event: TypeEvent): void => {
26
+ const getEvent = bootstrap.cache.events.features.find(f => f?.properties?.metadata?.tracking === event?.properties?.metadata?.tracking);
27
+ if (getEvent) {
28
+ setEventEmit({
29
+ event: `onEventStatus`,
30
+ metadata: {
31
+ type: `Removed`,
32
+ event: event
33
+ },
34
+ message: `[Removed] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
35
+ })
36
+ setEventEmit({ event: `onExpiredProduct`, metadata: event })
37
+ updateWebhooks(event)
38
+ bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(getEvent), 1);
39
+ bootstrap.cache.hashes = bootstrap.cache.hashes.filter(hash => hash.tracking !== event.properties.metadata.tracking);
40
+ }
41
+ setEventEmit({
42
+ event: `onEventCache`,
43
+ metadata: bootstrap.cache.events,
44
+ limited: true
45
+ })
46
+ }
@@ -0,0 +1,37 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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 = async (event: TypeEvent, entry: TypeHash): Promise<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,55 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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 { TypeEvent } from "../@types/type.event";
23
+ import { bootstrap } from "../bootstrap"
24
+
25
+
26
+ export const updateNode = async (selectedEvent?: TypeEvent): Promise<void> => {
27
+ const events = bootstrap.cache.events.features;
28
+ const ttl = bootstrap.settings.GlobalSettings.NodeTTL * 1e3;
29
+ let total = 0;
30
+
31
+ async function update(evt: TypeEvent) {
32
+ const lastUpdate = evt?.properties?.metadata?.updated ?? null;
33
+ if (lastUpdate != null && (Date.now() - lastUpdate) < ttl) {
34
+ return evt;
35
+ }
36
+ const node = await getEventNodes(evt);
37
+ if (node.nodes.length > 0) {
38
+ total++
39
+ }
40
+ evt.properties.metadata.nodes = node.nodes
41
+ evt.properties.metadata.filtered_proximity = node.filtered
42
+ evt.properties.metadata.updated = node.updated
43
+ }
44
+ if (!selectedEvent) { await Promise.all(events.map(async (evt) => { await update(evt) })) }
45
+ if (selectedEvent) { await update(selectedEvent) }
46
+ if (total > 0) {
47
+ setEventEmit({
48
+ event: `onNodeUpdate`,
49
+ metadata: {
50
+ type: `global-update`,
51
+ updated: total
52
+ },
53
+ })
54
+ }
55
+ }
@@ -0,0 +1,50 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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 { createWebhook } from "../@modules/@utilities/utilities.createWebhook";
21
+ import { TypeEvent } from "../@types/type.event";
22
+ import { TypeWebhook } from "../@types/types.webhook";
23
+ import { bootstrap } from "../bootstrap"
24
+
25
+
26
+ export const updateWebhooks = async (event: TypeEvent): Promise<void> => {
27
+ const settings = bootstrap.settings;
28
+ const webhooks = settings.WebhookSettings as TypeWebhook[];
29
+ const eventName = event.properties.event;
30
+ for (const socket of webhooks) {
31
+ const events = socket.events;
32
+ if (!events || events.length === 0) {
33
+ await createWebhook({ webhook: socket, event });
34
+ continue;
35
+ }
36
+ const matched = events.some(pattern => {
37
+ if (!pattern) return false;
38
+ if (pattern === "*" || pattern === eventName) return true;
39
+ if (pattern.includes("*")) {
40
+ const regex = "^" +
41
+ pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$";
42
+ return new RegExp(regex).test(eventName);
43
+ }
44
+ return false;
45
+ });
46
+ if (matched) {
47
+ await createWebhook({ webhook: socket, event });
48
+ }
49
+ }
50
+ };
@@ -0,0 +1,48 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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
+ }
@@ -0,0 +1,45 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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 fs from 'fs'
21
+ import sqlite3 from 'better-sqlite3'
22
+ import { TypeSettings } from "../../@types/types.settings"
23
+ import { bootstrap } from "../../bootstrap"
24
+ import { setWarning } from '../@utilities/utilities.setWarning'
25
+ import { importShapefiles } from './database.shapefiles'
26
+
27
+ export const initializeDatabase = async (): Promise<void> => {
28
+ const settings = bootstrap.settings as TypeSettings;
29
+ try {
30
+ if (!fs.existsSync(settings.Database)) {
31
+ fs.writeFileSync(settings.Database, '')
32
+ setWarning({ message: `Creating new database at ${settings.Database}` })
33
+ }
34
+ bootstrap.database = new sqlite3(settings.Database);
35
+ bootstrap.database
36
+ .prepare(`CREATE TABLE IF NOT EXISTS stanzas ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, issued TEXT, stanza TEXT )`)
37
+ .run();
38
+ bootstrap.database
39
+ .prepare(`CREATE TABLE IF NOT EXISTS shapefiles (id TEXT PRIMARY KEY, location TEXT, geometry TEXT)`)
40
+ .run();
41
+ await importShapefiles();
42
+ } catch (error) {
43
+ setWarning({ message: `An error occurred while initializing the database: ${error.message}` })
44
+ }
45
+ }
@@ -0,0 +1,96 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & 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 fs from 'fs'
21
+ import { resolve, extname} from 'path'
22
+ import { loadAsync } from 'jszip'
23
+ import { read } from 'shapefile'
24
+ import { TypeSettings } from "../../@types/types.settings"
25
+ import { bootstrap } from "../../bootstrap"
26
+ import { setSleep } from '../@utilities/utilities.setSleep'
27
+ import { setWarning } from '../@utilities/utilities.setWarning'
28
+ import { shapefileLinks } from '../../@dictionaries/dictionaries.shapefileLinks'
29
+
30
+ export const importShapefiles = async (): Promise<void> => {
31
+ const settings = bootstrap.settings as TypeSettings;
32
+ try {
33
+ const tShapefiles = bootstrap.database
34
+ .prepare(`SELECT COUNT(*) AS count FROM shapefiles`)
35
+ .get().count;
36
+ if (tShapefiles === 0) {
37
+ await setSleep({timeout: 1e3});
38
+ setWarning({ message: `Shapefiles are currently building, please DO NOT close your terminal. The shapefiles will not finish and will remain incomplete. If you do mess up, you will need to delete ${settings.Database} and restart the application.` })
39
+ for (const shapefile of shapefileLinks) {
40
+ const response = await fetch(shapefile.link);
41
+ const arrayBuff = await response.arrayBuffer();
42
+ const content = await loadAsync(arrayBuff);
43
+ const directory = resolve(__dirname, `../../shapefiles`);
44
+ if (!fs.existsSync(directory)) {
45
+ fs.mkdirSync(directory, { recursive: true });
46
+ }
47
+ for (const file of Object.keys(content.files)) {
48
+ if (file.endsWith('.shp') || file.endsWith('.dbf')) {
49
+ const data = await content.files[file].async(`nodebuffer`)
50
+ const output = resolve(directory, `${shapefile?.name ?? ``}_${shapefile?.id ?? ``}${extname(file)}`)
51
+ fs.writeFileSync(output, data)
52
+ }
53
+ }
54
+ const filepath = resolve(__dirname, '../../shapefiles', shapefile.name + '_' + shapefile.id)
55
+ const { features } = await read(
56
+ filepath,
57
+ filepath,
58
+ );
59
+ setWarning({ message: `Importing ${features.length} features from ${shapefile.name}_${shapefile.id}` })
60
+ const insert = bootstrap.database
61
+ .prepare(`INSERT OR REPLACE INTO shapefiles (id, location, geometry) VALUES (?, ?, ?)`)
62
+ const transaction = bootstrap.database.transaction((entries: any[]) => {
63
+ for (const entry of entries) {
64
+ const { properties, geometry } = entry;
65
+ let final: string, location: string;
66
+ if (properties.FIPS) {
67
+ final = `${properties.STATE}${shapefile.id}${properties.FIPS.substring(2)}`;
68
+ location = `${properties.COUNTYNAME}, ${properties.STATE}`;
69
+ }
70
+ else if (properties.FULLSTAID) {
71
+ final = `${properties.ST}${shapefile.id}${properties.WFO}`;
72
+ location = `${properties.CITY}, ${properties.STATE}`;
73
+ }
74
+ else if (properties.STATE) {
75
+ final = `${properties.STATE}${shapefile.id}${properties.ZONE ?? properties.SITE_ID}`;
76
+ location = `${properties.NAME ?? `${properties.RFC_NAME} ${properties.RFC_CITY}`}, ${properties.STATE}`;
77
+ }
78
+ else {
79
+ final = properties.ID ?? properties.WFO
80
+ location = properties.NAME;
81
+ }
82
+ insert.run(final, location, JSON.stringify(geometry));
83
+ }
84
+ })
85
+ fs.unlinkSync(`${filepath}.shp`)
86
+ fs.unlinkSync(`${filepath}.dbf`)
87
+ setWarning({ message: `Cleaned up temporary files for ${shapefile.name}_${shapefile.id}` })
88
+ transaction(features)
89
+ }
90
+ setWarning({ message: `Shapefiles have finished compiling, you can now continue and close this terminal` })
91
+ fs.rm(resolve(__dirname, '../../shapefiles'), { recursive: true, force: true }, () => {});
92
+ }
93
+ } catch (error) {
94
+ setWarning( {message: `An error occurred while compiling shapefiles: ${error.message}` })
95
+ }
96
+ }