@atmosx/event-product-parser 3.0.61 → 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.
- package/.github/docs/docs-functions.md +1 -1
- package/.github/docs/docs-general-configurations.md +1 -1
- package/.github/docs/docs-integrations.md +1 -1
- package/.github/docs/docs-listeners.md +1 -1
- package/.github/docs/docs-source-configuration.md +1 -1
- package/.github/docs/docs-technical.md +1 -1
- package/README.md +7 -5
- package/dist/cjs/index.cjs +21216 -6908
- package/dist/esm/index.mjs +21207 -6900
- package/package.json +49 -47
- package/pnpm-workspace.yaml +4 -0
- package/src/@building/CreateEvent.ts +20 -22
- package/src/@building/GetEventAttachments.ts +8 -8
- package/src/@building/GetEventEnhancedName.ts +2 -4
- package/src/@building/GetEventGeometry.ts +5 -5
- package/src/@building/GetEventHeader.ts +11 -11
- package/src/@building/GetEventNodes.ts +12 -12
- package/src/@building/GetEventOffice.ts +11 -11
- package/src/@building/GetEventProperties.ts +60 -55
- package/src/@building/GetEventSignature.ts +7 -7
- package/src/@building/GetEventTags.ts +1 -1
- package/src/@building/GetEventTracking.ts +28 -32
- package/src/@core/ClearEvents.ts +7 -7
- package/src/@core/CreateListener.ts +2 -2
- package/src/@core/GetEvents.ts +2 -2
- package/src/@core/GetNodes.ts +2 -2
- package/src/@core/GetRandomEvent.ts +2 -2
- package/src/@core/GetVersion.ts +2 -2
- package/src/@core/ManualEvent.ts +20 -21
- package/src/@core/QueryStanza.ts +7 -7
- package/src/@core/SetNode.ts +32 -26
- package/src/@core/StartService.ts +18 -18
- package/src/@core/StopService.ts +8 -8
- package/src/@enums/Expressions.ts +1 -1
- package/src/@enums/Tags.ts +1 -1
- package/src/@events/ParseAPI.ts +44 -39
- package/src/@events/ParseText.ts +19 -19
- package/src/@events/ParseUGC.ts +21 -21
- package/src/@events/ParseVTEC.ts +32 -33
- package/src/@manager/MakeEvents.ts +33 -30
- package/src/@manager/RemoveEvent.ts +38 -34
- package/src/@manager/SetHash.ts +16 -11
- package/src/@manager/UpdateEvents.ts +10 -10
- package/src/@manager/UpdateNode.ts +13 -13
- package/src/@manager/ValidateEvents.ts +36 -37
- package/src/@modules/@database/GetCachedEvents.ts +10 -12
- package/src/@modules/@database/ImportBroadcastify.ts +12 -13
- package/src/@modules/@database/ImportShapefiles.ts +17 -18
- package/src/@modules/@database/ImportStanza.ts +11 -11
- package/src/@modules/@database/InitializeDatabase.ts +16 -16
- package/src/@modules/@eas/GenerateEASMessage.ts +53 -47
- package/src/@modules/@eas/GetPCM16.ts +11 -6
- package/src/@modules/@eas/GetSampledPCM16.ts +12 -6
- package/src/@modules/@eas/GetTTS.ts +12 -7
- package/src/@modules/@eas/GetWavPCM16.ts +5 -5
- package/src/@modules/@eas/SetAFSK.ts +11 -6
- package/src/@modules/@eas/SetAttentionTone.ts +9 -4
- package/src/@modules/@eas/SetNoise.ts +10 -5
- package/src/@modules/@eas/SetRadioEffect.ts +10 -5
- package/src/@modules/@eas/SetSameHeader.ts +20 -12
- package/src/@modules/@stanza/GetAwipsType.ts +14 -15
- package/src/@modules/@stanza/ValidateStanza.ts +25 -13
- package/src/@modules/@utilities/CreateHttp.ts +24 -24
- package/src/@modules/@utilities/GetMatched.ts +8 -3
- package/src/@modules/@utilities/GetSettings.ts +3 -3
- package/src/@modules/@utilities/GetShapeNearestPoint.ts +22 -17
- package/src/@modules/@utilities/QueueManager.ts +70 -0
- package/src/@modules/@utilities/SetCronSchedule.ts +20 -20
- package/src/@modules/@utilities/SetDebug.ts +10 -10
- package/src/@modules/@utilities/SetEventEmit.ts +15 -15
- package/src/@modules/@utilities/SetListener.ts +6 -6
- package/src/@modules/@utilities/SetSettings.ts +5 -5
- package/src/@modules/@utilities/SetSleep.ts +3 -3
- package/src/@modules/@utilities/SetTimeoutAction.ts +25 -25
- package/src/@modules/@utilities/SetWarning.ts +8 -8
- package/src/@modules/@xmpp/DeployXMPP.ts +16 -16
- package/src/@modules/@xmpp/ErrorXMPP.ts +4 -4
- package/src/@modules/@xmpp/OfflineXMPP.ts +11 -11
- package/src/@modules/@xmpp/OnlineXMPP.ts +16 -16
- package/src/@modules/@xmpp/ReconnectXMPP.ts +27 -27
- package/src/@modules/@xmpp/StanzaXMPP.ts +23 -23
- package/src/@parsers/@hvtec/HVExtract.ts +9 -9
- package/src/@parsers/@text/GetDescriptionFromProduct.ts +18 -19
- package/src/@parsers/@text/GetEmbededText.ts +3 -3
- package/src/@parsers/@text/GetStringText.ts +6 -6
- package/src/@parsers/@text/GetTextFromProduct.ts +10 -10
- package/src/@parsers/@text/GetXML.ts +5 -5
- package/src/@parsers/@ugc/GetCache.ts +2 -2
- package/src/@parsers/@ugc/{GetUGCHeader.ts → GetHeader.ts} +2 -2
- package/src/@parsers/@ugc/GetLocations.ts +5 -5
- package/src/@parsers/@ugc/GetZonePolygon.ts +10 -10
- package/src/@parsers/@ugc/GetZones.ts +1 -1
- package/src/@parsers/@ugc/SetCache.ts +11 -6
- package/src/@parsers/@ugc/UGCExtract.ts +10 -10
- package/src/@parsers/{@pvtec → @vtec}/VTECExtract.ts +19 -19
- package/src/@tasks/CreateTasks.ts +110 -0
- package/src/@tasks/TaskGenerateAudio.ts +34 -0
- package/src/@tasks/TaskGenerateJSON.ts +34 -0
- package/src/@tasks/TaskGenerateText.ts +34 -0
- package/src/@tasks/TaskSendNTFY.ts +91 -0
- package/src/@tasks/TaskSendWebhook.ts +100 -0
- package/src/@types/HVTEC.ts +4 -4
- package/src/@types/Hash.ts +3 -3
- package/src/@types/Settings.ts +1 -1
- package/src/@types/StanzaCompiled.ts +13 -13
- package/src/@types/UGC.ts +3 -3
- package/src/@types/VTEC.ts +10 -10
- package/src/{@types → @types-lower}/Event.ts +4 -4
- package/src/{@types → @types-lower}/Properties.ts +2 -1
- package/src/{@types → @types-lower}/Stanza.ts +1 -1
- package/src/bootstrap.ts +26 -26
- package/src/index.ts +30 -27
- package/tools/build.js +45 -0
- package/tsconfig.json +21 -1
- package/src/@manager/Tasks.ts +0 -246
- package/tsup.config.ts +0 -16
- /package/src/@parsers/{@pvtec → @vtec}/GetExpiry.ts +0 -0
- /package/src/{@types → @types-lower}/Attributes.ts +0 -0
|
@@ -17,15 +17,14 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { EnumExpressions } from "
|
|
20
|
+
import { EnumExpressions } from "@enums/Expressions"
|
|
21
21
|
|
|
22
22
|
interface GetDescriptionFromProductOptions {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
Message: string
|
|
24
|
+
Handle?: string
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export const GetDescriptionFromProduct = (
|
|
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(
|
|
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 =
|
|
38
|
+
const sIndx = Message.lastIndexOf(lastMatch);
|
|
40
39
|
if (sIndx !== -1) {
|
|
41
|
-
const endIndx = getEndIndex(
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
if (
|
|
45
|
-
const handleIdx =
|
|
46
|
-
|
|
47
|
-
if (
|
|
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 (
|
|
51
|
-
const handleIndx =
|
|
49
|
+
} else if (Handle) {
|
|
50
|
+
const handleIndx = Message.indexOf(Handle);
|
|
52
51
|
if (handleIndx !== -1) {
|
|
53
|
-
let afterHandle =
|
|
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
|
-
|
|
55
|
+
Message = latEnd !== -1 ? afterHandle.substring(0, latEnd).trim() : afterHandle.trim();
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
|
-
return
|
|
58
|
+
return Message.trim();
|
|
60
59
|
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeEvent } from "
|
|
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(`**
|
|
34
|
-
line(`**
|
|
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 "
|
|
21
|
-
import { TypeSettings } from "
|
|
22
|
-
import {
|
|
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 =
|
|
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(`
|
|
38
|
-
line(`
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
Message: string
|
|
22
|
+
Find: string[]
|
|
23
|
+
Append?: string
|
|
24
|
+
Removal?: string[]
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export const GetTextFromProduct = (
|
|
28
|
-
const lines =
|
|
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 =
|
|
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 (
|
|
34
|
-
for (const str of
|
|
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() + (
|
|
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
|
-
|
|
22
|
-
|
|
21
|
+
Message: string
|
|
22
|
+
Targets: string[]
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export const GetXML = (
|
|
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
|
|
56
|
-
const values = findValueByKey(
|
|
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,9 +17,9 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { EnumExpressions } from "
|
|
20
|
+
import { EnumExpressions } from "@enums/Expressions"
|
|
21
21
|
|
|
22
|
-
export const
|
|
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 {
|
|
21
|
-
import { getCache } from "
|
|
22
|
-
import { setCache } from "
|
|
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
|
|
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 {
|
|
21
|
-
import { union } from "polygon-clipping"
|
|
20
|
+
import { Bootstrap } from "@bootstrap"
|
|
21
|
+
import { union } from "polygon-clipping"
|
|
22
22
|
|
|
23
23
|
interface CoordinatesOptions {
|
|
24
|
-
|
|
25
|
-
|
|
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 = (
|
|
34
|
-
const list = [...new Set(
|
|
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 =
|
|
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 (
|
|
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(
|
|
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(
|
|
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,12 +17,17 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import {
|
|
20
|
+
import { Bootstrap } from "@bootstrap"
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
32
|
+
Bootstrap.Cache.UGC.set(Key, Value);
|
|
28
33
|
};
|
|
@@ -17,21 +17,21 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeUGC } from "
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { GetExpiry } from
|
|
24
|
-
import { getLocations } from "
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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 {
|
|
21
|
-
import { EnumExpressions } from "
|
|
22
|
-
import { EnumProducts } from "
|
|
23
|
-
import { EnumEvents } from "
|
|
24
|
-
import { EnumActions } from "
|
|
25
|
-
import { EnumStatus } from "
|
|
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):
|
|
28
|
+
export const VTECExtract = (message: string): TypeVTEC[] | null => {
|
|
29
29
|
if (!message) return null;
|
|
30
|
-
const getVTECs = message.match(EnumExpressions.
|
|
31
|
-
const vtecs:
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
+
}
|