@atmosx/event-product-parser 3.0.62 → 3.0.75

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 (179) hide show
  1. package/.github/docs/docs-functions.md +1 -1
  2. package/.github/docs/docs-general-configurations.md +1 -11
  3. package/.github/docs/docs-integrations.md +3 -2
  4. package/README.md +10 -8
  5. package/dist/cjs/index.cjs +24482 -7207
  6. package/dist/esm/index.mjs +24275 -7003
  7. package/package.json +56 -47
  8. package/pnpm-workspace.yaml +4 -0
  9. package/src/bootstrap.ts +65 -48
  10. package/src/{@building → building}/CreateEvent.ts +22 -24
  11. package/src/{@building → building}/GetCleanedEvent.ts +2 -2
  12. package/src/{@building → building}/GetEventAttachments.ts +14 -12
  13. package/src/building/GetEventDirection.ts +28 -0
  14. package/src/{@building → building}/GetEventEnhancedName.ts +5 -8
  15. package/src/{@building → building}/GetEventGeometry.ts +19 -13
  16. package/src/{@building → building}/GetEventHeader.ts +13 -13
  17. package/src/{@building → building}/GetEventNodes.ts +22 -20
  18. package/src/{@building → building}/GetEventOffice.ts +13 -13
  19. package/src/building/GetEventPopulation.ts +58 -0
  20. package/src/building/GetEventProperties.ts +106 -0
  21. package/src/{@building → building}/GetEventSignature.ts +9 -9
  22. package/src/{@building → building}/GetEventTags.ts +3 -3
  23. package/src/building/GetEventTheme.ts +26 -0
  24. package/src/building/GetEventTracking.ts +64 -0
  25. package/src/components/audio/GenerateAudioMessage.ts +149 -0
  26. package/src/{@modules/@eas → components/audio/components}/GetCleanDescription.ts +2 -2
  27. package/src/{@modules/@eas → components/audio/components}/GetFloatPCM16.ts +2 -2
  28. package/src/{@modules/@eas → components/audio/components}/GetMergedPCM16.ts +2 -2
  29. package/src/{@modules/@eas → components/audio/components}/GetPCM16.ts +13 -8
  30. package/src/{@modules/@eas → components/audio/components}/GetPCMToFloat.ts +2 -2
  31. package/src/{@modules/@eas → components/audio/components}/GetSampledPCM16.ts +14 -8
  32. package/src/{@modules/@eas → components/audio/components}/GetTTS.ts +17 -10
  33. package/src/{@modules/@eas → components/audio/components}/GetWavPCM16.ts +7 -7
  34. package/src/{@modules/@eas → components/audio/components}/SetAFSK.ts +13 -8
  35. package/src/{@modules/@eas → components/audio/components}/SetAsciiToBits.ts +2 -2
  36. package/src/{@modules/@eas → components/audio/components}/SetAttentionTone.ts +11 -6
  37. package/src/{@modules/@eas → components/audio/components}/SetNoise.ts +12 -7
  38. package/src/{@modules/@eas → components/audio/components}/SetRadioEffect.ts +12 -7
  39. package/src/{@modules/@eas → components/audio/components}/SetSameHeader.ts +22 -14
  40. package/src/{@modules/@utilities/SetWarning.ts → components/database/CreateQuery.ts} +18 -13
  41. package/src/{@modules/@database → components/database}/GetCachedEvents.ts +18 -15
  42. package/src/components/database/ImportBoundaries.ts +168 -0
  43. package/src/{@modules/@database → components/database}/ImportBroadcastify.ts +14 -24
  44. package/src/components/database/ImportCities.ts +87 -0
  45. package/src/{@modules/@database → components/database}/ImportShapefiles.ts +23 -26
  46. package/src/{@modules/@database → components/database}/ImportStanza.ts +15 -19
  47. package/src/components/database/InitializeDatabase.ts +71 -0
  48. package/src/components/images/GenerateGraphic.ts +242 -0
  49. package/src/components/images/components/CreateRectangle.ts +22 -0
  50. package/src/components/images/components/CreateText.ts +22 -0
  51. package/src/components/images/modules/CreateSVG.ts +37 -0
  52. package/src/components/images/modules/GetGeographicalBoundaries.ts +72 -0
  53. package/src/components/images/modules/GetGeographicalCities.ts +58 -0
  54. package/src/components/images/modules/GetGeographicalEvents.ts +48 -0
  55. package/src/components/images/modules/GetGeometryBounds.ts +82 -0
  56. package/src/components/images/modules/GetParsedBoundary.ts +58 -0
  57. package/src/components/images/modules/GetSVGPath.ts +53 -0
  58. package/src/components/images/modules/NormalizePolygon.ts +57 -0
  59. package/src/{@modules/@stanza → components/stanza}/GetAwipsType.ts +16 -17
  60. package/src/{@modules/@stanza → components/stanza}/ValidateStanza.ts +27 -15
  61. package/src/{@modules/@utilities → components/utilities}/CreateHttp.ts +26 -26
  62. package/src/{@parsers/@text → components/utilities}/GetEmbededText.ts +8 -6
  63. package/src/{@modules/@utilities → components/utilities}/GetFormattedTime.ts +2 -2
  64. package/src/{@modules/@utilities → components/utilities}/GetLatestIssuance.ts +2 -2
  65. package/src/{@modules/@utilities → components/utilities}/GetMatched.ts +10 -5
  66. package/src/{@modules/@utilities → components/utilities}/GetShapeNearestPoint.ts +24 -19
  67. package/src/{@parsers/@text → components/utilities}/GetStringText.ts +9 -9
  68. package/src/components/utilities/GetUnionPolygon.ts +36 -0
  69. package/src/components/utilities/QueueManager.ts +70 -0
  70. package/src/components/utilities/SetCronSchedule.ts +106 -0
  71. package/src/{@modules/@utilities → components/utilities}/SetDebug.ts +12 -12
  72. package/src/components/utilities/SetEventEmit.ts +42 -0
  73. package/src/{@modules/@utilities → components/utilities}/SetSettings.ts +7 -7
  74. package/src/{@modules/@utilities → components/utilities}/SetSleep.ts +5 -5
  75. package/src/components/utilities/SetTimeoutAction.ts +64 -0
  76. package/src/components/utilities/SetWarning.ts +47 -0
  77. package/src/{@modules/@xmpp → components/xmpp}/DeployXMPP.ts +20 -20
  78. package/src/{@core/CreateListener.ts → components/xmpp/ErrorXMPP.ts} +8 -5
  79. package/src/{@modules/@xmpp → components/xmpp}/OfflineXMPP.ts +13 -13
  80. package/src/{@modules/@xmpp → components/xmpp}/OnlineXMPP.ts +18 -18
  81. package/src/components/xmpp/ReconnectXMPP.ts +64 -0
  82. package/src/{@modules/@xmpp → components/xmpp}/StanzaXMPP.ts +25 -25
  83. package/src/{@core → core}/ClearEvents.ts +9 -9
  84. package/src/{@core → core}/GetEvents.ts +4 -4
  85. package/src/{@core → core}/GetNodes.ts +4 -4
  86. package/src/{@core → core}/GetRandomEvent.ts +4 -4
  87. package/src/{@core → core}/GetVersion.ts +4 -4
  88. package/src/{@core → core}/ManualEvent.ts +23 -24
  89. package/src/{@core → core}/QueryStanza.ts +12 -11
  90. package/src/core/SetNode.ts +87 -0
  91. package/src/{@core → core}/StartService.ts +21 -20
  92. package/src/{@core → core}/StopService.ts +10 -10
  93. package/src/{@enums → enums}/AWIPS.ts +2 -2
  94. package/src/{@enums → enums}/Actions.ts +2 -2
  95. package/src/{@enums → enums}/Cancellation.ts +2 -2
  96. package/src/{@enums → enums}/Causes.ts +2 -2
  97. package/src/{@enums → enums}/Correlations.ts +2 -2
  98. package/src/{@enums → enums}/Enhanced.ts +4 -3
  99. package/src/{@enums → enums}/Events.ts +2 -2
  100. package/src/{@enums → enums}/Expressions.ts +3 -3
  101. package/src/{@enums → enums}/GlobalFilter.ts +2 -2
  102. package/src/{@enums → enums}/Hail.ts +2 -2
  103. package/src/{@enums → enums}/ICAO.ts +2 -2
  104. package/src/{@enums → enums}/Matches.ts +8 -3
  105. package/src/{@enums → enums}/Products.ts +2 -2
  106. package/src/{@enums → enums}/Records.ts +2 -2
  107. package/src/{@enums → enums}/Severity.ts +2 -2
  108. package/src/{@enums → enums}/Shapefiles.ts +2 -2
  109. package/src/{@enums → enums}/States.ts +68 -4
  110. package/src/{@enums → enums}/Status.ts +2 -2
  111. package/src/{@enums → enums}/Strings.ts +2 -2
  112. package/src/{@enums → enums}/Tags.ts +9 -4
  113. package/src/{@enums → enums}/Testing.ts +2 -2
  114. package/src/enums/Themes.ts +70 -0
  115. package/src/events/ParseAPI.ts +133 -0
  116. package/src/{@events → events}/ParseText.ts +24 -22
  117. package/src/{@events → events}/ParseUGC.ts +27 -26
  118. package/src/{@events → events}/ParseVTEC.ts +38 -37
  119. package/src/index.ts +57 -37
  120. package/src/{@manager → manager}/MakeEvents.ts +38 -47
  121. package/src/manager/RemoveEvent.ts +74 -0
  122. package/src/{@manager → manager}/SetHash.ts +18 -13
  123. package/src/{@manager → manager}/UpdateEvents.ts +12 -12
  124. package/src/{@manager → manager}/UpdateNode.ts +14 -14
  125. package/src/{@manager → manager}/ValidateEvents.ts +55 -45
  126. package/src/{@parsers/@hvtec → parsers/hvtec}/HVExtract.ts +11 -11
  127. package/src/{@parsers/@text → parsers/text}/GetDescriptionFromProduct.ts +20 -21
  128. package/src/parsers/text/GetPolygonFromProduct.ts +71 -0
  129. package/src/{@parsers/@text → parsers/text}/GetTextFromProduct.ts +12 -12
  130. package/src/parsers/ugc/GetCache.ts +24 -0
  131. package/src/{@parsers/@ugc → parsers/ugc}/GetExpiry.ts +2 -2
  132. package/src/{@parsers/@ugc/GetUGCHeader.ts → parsers/ugc/GetHeader.ts} +4 -4
  133. package/src/{@parsers/@ugc → parsers/ugc}/GetLocations.ts +10 -10
  134. package/src/parsers/ugc/GetZonePolygon.ts +73 -0
  135. package/src/{@parsers/@ugc → parsers/ugc}/GetZones.ts +3 -3
  136. package/src/{@parsers/@ugc → parsers/ugc}/SetCache.ts +13 -8
  137. package/src/{@parsers/@ugc → parsers/ugc}/UGCExtract.ts +14 -14
  138. package/src/{@parsers/@pvtec → parsers/vtec}/GetExpiry.ts +2 -2
  139. package/src/parsers/vtec/VTECExtract.ts +49 -0
  140. package/src/{@types → static}/Attributes.ts +2 -3
  141. package/src/{@types → static}/Event.ts +8 -7
  142. package/src/{@types → static}/Properties.ts +17 -3
  143. package/src/{@types → static}/Stanza.ts +2 -2
  144. package/src/tasks/CreateTasks.ts +116 -0
  145. package/src/tasks/TaskGenerateJSON.ts +34 -0
  146. package/src/tasks/TaskGenerateText.ts +34 -0
  147. package/src/tasks/TaskSendNTFY.ts +95 -0
  148. package/src/tasks/TaskSendWebhook.ts +107 -0
  149. package/src/{@types → types}/Actions.ts +3 -3
  150. package/src/{@types → types}/HVTEC.ts +6 -6
  151. package/src/{@types → types}/Hash.ts +5 -5
  152. package/src/types/Nodes.ts +29 -0
  153. package/src/{@types → types}/Settings.ts +17 -8
  154. package/src/{@types → types}/StanzaCompiled.ts +15 -15
  155. package/src/{@types → types}/UGC.ts +5 -5
  156. package/src/{@modules/@utilities/GetSettings.ts → types/VTEC.ts} +12 -7
  157. package/tools/build.js +47 -0
  158. package/tsconfig.json +28 -1
  159. package/src/@building/GetEventProperties.ts +0 -96
  160. package/src/@building/GetEventTracking.ts +0 -68
  161. package/src/@core/SetNode.ts +0 -81
  162. package/src/@events/ParseAPI.ts +0 -117
  163. package/src/@manager/RemoveEvent.ts +0 -70
  164. package/src/@manager/Tasks.ts +0 -246
  165. package/src/@modules/@database/InitializeDatabase.ts +0 -59
  166. package/src/@modules/@eas/GenerateEASMessage.ts +0 -144
  167. package/src/@modules/@utilities/SetCronSchedule.ts +0 -94
  168. package/src/@modules/@utilities/SetEventEmit.ts +0 -41
  169. package/src/@modules/@utilities/SetListener.ts +0 -30
  170. package/src/@modules/@utilities/SetTimeoutAction.ts +0 -64
  171. package/src/@modules/@xmpp/ErrorXMPP.ts +0 -27
  172. package/src/@modules/@xmpp/ReconnectXMPP.ts +0 -64
  173. package/src/@parsers/@pvtec/VTECExtract.ts +0 -49
  174. package/src/@parsers/@text/GetPolygonFromProduct.ts +0 -53
  175. package/src/@parsers/@text/GetXML.ts +0 -61
  176. package/src/@parsers/@ugc/GetCache.ts +0 -24
  177. package/src/@parsers/@ugc/GetZonePolygon.ts +0 -111
  178. package/src/@types/VTEC.ts +0 -30
  179. package/tsup.config.ts +0 -16
@@ -1,117 +0,0 @@
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 { TypeStanzaCompiled } from "../@types/StanzaCompiled"
21
- import { TypePVTEC } from "../@types/VTEC";
22
- import { EnumICAO } from "../@enums/ICAO";
23
- import { bootstrap } from "../bootstrap";
24
- import { GetEventTracking } from "../@building/GetEventTracking";
25
- import { VTECExtract } from "../@parsers/@pvtec/VTECExtract"
26
- import { GetEventTags } from "../@building/GetEventTags";
27
- import { GetTextFromProduct } from "../@parsers/@text/GetTextFromProduct";
28
- import { SetDebug } from "../@modules/@utilities/SetDebug";
29
-
30
- export const ParseAPI = async (stanza: TypeStanzaCompiled): Promise<void> => {
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 = VTECExtract(feature?.properties?.parameters?.VTEC?.[0]) ?? null as TypePVTEC[]
35
- bootstrap.cache.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
- locations_array: feature?.properties?.areaDesc ? feature?.properties?.areaDesc.split(';') : [],
49
- description: feature?.properties?.description ?? null,
50
- attributes: feature?.properties?.attributes ?? {},
51
- geocode: {
52
- office: {
53
- office: pVtec ? pVtec?.[0]?.tracking.split(`.`)[0] : null,
54
- name: EnumICAO[pVtec ? pVtec?.[0]?.tracking.split(`.`)[0] : null] ?? null,
55
- },
56
- organization: feature?.properties?.parameters?.WMOidentifier?.[0],
57
- ugc: feature?.properties?.geocode?.UGC ?? [],
58
- polygon: feature?.geometry?.coordinates.length > 0 ? Buffer.from(JSON.stringify([feature?.geometry?.coordinates[0]])).toString('base64') : null,
59
- polygon_generated: feature?.geometry?.coordinates.length > 0 ? true : false,
60
- },
61
- parameters: {
62
- tags: GetEventTags(feature?.properties?.description),
63
- instructions: feature?.properties?.instruction ?? null,
64
- source: GetTextFromProduct({ message: feature?.properties?.description, find: [`SOURCE...`], removal: [`.`]}) ?? null,
65
- hazards: GetTextFromProduct({ message: feature?.properties?.description, find: [`HAZARD...`], removal: [`.`]}) ?? null,
66
- impacts: GetTextFromProduct({ message: feature?.properties?.description, find: [`IMPACT...`], removal: [`.`]}) ?? null,
67
- estimated_hail_size: feature?.properties?.parameters?.maxHailSize?.[0] ?? null,
68
- estimated_wind_gusts: feature?.properties?.parameters?.maxWindGust?.[0] ?? null,
69
- damage_threat: feature?.properties?.parameters?.thunderstormDamageThreat?.[0] ?? null,
70
- tornado_threat: feature?.properties?.parameters?.tornadoDetection?.[0] ?? null,
71
- flood_threat: feature?.properties?.parameters?.floodDetection?.[0] ?? null,
72
- wind_threat: feature?.properties?.parameters?.windThreat?.[0] ?? null,
73
- hail_threat: feature?.properties?.parameters?.hailThreat?.[0] ?? null,
74
- },
75
- discussion_parameters: {
76
- discussion_number: GetTextFromProduct({ message: feature?.properties?.description, find: [`Mesoscale Discussion `], removal: [`Mesoscale Discussion`, `Number`, `...`] })?.toString()?.padStart(4, "0") ?? null,
77
- discussion_concerning: GetTextFromProduct({ message: feature?.properties?.description, find: [`Concerning...`] }) ?? null,
78
- discussion_max_tornado: GetTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
79
- discussion_max_hail: GetTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
80
- discussion_max_wind: GetTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
81
- discussion_watch_issuance: GetTextFromProduct({ message: feature?.properties?.description, find: [`Probability of Watch Issuance...`], removal: [`percent`]}) ?? null,
82
- },
83
- watch_parameters: {
84
- watch_number: (pVtec?.[0]?.is_watch) && (GetTextFromProduct({ message: feature?.properties?.description, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim()?.toString()?.padStart(4, "0") ?? pVtec?.[0]?.tracking?.slice(-4)?.toString()?.padStart(4, "0") ?? null),
85
- watch_type: feature?.properties?.description.includes(`TORNADO WATCH`) ? `Tornado` : feature?.properties?.description.includes(`SEVERE`) ? `Severe` : null,
86
- additional_tornadoes_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
87
- strong_tornadoes_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
88
- severe_wind_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
89
- severe_hail_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
90
- hail_2in_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], removal: [`%`, `<`, `:`] }) ?? null,
91
- combined_hail_wind_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
92
- max_hail_in: GetTextFromProduct({ message: feature?.properties?.description, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] }) ?? null,
93
- max_wind_surface: GetTextFromProduct({ message: feature?.properties?.description, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] }) ?? null,
94
- max_tops_x100feet: GetTextFromProduct({ message: feature?.properties?.description, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] }) ?? null,
95
- pds_watch: (GetTextFromProduct({ message: feature?.properties?.description, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`)
96
- },
97
- metadata: {
98
- ms: performance.now() - tick,
99
- source: `events.api`,
100
- tracking: GetEventTracking({ type: `API`, organization: { wmoidentifier: feature?.properties?.parameters?.WMOidentifier?.[0], featureId: feature?.id}, vtec: pVtec?.[0]}),
101
- header: `ZCZC-ATMOSX-${feature?.properties?.parameters?.WMOidentifier}`,
102
- vtec: pVtec?.[0],
103
- hvtec: null,
104
- raw: feature?.properties?.description,
105
- history: [
106
- {
107
- description: feature?.properties?.description,
108
- issued: feature?.properties?.sent ? new Date(feature?.properties?.sent).toISOString() : null,
109
- status: feature?.properties?.messageType ?? null,
110
- }
111
- ]
112
- }
113
- }
114
- })
115
- SetDebug({ title: `ParseAPI`, message: `${Math.round(performance.now() - tick)}ms` })
116
- }
117
- }
@@ -1,70 +0,0 @@
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/Event";
21
- import { EnumStrings } from "../@enums/Strings";
22
- import { bootstrap } from "../bootstrap"
23
- import { SetEventEmit } from "../@modules/@utilities/SetEventEmit";
24
- import { SetTimeoutAction } from "../@modules/@utilities/SetTimeoutAction";
25
- import { Tasks } from "./Tasks";
26
-
27
-
28
- export const RemoveEvent = async (event: TypeEvent, isTimeBasedExpiration: boolean):Promise<void> => {
29
- const gTracking = event.properties.metadata.tracking;
30
- const isTrackingEventLogged = bootstrap.cache.events.features
31
- .find(f => f?.properties?.metadata?.tracking === gTracking);
32
- const isStatement = event.properties.status_metadata.is_statement;
33
-
34
- if (isTrackingEventLogged) {
35
- event.properties.expires = new Date().toISOString();
36
- event.properties.status = `Expired`;
37
- event.properties.status_metadata.is_expired = true;
38
-
39
- const description = isTimeBasedExpiration ? EnumStrings.cancellation
40
- .replace(`{SENDER}`, event.properties.geocode.office.name)
41
- .replace(`{EVENT}`, event.properties.event) : event.properties.description
42
- event.properties.description = description;
43
- event.properties.metadata.raw = isTimeBasedExpiration ? description : event.properties.metadata.raw;
44
- event.properties.metadata.history.push({
45
- description: isTimeBasedExpiration ? description : event.properties.description,
46
- issued: event.properties.expires,
47
- status: event.properties.status
48
- })
49
-
50
- bootstrap.cache.events.features
51
- .splice(bootstrap.cache.events.features.indexOf(isTrackingEventLogged), 1);
52
- bootstrap.cache.hashes = bootstrap.cache.hashes
53
- .filter(hash => hash.tracking !== gTracking);
54
-
55
- if (!isStatement) {
56
- SetEventEmit({
57
- event: `onEventStatus`,
58
- metadata: { type: `Removed`, event: event },
59
- message: `[Removed] ${event.properties.event} (${event.properties.status}) (${gTracking})`
60
- })
61
- await Tasks([event])
62
- }
63
- SetTimeoutAction({ identifier: gTracking, expire: true })
64
- }
65
- SetEventEmit({
66
- event: `onEventCache`,
67
- metadata: bootstrap.cache.events,
68
- limited: true
69
- })
70
- }
@@ -1,246 +0,0 @@
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/Settings";
21
- import { TypeEvent } from "../@types/Event";
22
- import { TypeActions } from "../@types/Actions";
23
- import { bootstrap } from "../bootstrap"
24
- import { GenerateEASMessage } from "../@modules/@eas/GenerateEASMessage"
25
- import { SetTimeoutAction } from "../@modules/@utilities/SetTimeoutAction";
26
- import { GetEmebedText } from "../@parsers/@text/GetEmbededText";
27
- import { GetStringText } from "../@parsers/@text/GetStringText";
28
- import { GetCleanedEvent } from "../@building/GetCleanedEvent"
29
- import { CreateHttp } from "../@modules/@utilities/CreateHttp";
30
- import { SetDebug } from "../@modules/@utilities/SetDebug";
31
- import { GetMatched } from "../@modules/@utilities/GetMatched";
32
- import { mkdir, writeFile, readFile, appendFile } from "fs/promises";
33
-
34
- export const Tasks = async (events: TypeEvent[]): Promise<void> => {
35
- const tick = performance.now()
36
- const settings = bootstrap.settings as TypeSettings;
37
- const notifyServer = settings.NotifyServer;
38
- const actions = settings.ActionSettings as TypeActions[];
39
- for (const event of events) {
40
- const properties = event.properties;
41
- const hasActions = Array.isArray(actions) && actions.length > 0;
42
- if (!hasActions) {
43
- SetDebug({ title: `Tasks`, message: `${Math.round(performance.now() - tick)}ms` });
44
- return;
45
- }
46
- const metadata = {
47
- text: null,
48
- eas: null,
49
- json: null,
50
- name: properties.event,
51
- status: properties.status,
52
- description: properties.description,
53
- tracking: properties.metadata.tracking,
54
- header: properties.metadata.header,
55
- raw: properties.metadata.raw,
56
- expired: properties.status_metadata.is_expired,
57
- attachments: properties.metadata.attachments
58
- }
59
-
60
- const archiveSettings = settings.GlobalSettings?.ArchiveSettings;
61
- const textArchiveDir = archiveSettings?.TextDirectory;
62
- const jsonArchiveDir = archiveSettings?.JSONDirectory;
63
- const eventBaseName = `${metadata.name}_${metadata.tracking}`;
64
- const easTitle = `${metadata.name}_${metadata.status}_${metadata.tracking}`;
65
- const cleanedEventText = JSON.stringify(GetCleanedEvent(event), null, 2);
66
- const stringText = GetStringText(event);
67
- const embedText = GetEmebedText(event);
68
-
69
- for (const action of actions) {
70
- const events = action?.Events;
71
- const webhook = action?.Webhook;
72
- const notify = action?.NotificationServer;
73
- const uploads = action?.Uploads
74
- const isMatched = GetMatched(events ?? [], metadata.name)
75
-
76
- if (events?.length == 0 || isMatched) {
77
- const t = performance.now()
78
-
79
- if (uploads?.EAS && !metadata.eas) {
80
- metadata.eas = await GenerateEASMessage({
81
- title: easTitle,
82
- message: metadata.description,
83
- header: metadata.header
84
- });
85
- SetDebug({
86
- title: "Tasks/EAS",
87
- message: `${Math.round(performance.now() - t)}ms`
88
- });
89
- }
90
-
91
- if (uploads?.TEXT && metadata.text === null) {
92
- const t = performance.now()
93
- if (textArchiveDir) {
94
- const file = (`${textArchiveDir}/${eventBaseName}.txt`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
95
- await mkdir(textArchiveDir, { recursive: true });
96
- await appendFile(file, `${"\n".repeat(7)}${metadata.raw}`);
97
- SetDebug({
98
- title: "Tasks/TEXT",
99
- message: `${Math.round(performance.now() - t)}ms`
100
- });
101
- }
102
- metadata.text = metadata.raw;
103
- }
104
-
105
- if (uploads?.JSON && metadata.json === null) {
106
- const t = performance.now()
107
- if (jsonArchiveDir) {
108
- const file = (`${jsonArchiveDir}/${eventBaseName}.json`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
109
- await mkdir(jsonArchiveDir, { recursive: true });
110
- await writeFile(file, cleanedEventText);
111
- SetDebug({
112
- title: "Tasks/JSON",
113
- message: `${Math.round(performance.now() - t)}ms`
114
- });
115
- }
116
- metadata.json = cleanedEventText;
117
- }
118
-
119
- if (notifyServer?.Enabled && notify?.Enabled && notify?.Topic) {
120
- let buttons = [];
121
- const t = performance.now()
122
- const auth = notifyServer?.Credentials?.Username && notifyServer?.Credentials?.Password ? { username: notifyServer?.Credentials?.Username, password: notifyServer?.Credentials?.Password } : undefined;
123
- const image = metadata.attachments?.find(a => a.name === "Image: Graphic");
124
-
125
-
126
- if (notifyServer?.MediaStorage?.EAS) {
127
- if (metadata.eas) {
128
- buttons.push({
129
- "action": "view",
130
- "label": "Listen",
131
- "url": `${notifyServer?.MediaStorage?.EAS}/${metadata.name}_${metadata.status}_${metadata.tracking}.wav`,
132
- })
133
- }
134
- }
135
- if (metadata.json) {
136
- buttons.push({
137
- "action": "view",
138
- "label": "View JSON",
139
- "url": `${notifyServer?.MediaStorage?.JSON}/${metadata.name}_${metadata.tracking}.json`,
140
- })
141
- }
142
- if (metadata.text) {
143
- buttons.push({
144
- "action": "view",
145
- "label": "View Text",
146
- "url": `${notifyServer?.MediaStorage?.TEXT}/${metadata.name}_${metadata.tracking}.txt`,
147
- })
148
- }
149
- if (image) {
150
- buttons.push({
151
- "action": "view",
152
- "label": "View Image",
153
- "url": image.link,
154
- })
155
- }
156
- await CreateHttp({
157
- url: `${notifyServer?.Server?.replace(/\/$/, "")}/${notify.Topic}`,
158
- timeout: 15_000,
159
- method: "PUT",
160
- ...(auth && { auth }),
161
- headers: {
162
- "Title": `${metadata.name} (${metadata.status})`,
163
- "Tags": properties.parameters.tags?.join(",") ?? "N/A",
164
- "Priority": notify?.Priority ?? "5",
165
- ... (buttons.length > 0 && { "Actions": JSON.stringify(buttons) }),
166
- },
167
- body: stringText
168
- })
169
- SetDebug({
170
- title: "Tasks/NTFY",
171
- message: `${Math.round(performance.now() - t)}ms`
172
- });
173
- }
174
-
175
- if (webhook?.Enabled && webhook?.Destination) {
176
- const t = performance.now()
177
- const isRatelimited = SetTimeoutAction({ identifier: webhook.Destination, interval: (webhook.Ratelimit ?? 2) * 2, max: (webhook.Ratelimit ?? 2), addTime: true })
178
- const form = new FormData();
179
- const embed = {
180
- title: `${metadata.name} (${metadata.status})`,
181
- description: embedText,
182
- fields: [],
183
- color: 16711680,
184
- timestamp: new Date().toISOString(),
185
- footer: { text: webhook.Title ?? `AtmosphericX` }
186
- };
187
-
188
- if (isRatelimited.limited) { return }
189
-
190
-
191
- if (metadata.description && !metadata.expired) {
192
- const description = metadata.description.length > 900
193
- ? metadata.description.substring(0, 900) + "\n\n[Message truncated due to length]"
194
- : metadata.description;
195
- embed.fields.push({
196
- name: "Description",
197
- value: description ? '```' + '\n' + description.split('\n').map(l => l.trim()).filter(Boolean).join('\n') + '\n' + '```' : ""
198
- });
199
- }
200
-
201
-
202
- if (metadata.attachments?.length > 0) {
203
- const attachments = metadata.attachments.slice(0, 5);
204
- embed.fields.push({
205
- name: "Attachments",
206
- value: attachments.map(attachment => `- [${attachment.name.length > 45 ? attachment.name.substring(0, 45) + '...' : attachment.name}](${attachment.link})`).join('\n')
207
- });
208
- }
209
-
210
- if (uploads?.TEXT) {
211
- form.append("fUpload", new Blob([Buffer.from(metadata.text)], {type: "application/text"}), `${properties.event}_${properties.status}_${properties.metadata.tracking}.txt`)
212
- }
213
-
214
- if (uploads?.JSON) {
215
- form.append("fUpload2", new Blob([Buffer.from(metadata.json)], {type: "application/json"}), `${properties.event}_${properties.status}_${properties.metadata.tracking}.json`)
216
- }
217
-
218
- if (uploads?.EAS) {
219
- if (metadata.eas) {
220
- const file = await readFile(metadata.eas);
221
- form.append("fEas", new Blob([Buffer.from(file)], { type: "audio/mpeg" }), `${properties.event}_${properties.status}_${properties.metadata.tracking}_eas.mp3`)
222
- }
223
- }
224
-
225
- form.append("payload_json", JSON.stringify({
226
- username: webhook.Title ?? "AtmosphericX",
227
- content: webhook.Message ?? "",
228
- embeds: [embed]
229
- }));
230
-
231
- await CreateHttp({
232
- url: webhook.Destination,
233
- timeout: 15e3,
234
- method: `POST`,
235
- body: form
236
- })
237
- SetDebug({
238
- title: "Tasks/Webhook",
239
- message: `${Math.round(performance.now() - t)}ms`
240
- });
241
- }
242
- }
243
- }
244
- }
245
- SetDebug({ title: `Tasks`, message: `${Math.round(performance.now() - tick)}ms` })
246
- }
@@ -1,59 +0,0 @@
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
-
21
- import { TypeSettings } from "../../@types/Settings"
22
- import { bootstrap } from "../../bootstrap"
23
- import { SetWarning } from '../@utilities/SetWarning'
24
- import { ImportShapefiles } from './ImportShapefiles'
25
- import { ImportBroadcastify } from "./ImportBroadcastify"
26
- import { existsSync, writeFileSync } from "fs"
27
- import sqlite3 from 'better-sqlite3'
28
-
29
- export const InitializeDatabase = async (): Promise<void> => {
30
- const settings = bootstrap.settings as TypeSettings;
31
- try {
32
- if (!existsSync(settings.Database)) {
33
- writeFileSync(settings.Database, '')
34
- SetWarning({ message: `Creating new database at ${settings.Database}` })
35
- }
36
- bootstrap.database = new sqlite3(settings.Database);
37
- bootstrap.database
38
- .prepare(`CREATE TABLE IF NOT EXISTS stanzas ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, issued TEXT, stanza TEXT )`)
39
- .run();
40
- bootstrap.database
41
- .prepare(`CREATE TABLE IF NOT EXISTS shapefiles (id TEXT PRIMARY KEY, location TEXT, geometry TEXT)`)
42
- .run();
43
- const isNeedingShapefiles = bootstrap.database
44
- .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='shapefiles';`)
45
- .get();
46
- const isNeedingBroadcastify = bootstrap.database
47
- .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';`)
48
- .get();
49
-
50
- if (!isNeedingShapefiles || !isNeedingBroadcastify) {
51
- SetWarning({message: `Required database tables are currently building, please ${bootstrap.ansi_colors.RED}DO NOT${bootstrap.ansi_colors.RESET} close your terminal. The building will not finish and will remain incomplete. If you do mess up, you will need to delete ${settings.Database} and restart the application.` })
52
- await ImportBroadcastify();
53
- await ImportShapefiles();
54
- SetWarning({ message: `Building has completed, you can now continue or close the terminal`})
55
- }
56
- } catch (error) {
57
- SetWarning({ message: `An error occurred while initializing the database: ${error.message}` })
58
- }
59
- }
@@ -1,144 +0,0 @@
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/Settings";
21
- import { bootstrap } from "../../bootstrap";
22
- import { SetWarning } from "../@utilities/SetWarning";
23
- import { GetWavPCM16 } from "./GetWavPCM16";
24
- import { GetSampledPCM16 } from "./GetSampledPCM16";
25
- import { SetRadioEffect } from "./SetRadioEffect";
26
- import { SetSameHeader } from "./SetSameHeader";
27
- import { SetAttentionTone } from "./SetAttentionTone";
28
- import { GetMergedPCM16 } from "./GetMergedPCM16";
29
- import { SetNoise } from "./SetNoise";
30
- import { GetPCM16 } from "./GetPCM16";
31
- import { GetTTS } from "./GetTTS";
32
- import { GetCleanDescription } from "./GetCleanDescription";
33
- import { SetDebug } from "../@utilities/SetDebug";
34
- import { join } from 'path'
35
- import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs'
36
- import { execSync } from 'child_process'
37
- import { platform } from 'os'
38
-
39
-
40
- interface GenerateEASMessageOptions {
41
- message: string
42
- header: string
43
- title: string
44
- }
45
-
46
- export const GenerateEASMessage = async (options: GenerateEASMessageOptions): Promise<string> => {
47
- const tick = performance.now()
48
- const settings = bootstrap.settings as TypeSettings;
49
- const directory = settings.GlobalSettings.ArchiveSettings.EasDirectory;
50
- const prefix = settings.GlobalSettings.ArchiveSettings.EasToneout;
51
- let message = options.message;
52
- let header = options.header;
53
- let title = (options.title ?? `${Math.random().toString(36).substring(2, 15)}-${header.replace(/[^a-zA-Z0-9]/g, '')}`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
54
- if (!message || !header) {
55
- SetWarning({
56
- title: `EAS`,
57
- message: `Message and header are required to generate an EAS tone.`
58
- })
59
- return null;
60
- }
61
- let buffTTS: Buffer;
62
- let buffRadio: any;
63
- let buffFull: any[] = [];
64
-
65
- if (!existsSync(directory)) {
66
- mkdirSync(directory, { recursive: true });
67
- }
68
- const tmpTTS = join(directory, `/${title}-tts.wav`)
69
- const outTTS = join(directory, `/${title}.wav`)
70
- const vPlatform = platform();
71
-
72
- if (vPlatform === 'darwin') {
73
- SetWarning({
74
- title: `EAS`,
75
- message: `EAS tone generation is not supported on macOS.`
76
- });
77
- return null
78
- }
79
-
80
-
81
- await new Promise<void>((resolve, reject) => {
82
- const tMsg = GetCleanDescription(message)
83
- GetTTS(tMsg, tmpTTS).then(() => {
84
- resolve();
85
- });
86
- });
87
- if (!existsSync(tmpTTS)) {
88
- return null;
89
- }
90
- buffTTS = readFileSync(tmpTTS);
91
- const vWav = GetWavPCM16(buffTTS);
92
- const vSamples = GetSampledPCM16(vWav.samples, vWav.sampleRate, 8000)
93
- const vRadio = SetRadioEffect(vSamples, 8000)
94
-
95
- if (existsSync(prefix)) {
96
- let tBuffer = readFileSync(prefix);
97
- let tWav = GetWavPCM16(tBuffer);
98
-
99
- if (tWav == null) {
100
- try {
101
- const converted = join(directory, `/${title}-tts-fixed.wav`)
102
- execSync(`ffmpeg -y -i "${prefix}" -ar 8000 -ac 1 -sample_fmt s16 "${converted}"`, { stdio: 'ignore' })
103
- if (existsSync(converted)) {
104
- tBuffer = readFileSync(converted)
105
- tWav = GetWavPCM16(tBuffer)
106
- try { unlinkSync(converted) } catch {}
107
- }
108
- } catch (e) {}
109
- }
110
-
111
- if (tWav == null) {
112
- SetWarning({ title: `EAS`, message: `Intro tone isn't a valid .WAV file or isn't in PCM 16-bit format. Converted attempt failed; please convert it then try again.` })
113
- return null;
114
- }
115
-
116
- const tSamples = (tWav.sampleRate != 8000 ? GetSampledPCM16(tWav.samples, tWav.sampleRate, 8000) : tWav.samples)
117
- buffRadio = SetRadioEffect(tSamples, 8000)
118
- }
119
-
120
- buffFull = buffRadio != null ? [buffRadio, new Int16Array(Math.floor(0.5 * 8000))] : [];
121
- buffFull.push(
122
- SetSameHeader(header, 3, 8000, {
123
- preMarkSec: 1.1,
124
- gapSec: 0.5,
125
- }),
126
- new Int16Array(Math.floor(0.5 * 8000)),
127
- SetAttentionTone(8, 8000),
128
- new Int16Array(Math.floor(0.5 * 8000)),
129
- vRadio
130
- )
131
- for (let i = 0; i < 3; i++) {
132
- buffFull.push(SetSameHeader(header, 1, 8000, { preMarkSec: 0.5, gapSec: 0.1 }))
133
- buffFull.push(new Int16Array(Math.floor(0.5 * 8000)));
134
- }
135
- const aSamples = GetMergedPCM16(buffFull);
136
- const aFinal = SetNoise(aSamples, 0.002);
137
- const aBuffer = GetPCM16(Array.from(aFinal).map(v => ({ value: v })), 8000);
138
- writeFileSync(outTTS, aBuffer)
139
- try{ unlinkSync(tmpTTS) } catch {}
140
- SetDebug({ title: `GenerateEASMessage`, message: `${Math.round(performance.now() - tick)}ms` })
141
- return outTTS;
142
- }
143
-
144
-