@atmosx/event-product-parser 3.0.62 → 3.0.63

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 (112) hide show
  1. package/README.md +6 -4
  2. package/dist/cjs/index.cjs +21216 -6908
  3. package/dist/esm/index.mjs +21207 -6900
  4. package/package.json +49 -47
  5. package/pnpm-workspace.yaml +4 -0
  6. package/src/@building/CreateEvent.ts +20 -22
  7. package/src/@building/GetEventAttachments.ts +8 -8
  8. package/src/@building/GetEventEnhancedName.ts +2 -4
  9. package/src/@building/GetEventGeometry.ts +5 -5
  10. package/src/@building/GetEventHeader.ts +11 -11
  11. package/src/@building/GetEventNodes.ts +12 -12
  12. package/src/@building/GetEventOffice.ts +11 -11
  13. package/src/@building/GetEventProperties.ts +60 -55
  14. package/src/@building/GetEventSignature.ts +7 -7
  15. package/src/@building/GetEventTags.ts +1 -1
  16. package/src/@building/GetEventTracking.ts +28 -32
  17. package/src/@core/ClearEvents.ts +7 -7
  18. package/src/@core/CreateListener.ts +2 -2
  19. package/src/@core/GetEvents.ts +2 -2
  20. package/src/@core/GetNodes.ts +2 -2
  21. package/src/@core/GetRandomEvent.ts +2 -2
  22. package/src/@core/GetVersion.ts +2 -2
  23. package/src/@core/ManualEvent.ts +20 -21
  24. package/src/@core/QueryStanza.ts +7 -7
  25. package/src/@core/SetNode.ts +32 -26
  26. package/src/@core/StartService.ts +18 -18
  27. package/src/@core/StopService.ts +8 -8
  28. package/src/@enums/Expressions.ts +1 -1
  29. package/src/@enums/Tags.ts +1 -1
  30. package/src/@events/ParseAPI.ts +44 -39
  31. package/src/@events/ParseText.ts +19 -19
  32. package/src/@events/ParseUGC.ts +21 -21
  33. package/src/@events/ParseVTEC.ts +32 -33
  34. package/src/@manager/MakeEvents.ts +33 -30
  35. package/src/@manager/RemoveEvent.ts +38 -34
  36. package/src/@manager/SetHash.ts +16 -11
  37. package/src/@manager/UpdateEvents.ts +10 -10
  38. package/src/@manager/UpdateNode.ts +13 -13
  39. package/src/@manager/ValidateEvents.ts +36 -37
  40. package/src/@modules/@database/GetCachedEvents.ts +10 -12
  41. package/src/@modules/@database/ImportBroadcastify.ts +12 -13
  42. package/src/@modules/@database/ImportShapefiles.ts +17 -18
  43. package/src/@modules/@database/ImportStanza.ts +11 -11
  44. package/src/@modules/@database/InitializeDatabase.ts +16 -16
  45. package/src/@modules/@eas/GenerateEASMessage.ts +53 -47
  46. package/src/@modules/@eas/GetPCM16.ts +11 -6
  47. package/src/@modules/@eas/GetSampledPCM16.ts +12 -6
  48. package/src/@modules/@eas/GetTTS.ts +12 -7
  49. package/src/@modules/@eas/GetWavPCM16.ts +5 -5
  50. package/src/@modules/@eas/SetAFSK.ts +11 -6
  51. package/src/@modules/@eas/SetAttentionTone.ts +9 -4
  52. package/src/@modules/@eas/SetNoise.ts +10 -5
  53. package/src/@modules/@eas/SetRadioEffect.ts +10 -5
  54. package/src/@modules/@eas/SetSameHeader.ts +20 -12
  55. package/src/@modules/@stanza/GetAwipsType.ts +14 -15
  56. package/src/@modules/@stanza/ValidateStanza.ts +25 -13
  57. package/src/@modules/@utilities/CreateHttp.ts +24 -24
  58. package/src/@modules/@utilities/GetMatched.ts +8 -3
  59. package/src/@modules/@utilities/GetSettings.ts +3 -3
  60. package/src/@modules/@utilities/GetShapeNearestPoint.ts +22 -17
  61. package/src/@modules/@utilities/QueueManager.ts +70 -0
  62. package/src/@modules/@utilities/SetCronSchedule.ts +20 -20
  63. package/src/@modules/@utilities/SetDebug.ts +10 -10
  64. package/src/@modules/@utilities/SetEventEmit.ts +15 -15
  65. package/src/@modules/@utilities/SetListener.ts +6 -6
  66. package/src/@modules/@utilities/SetSettings.ts +5 -5
  67. package/src/@modules/@utilities/SetSleep.ts +3 -3
  68. package/src/@modules/@utilities/SetTimeoutAction.ts +25 -25
  69. package/src/@modules/@utilities/SetWarning.ts +8 -8
  70. package/src/@modules/@xmpp/DeployXMPP.ts +16 -16
  71. package/src/@modules/@xmpp/ErrorXMPP.ts +4 -4
  72. package/src/@modules/@xmpp/OfflineXMPP.ts +11 -11
  73. package/src/@modules/@xmpp/OnlineXMPP.ts +16 -16
  74. package/src/@modules/@xmpp/ReconnectXMPP.ts +27 -27
  75. package/src/@modules/@xmpp/StanzaXMPP.ts +23 -23
  76. package/src/@parsers/@hvtec/HVExtract.ts +9 -9
  77. package/src/@parsers/@text/GetDescriptionFromProduct.ts +18 -19
  78. package/src/@parsers/@text/GetEmbededText.ts +3 -3
  79. package/src/@parsers/@text/GetStringText.ts +6 -6
  80. package/src/@parsers/@text/GetTextFromProduct.ts +10 -10
  81. package/src/@parsers/@text/GetXML.ts +5 -5
  82. package/src/@parsers/@ugc/GetCache.ts +2 -2
  83. package/src/@parsers/@ugc/{GetUGCHeader.ts → GetHeader.ts} +2 -2
  84. package/src/@parsers/@ugc/GetLocations.ts +5 -5
  85. package/src/@parsers/@ugc/GetZonePolygon.ts +10 -10
  86. package/src/@parsers/@ugc/GetZones.ts +1 -1
  87. package/src/@parsers/@ugc/SetCache.ts +11 -6
  88. package/src/@parsers/@ugc/UGCExtract.ts +10 -10
  89. package/src/@parsers/{@pvtec → @vtec}/VTECExtract.ts +19 -19
  90. package/src/@tasks/CreateTasks.ts +110 -0
  91. package/src/@tasks/TaskGenerateAudio.ts +34 -0
  92. package/src/@tasks/TaskGenerateJSON.ts +34 -0
  93. package/src/@tasks/TaskGenerateText.ts +34 -0
  94. package/src/@tasks/TaskSendNTFY.ts +91 -0
  95. package/src/@tasks/TaskSendWebhook.ts +100 -0
  96. package/src/@types/HVTEC.ts +4 -4
  97. package/src/@types/Hash.ts +3 -3
  98. package/src/@types/Settings.ts +1 -1
  99. package/src/@types/StanzaCompiled.ts +13 -13
  100. package/src/@types/UGC.ts +3 -3
  101. package/src/@types/VTEC.ts +10 -10
  102. package/src/{@types → @types-lower}/Event.ts +4 -4
  103. package/src/{@types → @types-lower}/Properties.ts +2 -1
  104. package/src/{@types → @types-lower}/Stanza.ts +1 -1
  105. package/src/bootstrap.ts +26 -26
  106. package/src/index.ts +30 -27
  107. package/tools/build.js +45 -0
  108. package/tsconfig.json +21 -1
  109. package/src/@manager/Tasks.ts +0 -246
  110. package/tsup.config.ts +0 -16
  111. /package/src/@parsers/{@pvtec → @vtec}/GetExpiry.ts +0 -0
  112. /package/src/{@types → @types-lower}/Attributes.ts +0 -0
@@ -17,15 +17,14 @@
17
17
 
18
18
  */
19
19
 
20
- import { EnumExpressions } from "../../@enums/Expressions";
20
+ import { EnumExpressions } from "@enums/Expressions"
21
21
 
22
22
  interface GetDescriptionFromProductOptions {
23
- message: string
24
- handle?: string
23
+ Message: string
24
+ Handle?: string
25
25
  }
26
26
 
27
- export const GetDescriptionFromProduct = (options: GetDescriptionFromProductOptions): string => {
28
- let message = options.message;
27
+ export const GetDescriptionFromProduct = ({ Message, Handle }: GetDescriptionFromProductOptions): string => {
29
28
  const predefinedEndMarkers = ['&&', 'LAT...'];
30
29
  const getEndIndex = (text: string, fromIndex = 0): number => {
31
30
  const indices = predefinedEndMarkers
@@ -33,28 +32,28 @@ export const GetDescriptionFromProduct = (options: GetDescriptionFromProductOpti
33
32
  .filter((idx) => idx !== -1);
34
33
  return indices.length ? Math.min(...indices) : -1;
35
34
  };
36
- const dates = Array.from(message.matchAll(EnumExpressions.dateline));
35
+ const dates = Array.from(Message.matchAll(EnumExpressions.dateline));
37
36
  if (dates.length) {
38
37
  const lastMatch = dates[dates.length - 1][0];
39
- const sIndx = message.lastIndexOf(lastMatch);
38
+ const sIndx = Message.lastIndexOf(lastMatch);
40
39
  if (sIndx !== -1) {
41
- const endIndx = getEndIndex(message, sIndx);
42
- message = message.substring(sIndx + lastMatch.length, endIndx !== -1 ? endIndx : undefined).trimStart();
43
- if (message.startsWith('/')) message = message.slice(1).trimStart();
44
- if (options.handle && message.includes(options.handle)) {
45
- const handleIdx = message.indexOf(options.handle);
46
- message = message.substring(handleIdx + options.handle.length).trimStart();
47
- if (message.startsWith('/')) message = message.slice(1).trimStart();
40
+ const endIndx = getEndIndex(Message, sIndx);
41
+ Message = Message.substring(sIndx + lastMatch.length, endIndx !== -1 ? endIndx : undefined).trimStart();
42
+ if (Message.startsWith('/')) Message = Message.slice(1).trimStart();
43
+ if (Handle && Message.includes(Handle)) {
44
+ const handleIdx = Message.indexOf(Handle);
45
+ Message = Message.substring(handleIdx + Handle.length).trimStart();
46
+ if (Message.startsWith('/')) Message = Message.slice(1).trimStart();
48
47
  }
49
48
  }
50
- } else if (options.handle) {
51
- const handleIndx = message.indexOf(options.handle);
49
+ } else if (Handle) {
50
+ const handleIndx = Message.indexOf(Handle);
52
51
  if (handleIndx !== -1) {
53
- let afterHandle = message.substring(handleIndx + options.handle.length).trimStart();
52
+ let afterHandle = Message.substring(handleIndx + Handle.length).trimStart();
54
53
  if (afterHandle.startsWith('/')) afterHandle = afterHandle.slice(1).trimStart();
55
54
  const latEnd = getEndIndex(afterHandle);
56
- message = latEnd !== -1 ? afterHandle.substring(0, latEnd).trim() : afterHandle.trim();
55
+ Message = latEnd !== -1 ? afterHandle.substring(0, latEnd).trim() : afterHandle.trim();
57
56
  }
58
57
  }
59
- return message.trim();
58
+ return Message.trim();
60
59
  }
@@ -17,7 +17,7 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeEvent } from "../../@types/Event"
20
+ import { TypeEvent } from "types-lower/Event"
21
21
 
22
22
  export const GetEmebedText = (event: TypeEvent): string => {
23
23
  const line = (label: string, value: unknown, condition = true) => condition && value ? `${label} ${value}` : null;
@@ -30,8 +30,8 @@ export const GetEmebedText = (event: TypeEvent): string => {
30
30
  line(`**Damage Threat:**`, event?.properties?.parameters?.damage_threat, !isExpired),
31
31
  line(`**Flood Threat:**`, event?.properties?.parameters?.flood_threat, !isExpired),
32
32
  line(`**Tornado Threat:**`, event?.properties?.parameters?.tornado_threat, !isExpired),
33
- line(`**Estimated Wind Gusts:**`, `${event?.properties?.parameters?.estimated_wind_gusts} ${event?.properties?.parameters?.wind_threat ? ` (${event?.properties?.parameters?.wind_threat})` : ''}`, !isExpired && event?.properties?.parameters?.estimated_wind_gusts != null),
34
- line(`**Estimated Hail Size:**`, `${event?.properties?.parameters?.estimated_hail_size} ${event?.properties?.parameters?.hail_threat ? ` (${event?.properties?.parameters?.hail_threat})` : ''}`, !isExpired && event?.properties?.parameters?.estimated_hail_size != null),
33
+ line(`**Wind Gusts:**`, `${event?.properties?.parameters?.estimated_wind_gusts} ${event?.properties?.parameters?.wind_threat ? ` (${event?.properties?.parameters?.wind_threat})` : ''}`, !isExpired && event?.properties?.parameters?.estimated_wind_gusts != null),
34
+ line(`**Hail Size:**`, `${event?.properties?.parameters?.estimated_hail_size} ${event?.properties?.parameters?.hail_threat ? ` (${event?.properties?.parameters?.hail_threat})` : ''}`, !isExpired && event?.properties?.parameters?.estimated_hail_size != null),
35
35
  line(`**Discussion:**`, event?.properties?.discussion_parameters?.discussion_number, !isExpired),
36
36
  line(`**Concern:**`, event?.properties?.discussion_parameters?.discussion_concerning, !isExpired),
37
37
  line(`**SPC Max Tornado Threat:**`, event?.properties?.discussion_parameters?.discussion_max_tornado, !isExpired),
@@ -17,12 +17,12 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeEvent } from "../../@types/Event"
21
- import { TypeSettings } from "../../@types/Settings";
22
- import { bootstrap } from "../../bootstrap";
20
+ import { TypeEvent } from "types-lower/Event"
21
+ import { TypeSettings } from "types/Settings"
22
+ import { Bootstrap } from "@bootstrap"
23
23
 
24
24
  export const GetStringText = (event: TypeEvent): string => {
25
- const settings = bootstrap.settings as TypeSettings;
25
+ const settings = Bootstrap.Settings as TypeSettings;
26
26
  const timezone = settings.NotifyServer.Timezone ?? `UTC`;
27
27
  const line = (label: string, value: unknown, condition = true) => condition && value ? `${label} ${value}` : null;
28
28
  const isStatement = event.properties.status_metadata.is_statement;
@@ -34,8 +34,8 @@ export const GetStringText = (event: TypeEvent): string => {
34
34
  line(`Damage Threat:`, event?.properties?.parameters?.damage_threat, !isExpired),
35
35
  line(`Flood Threat:`, event?.properties?.parameters?.flood_threat, !isExpired),
36
36
  line(`Tornado Threat:`, event?.properties?.parameters?.tornado_threat, !isExpired),
37
- line(`Estimated Wind Gusts:`, `${event?.properties?.parameters?.estimated_wind_gusts} ${event?.properties?.parameters?.wind_threat ? ` (${event?.properties?.parameters?.wind_threat})` : ''}`, !isExpired && event?.properties?.parameters?.estimated_wind_gusts != null),
38
- line(`Estimated Hail Size:`, `${event?.properties?.parameters?.estimated_hail_size} ${event?.properties?.parameters?.hail_threat ? ` (${event?.properties?.parameters?.hail_threat})` : ''}`, !isExpired && event?.properties?.parameters?.estimated_hail_size != null),
37
+ line(`Wind Gusts:`, `${event?.properties?.parameters?.estimated_wind_gusts} ${event?.properties?.parameters?.wind_threat ? ` (${event?.properties?.parameters?.wind_threat})` : ''}`, !isExpired && event?.properties?.parameters?.estimated_wind_gusts != null),
38
+ line(`Hail Size:`, `${event?.properties?.parameters?.estimated_hail_size} ${event?.properties?.parameters?.hail_threat ? ` (${event?.properties?.parameters?.hail_threat})` : ''}`, !isExpired && event?.properties?.parameters?.estimated_hail_size != null),
39
39
  line(`Discussion:`, event?.properties?.discussion_parameters?.discussion_number, !isExpired),
40
40
  line(`Concern:`, event?.properties?.discussion_parameters?.discussion_concerning, !isExpired),
41
41
  line(`SPC Max Tornado Threat:`, event?.properties?.discussion_parameters?.discussion_max_tornado, !isExpired),
@@ -18,25 +18,25 @@
18
18
  */
19
19
 
20
20
  interface GetTextFromProductOptions {
21
- message: string
22
- find: string[]
23
- append?: string
24
- removal?: string[]
21
+ Message: string
22
+ Find: string[]
23
+ Append?: string
24
+ Removal?: string[]
25
25
  }
26
26
 
27
- export const GetTextFromProduct = (options: GetTextFromProductOptions): string => {
28
- const lines = options.message.split(`\n`);
27
+ export const GetTextFromProduct = ({ Message, Find, Append, Removal }: GetTextFromProductOptions): string => {
28
+ const lines = Message.split(`\n`);
29
29
  for (const line of lines) {
30
- const matchedFind = options.find.find((find) => line.includes(find));
30
+ const matchedFind = Find.find((find) => line.includes(find));
31
31
  if (matchedFind) {
32
32
  let result = line.slice(line.indexOf(matchedFind) + matchedFind.length).trim();
33
- if (options.removal) {
34
- for (const str of options.removal) {
33
+ if (Removal) {
34
+ for (const str of Removal) {
35
35
  result = result.toLowerCase().split(str.toLowerCase()).join('');
36
36
  }
37
37
  result = result.replace(matchedFind, '').replace('<', '').trim();
38
38
  }
39
- return result.toUpperCase() + (options?.append ?? ``);
39
+ return result.toUpperCase() + (Append ?? ``);
40
40
  }
41
41
  }
42
42
  return null;
@@ -18,11 +18,11 @@
18
18
  */
19
19
 
20
20
  interface GetXMLOptions {
21
- message: string
22
- targets: string[]
21
+ Message: string
22
+ Targets: string[]
23
23
  }
24
24
 
25
- export const GetXML = (options: GetXMLOptions): Record<string, string> => {
25
+ export const GetXML = ({ Message, Targets }: GetXMLOptions): Record<string, string> => {
26
26
  const extracted: Record<string, any> = {};
27
27
  const findValueByKey = (obj: any, searchKey: string) => {
28
28
  const results = [];
@@ -52,8 +52,8 @@ export const GetXML = (options: GetXMLOptions): Record<string, string> => {
52
52
  }
53
53
  return results;
54
54
  };
55
- for (const key of options.targets) {
56
- const values = findValueByKey(options.message, key);
55
+ for (const key of Targets) {
56
+ const values = findValueByKey(Message, key);
57
57
  const uniqueValues = [...new Set(values)];
58
58
  extracted[key] = uniqueValues.length === 0 ? null : (uniqueValues.length === 1 ? uniqueValues[0] : uniqueValues);
59
59
  }
@@ -17,8 +17,8 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../../bootstrap";
20
+ import { Bootstrap } from "@bootstrap"
21
21
 
22
22
  export const getCache = (key: string) => {
23
- return bootstrap.cache.ugc.get(key);
23
+ return Bootstrap.Cache.UGC.get(key);
24
24
  };
@@ -17,9 +17,9 @@
17
17
 
18
18
  */
19
19
 
20
- import { EnumExpressions } from "../../@enums/Expressions"
20
+ import { EnumExpressions } from "@enums/Expressions"
21
21
 
22
- export const getUGCHeader = (message: string): string | null => {
22
+ export const GetHeader = (message: string): string | null => {
23
23
  const start = message.search(EnumExpressions.ugc1)
24
24
  const sub = message.substring(start)
25
25
  const end = sub.search(EnumExpressions.ugc2)
@@ -17,9 +17,9 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../../bootstrap";
21
- import { getCache } from "./GetCache";
22
- import { setCache } from "./SetCache";
20
+ import { Bootstrap } from "@bootstrap"
21
+ import { getCache } from "@parsers/ugc/GetCache"
22
+ import { setCache } from "@parsers/ugc/SetCache"
23
23
 
24
24
  export const getLocations = async (zones: string[]): Promise<string[]> => {
25
25
  const uniqueZones = Array.from(new Set(zones));
@@ -41,7 +41,7 @@ export const getLocations = async (zones: string[]): Promise<string[]> => {
41
41
  }
42
42
 
43
43
  if (missing.length > 0) {
44
- const rows = await bootstrap.database
44
+ const rows = await Bootstrap.Database
45
45
  .prepare(
46
46
  `SELECT id, location FROM shapefiles WHERE id IN (${missing.map(() => '?').join(',')})`
47
47
  )
@@ -49,7 +49,7 @@ export const getLocations = async (zones: string[]): Promise<string[]> => {
49
49
 
50
50
  for (let i = 0; i < rows.length; i++) {
51
51
  const r = rows[i] as any;
52
- setCache(r.id, [r.location]);
52
+ setCache({ Key: r.id, Value: [r.location] });
53
53
  results.push(r.location);
54
54
  }
55
55
  }
@@ -17,12 +17,12 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../../bootstrap"
21
- import { union } from "polygon-clipping";
20
+ import { Bootstrap } from "@bootstrap"
21
+ import { union } from "polygon-clipping"
22
22
 
23
23
  interface CoordinatesOptions {
24
- zones: string[]
25
- isUnion: boolean
24
+ Zones: string[]
25
+ Union: boolean
26
26
  }
27
27
 
28
28
  interface CoordinatesResponse {
@@ -30,12 +30,12 @@ interface CoordinatesResponse {
30
30
  coordinates: any[]
31
31
  }
32
32
 
33
- export const getZonePolygon = (options: CoordinatesOptions): CoordinatesResponse | null => {
34
- const list = [...new Set(options.zones.map(z => z.trim()))].filter(z => z === 'XX000' ? false : true);
33
+ export const getZonePolygon = ({ Zones, Union }: CoordinatesOptions): CoordinatesResponse | null => {
34
+ const list = [...new Set(Zones.map(z => z.trim()))].filter(z => z === 'XX000' ? false : true);
35
35
  if (list.length === 0) return null;
36
36
 
37
37
  const placeholders = list.map(() => "?").join(",");
38
- const rows = bootstrap.database
38
+ const rows = Bootstrap.Database
39
39
  .prepare(`SELECT geometry FROM shapefiles WHERE id IN (${placeholders})`)
40
40
  .all(...list);
41
41
  const polygons: any[] = [];
@@ -49,7 +49,7 @@ export const getZonePolygon = (options: CoordinatesOptions): CoordinatesResponse
49
49
 
50
50
  if (polygons.length === 0) return null;
51
51
 
52
- if (options.isUnion) {
52
+ if (Union) {
53
53
  const unionFn = union as (...polys: any[]) => any;
54
54
  const mergedCoords = unionFn(...polygons);
55
55
  if (!mergedCoords || mergedCoords.length === 0) return null;
@@ -71,7 +71,7 @@ export const getZonePolygon = (options: CoordinatesOptions): CoordinatesResponse
71
71
  }
72
72
  if (!bestPoly || bestPoly.length === 0) return null;
73
73
  const outerRing = bestPoly[0];
74
- const skip = Math.max(1, parseInt(String(bootstrap.settings.GlobalSettings.ShapefileSkipPoints), 10) ?? 1);
74
+ const skip = Math.max(1, parseInt(String(Bootstrap.Settings.GlobalSettings.ShapefileSkipPoints), 10) ?? 1);
75
75
  let skipped = outerRing.filter((_: any, idx: number) => idx % skip === 0);
76
76
  if (skipped.length < 4) {
77
77
  skipped = outerRing.slice();
@@ -90,7 +90,7 @@ export const getZonePolygon = (options: CoordinatesOptions): CoordinatesResponse
90
90
  }
91
91
  }
92
92
  if (multi.length === 0) return null;
93
- const skip = Math.max(1, parseInt(String(bootstrap.settings.GlobalSettings.ShapefileSkipPoints), 10) ?? 1);
93
+ const skip = Math.max(1, parseInt(String(Bootstrap.Settings.GlobalSettings.ShapefileSkipPoints), 10) ?? 1);
94
94
  if (skip > 1) {
95
95
  for (let p = 0; p < multi.length; p++) {
96
96
  for (let r = 0; r < multi[p].length; r++) {
@@ -17,7 +17,7 @@
17
17
 
18
18
  */
19
19
 
20
- export const getZones = (header: string): string[] => {
20
+ export const GetZones = (header: string): string[] => {
21
21
  const splits = header.split('-');
22
22
  const zones: string[] = [];
23
23
  let state = splits[0].substring(0, 2);
@@ -17,12 +17,17 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../../bootstrap";
20
+ import { Bootstrap } from "@bootstrap"
21
21
 
22
- export const setCache = (key: string, value: string[]) => {
23
- if (bootstrap.cache.ugc.size >= 5000) {
24
- const firstKey = bootstrap.cache.ugc.keys().next().value;
25
- bootstrap.cache.ugc.delete(firstKey);
22
+ interface SetCacheOptions {
23
+ Key: string
24
+ Value: string[]
25
+ }
26
+
27
+ export const setCache = ({ Key, Value }: SetCacheOptions) => {
28
+ if (Bootstrap.Cache.UGC.size >= 5000) {
29
+ const firstKey = Bootstrap.Cache.UGC.keys().next().value;
30
+ Bootstrap.Cache.UGC.delete(firstKey);
26
31
  }
27
- bootstrap.cache.ugc.set(key, value);
32
+ Bootstrap.Cache.UGC.set(Key, Value);
28
33
  };
@@ -17,21 +17,21 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeUGC } from "../../@types/UGC";
21
- import { getUGCHeader } from "./GetUGCHeader"
22
- import { getZones } from "./GetZones";
23
- import { GetExpiry } from './GetExpiry';
24
- import { getLocations } from "./GetLocations";
20
+ import { TypeUGC } from "types/UGC"
21
+ import { GetHeader } from "@parsers/ugc/GetHeader"
22
+ import { GetZones } from "@parsers/ugc/GetZones"
23
+ import { GetExpiry } from "@parsers/ugc/GetExpiry"
24
+ import { getLocations } from "@parsers/ugc/GetLocations"
25
25
 
26
26
  export const ugcExtract = async (message: string): Promise<TypeUGC> => {
27
- const head = getUGCHeader(message);
28
- const ugcs = getZones(head)
29
27
  const expires = GetExpiry(message)
28
+ const head = GetHeader(message);
29
+ const ugcs = GetZones(head);
30
30
  const areas = await getLocations(ugcs)
31
31
  if (!head || ugcs?.length == 0) return;
32
32
  return {
33
- zones: ugcs,
34
- locations: areas,
35
- expires: expires
33
+ Zones: ugcs,
34
+ Locations: areas,
35
+ Expires: expires
36
36
  }
37
37
  }
@@ -17,32 +17,32 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypePVTEC } from "../../@types/VTEC";
21
- import { EnumExpressions } from "../../@enums/Expressions";
22
- import { EnumProducts } from "../../@enums/Products";
23
- import { EnumEvents } from "../../@enums/Events";
24
- import { EnumActions } from "../../@enums/Actions";
25
- import { EnumStatus } from "../../@enums/Status";
26
- import { GetExpiry } from "./GetExpiry";
20
+ import { TypeVTEC } from "types/VTEC"
21
+ import { EnumExpressions } from "@enums/Expressions"
22
+ import { EnumProducts } from "@enums/Products"
23
+ import { EnumEvents } from "@enums/Events"
24
+ import { EnumActions } from "@enums/Actions"
25
+ import { EnumStatus } from "@enums/Status"
26
+ import { GetExpiry } from "./GetExpiry"
27
27
 
28
- export const VTECExtract = (message: string): TypePVTEC[] | null => {
28
+ export const VTECExtract = (message: string): TypeVTEC[] | null => {
29
29
  if (!message) return null;
30
- const getVTECs = message.match(EnumExpressions.pvtec) ?? [];
31
- const vtecs: TypePVTEC[] = [];
30
+ const getVTECs = message.match(EnumExpressions.vtec) ?? [];
31
+ const vtecs: TypeVTEC[] = [];
32
32
  for (const vtec of getVTECs) {
33
33
  const sub = vtec.split(`.`);
34
34
  if (sub?.length < 7) continue;
35
35
  const dates = sub[6]?.split(`-`);
36
36
  vtecs.push({
37
- vtec: vtec,
38
- product: EnumProducts[sub[0]],
39
- tracking: `${sub[2]}.${sub[3]}.${sub[4]}.${sub[5]}`,
40
- event: `${EnumEvents[sub[3]]} ${EnumActions[sub[4]]}`,
41
- status: EnumStatus[sub[1]],
42
- organization: message.match(EnumExpressions.wmo)?.[0] ?? null,
43
- expires: GetExpiry(dates),
44
- is_watch: (sub[4] == `A` || sub[4] == `Y`) && (sub[3] == `TO` || sub[3] == `SV`),
45
- prediction_center: sub[2] == `KWNS` ? true : false
37
+ Raw: vtec,
38
+ ProductType: EnumProducts[sub[0]],
39
+ Tracking: `${sub[2]}.${sub[3]}.${sub[4]}.${sub[5]}`,
40
+ Event: `${EnumEvents[sub[3]]} ${EnumActions[sub[4]]}`,
41
+ Status: EnumStatus[sub[1]],
42
+ WMO: message.match(EnumExpressions.wmo)?.[0] ?? null,
43
+ Expires: GetExpiry(dates),
44
+ Watch: (sub[4] == `A` || sub[4] == `Y`) && (sub[3] == `TO` || sub[3] == `SV`),
45
+ PredictionCenter: sub[2] == `KWNS` ? true : false
46
46
  })
47
47
  }
48
48
  return vtecs.length > 0 ? vtecs : null;
@@ -0,0 +1,110 @@
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
+ import { TypeSettings } from "types/Settings"
20
+ import { TypeEvent } from "types-lower/Event"
21
+ import { TypeActions } from "types/Actions"
22
+ import { Bootstrap } from "@bootstrap"
23
+ import { SetDebug } from "@utilities/SetDebug"
24
+ import { GetMatched } from "@utilities/GetMatched"
25
+ import { GetStringText } from "@parsers/text/GetStringText"
26
+ import { GetCleanedEvent } from "@building/GetCleanedEvent"
27
+ import { TaskGenerateAudio } from "@tasks/TaskGenerateAudio"
28
+ import { TaskGenerateText } from "@tasks/TaskGenerateText"
29
+ import { TaskGenerateJSON } from "@tasks/TaskGenerateJSON"
30
+ import { TaskSendNTFY } from "@tasks/TaskSendNTFY"
31
+ import { TaskSendWebhook } from "@tasks/TaskSendWebhook"
32
+ import { QueueManager } from "@utilities/QueueManager"
33
+
34
+ const Webhooks = new QueueManager({ Concurrency: 1 });
35
+ const NTFY = new QueueManager({ Concurrency: 5 });
36
+
37
+ export const CreateTasks = async (events: TypeEvent[]): Promise<void> => {
38
+ const tick = performance.now()
39
+ const settings = Bootstrap.Settings as TypeSettings;
40
+ const { ActionSettings, GlobalSettings, NotifyServer } = settings;
41
+ const actions = ActionSettings as TypeActions[];
42
+
43
+ for (const event of events) {
44
+ const { properties } = event;
45
+ const isActioning = Array.isArray(actions) && actions.length > 0;
46
+ if (!isActioning) { continue }
47
+
48
+ for (const action of actions) {
49
+ const { Events, Webhook, NotificationServer, Uploads } = action;
50
+ const isValidAction = GetMatched({ Strings: Events, String: properties.event });
51
+ if ((Events.length == 0 || isValidAction)) {
52
+ const a = performance.now();
53
+ const [eas, text, json] = await Promise.all([
54
+ Uploads?.EAS ? TaskGenerateAudio({
55
+ Filename: (`${properties.event}_${properties.metadata.tracking}`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim(),
56
+ Description: properties.description,
57
+ Header: properties.metadata.header
58
+ }).then((result) => { return result; }) : Promise.resolve(null),
59
+
60
+ Uploads?.TEXT ? TaskGenerateText({
61
+ String: properties.metadata.raw,
62
+ Directory: GlobalSettings?.ArchiveSettings?.TextDirectory,
63
+ Filename: (`${properties.event}_${properties.metadata.tracking}.txt`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim()
64
+ }).then((result) => { return result; }) : Promise.resolve(null),
65
+
66
+ Uploads?.JSON ? TaskGenerateJSON({
67
+ String: JSON.stringify(GetCleanedEvent(event), null, 2),
68
+ Directory: GlobalSettings?.ArchiveSettings?.JSONDirectory,
69
+ Filename: (`${properties.event}_${properties.metadata.tracking}.json`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim()
70
+ }).then((result) => { return result; }) : Promise.resolve(null),
71
+ ]);
72
+
73
+ SetDebug({ Title: `Tasks/Generative`, Message: `${Math.round(performance.now() - a)}ms` })
74
+
75
+ const b = performance.now();
76
+ await Promise.all([
77
+ NotificationServer?.Enabled && NotifyServer?.Enabled && NotificationServer?.Topic ? NTFY.enqueue(() => TaskSendNTFY({
78
+ Event: event,
79
+ Toggles: {
80
+ EAS: Uploads?.EAS,
81
+ Json: Uploads?.JSON,
82
+ Text: Uploads?.TEXT
83
+ },
84
+ Priority: NotificationServer?.Priority ?? 5,
85
+ Body: GetStringText(event),
86
+ Topic: NotificationServer?.Topic
87
+ })) : Promise.resolve(null),
88
+ Webhook?.Enabled && Webhook?.Destination ? Webhooks.enqueue(() => TaskSendWebhook({
89
+ Event: event,
90
+ Webhook: {
91
+ Enabled: Webhook?.Enabled,
92
+ Destination: Webhook?.Destination,
93
+ Message: Webhook?.Message,
94
+ Title: Webhook?.Title,
95
+ Ratelimit: Webhook?.Ratelimit
96
+ },
97
+ Attachments: {
98
+ Text: text,
99
+ EAS: eas,
100
+ Json: json
101
+ }
102
+ })) : Promise.resolve(null)
103
+ ]);
104
+ SetDebug({ Title: `Tasks/Send`, Message: `${Math.round(performance.now() - b)}ms` })
105
+ }
106
+ }
107
+ SetDebug({ Title: `Tasks/CompletedEventTask`, Message: `${Math.round(performance.now() - tick)}ms` })
108
+ }
109
+ SetDebug({ Title: `Tasks/Global`, Message: `${Math.round(performance.now() - tick)}ms` })
110
+ }
@@ -0,0 +1,34 @@
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 { GenerateEASMessage } from "@eas/GenerateEASMessage"
21
+
22
+ interface TaskGenerateAudioOptions {
23
+ Filename: string;
24
+ Description: string;
25
+ Header: string;
26
+ }
27
+
28
+ export const TaskGenerateAudio = async function({ Filename, Description, Header }: TaskGenerateAudioOptions): Promise<string> {
29
+ return await GenerateEASMessage({
30
+ Title: Filename,
31
+ Message: Description,
32
+ Header: Header
33
+ });
34
+ }
@@ -0,0 +1,34 @@
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 { mkdir, writeFile } from "fs/promises"
21
+
22
+ interface TaskGenerateJSONOptions {
23
+ String: string;
24
+ Directory: string;
25
+ Filename: string;
26
+ }
27
+
28
+ export const TaskGenerateJSON = async function({ String, Directory, Filename }: TaskGenerateJSONOptions): Promise<string> {
29
+ if (Directory) {
30
+ await mkdir(Directory, { recursive: true });
31
+ await writeFile(Directory + "/" + Filename, `${String}${"\n".repeat(5)}`);
32
+ }
33
+ return String;
34
+ }
@@ -0,0 +1,34 @@
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 { mkdir, appendFile } from "fs/promises"
21
+
22
+ interface TaskGenerateTextOptions {
23
+ String: string;
24
+ Directory: string;
25
+ Filename: string;
26
+ }
27
+
28
+ export const TaskGenerateText = async function({ String, Directory, Filename }: TaskGenerateTextOptions): Promise<string> {
29
+ if (Directory) {
30
+ await mkdir(Directory, { recursive: true });
31
+ await appendFile(Directory + "/" + Filename, `${String}${"\n".repeat(5)}`);
32
+ }
33
+ return String;
34
+ }