@atmosx/event-product-parser 2.0.15 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -237
- package/dist/cjs/index.cjs +2233 -3100
- package/dist/esm/index.mjs +2233 -3103
- package/package.json +3 -3
- package/src/@building/building.clean.ts +30 -0
- package/src/@building/building.create.ts +42 -0
- package/src/@building/building.enhance.ts +56 -0
- package/src/@building/building.geometry.ts +42 -0
- package/src/@building/building.headers.ts +37 -0
- package/src/@building/building.office.ts +43 -0
- package/src/@building/building.polygon.ts +71 -0
- package/src/@building/building.properties.ts +89 -0
- package/src/@building/building.signature.ts +78 -0
- package/src/@building/building.tags.ts +24 -0
- package/src/@building/building.tracking.ts +68 -0
- package/src/@building/building.validate.ts +132 -0
- package/src/@core/core.callback.ts +39 -0
- package/src/@core/core.getEvents.ts +25 -0
- package/src/@core/core.getNodes.ts +25 -0
- package/src/@core/core.listener.ts +24 -0
- package/src/@core/core.setNode.ts +81 -0
- package/src/@core/core.start.ts +54 -0
- package/src/@core/core.stop.ts +32 -0
- package/src/@dictionaries/dictionaries.betterEventNames.ts +85 -0
- package/src/@dictionaries/dictionaries.eventActions.ts +28 -0
- package/src/@dictionaries/{awips.ts → dictionaries.eventAwipAbreviations.ts} +12 -6
- package/src/@dictionaries/dictionaries.eventCancelMessages.ts +29 -0
- package/src/@dictionaries/dictionaries.eventCauses.ts +36 -0
- package/src/@dictionaries/dictionaries.eventProducts.ts +25 -0
- package/src/@dictionaries/dictionaries.eventRecords.ts +25 -0
- package/src/@dictionaries/dictionaries.eventSeverity.ts +27 -0
- package/src/@dictionaries/dictionaries.eventStatus.ts +31 -0
- package/src/@dictionaries/{signatures.ts → dictionaries.eventTags.ts} +13 -68
- package/src/@dictionaries/dictionaries.eventTypes.ts +82 -0
- package/src/@dictionaries/dictionaries.eventsOffshore.ts +31 -0
- package/src/@dictionaries/dictionaries.hailStrings.ts +31 -0
- package/src/@dictionaries/{icao.ts → dictionaries.officeICAOs.ts} +13 -6
- package/src/@dictionaries/dictionaries.regExp.ts +28 -0
- package/src/@dictionaries/dictionaries.shapefileLinks.ts +36 -0
- package/src/@dictionaries/dictionaries.statusCorrelationText.ts +40 -0
- package/src/@dictionaries/dictionaries.test_signatures.ts +23 -0
- package/src/@dictionaries/dictionaries.transcribedMessageReplacements.ts +68 -0
- package/src/@events/events.api.ts +113 -0
- package/src/@events/events.text.ts +79 -0
- package/src/@events/events.ugc.ts +83 -0
- package/src/@events/events.vtec.ts +87 -0
- package/src/@manager/manager.mkEvent.ts +79 -0
- package/src/@manager/manager.rmEvent.ts +44 -0
- package/src/@manager/manager.setHash.ts +37 -0
- package/src/@manager/manager.updateNodes.ts +51 -0
- package/src/@modules/@database/database.cache.ts +48 -0
- package/src/@modules/@database/database.init.ts +45 -0
- package/src/@modules/@database/database.shapefiles.ts +97 -0
- package/src/@modules/@database/database.stanza.ts +47 -0
- package/src/@modules/@stanza/stanza.getAwipsType.ts +46 -0
- package/src/@modules/@stanza/stanza.validate.ts +50 -0
- package/src/@modules/@utilities/utilities.createHttp.ts +75 -0
- package/src/@modules/@utilities/utilities.getFormattedTime.ts +43 -0
- package/src/@modules/@utilities/utilities.getSettings.ts +25 -0
- package/src/@modules/@utilities/utilities.getShapeNearestPoint.ts +114 -0
- package/src/@modules/@utilities/utilities.setCronSchedule.ts +38 -0
- package/src/@modules/@utilities/utilities.setEventEmit.ts +41 -0
- package/src/@modules/@utilities/utilities.setListener.ts +30 -0
- package/src/@modules/@utilities/utilities.setSettings.ts +42 -0
- package/src/@modules/@utilities/utilities.setSleep.ts +33 -0
- package/src/@modules/@utilities/utilities.setTimeoutAction.ts +59 -0
- package/src/@modules/@utilities/utilities.setWarning.ts +34 -0
- package/src/@modules/@xmpp/xmpp.xDeploy.ts +58 -0
- package/src/@modules/@xmpp/xmpp.xError.ts +38 -0
- package/src/@modules/@xmpp/xmpp.xOffline.ts +38 -0
- package/src/@modules/@xmpp/xmpp.xOnline.ts +61 -0
- package/src/@modules/@xmpp/xmpp.xReconnect.ts +59 -0
- package/src/@modules/@xmpp/xmpp.xStanza.ts +63 -0
- package/src/@parsers/@hvtec/hvtec.extract.ts +40 -0
- package/src/@parsers/@pvtec/pvtec.expires.ts +26 -0
- package/src/@parsers/@pvtec/pvtec.extract.ts +50 -0
- package/src/@parsers/@text/text.getDescriptionFromProduct.ts +53 -0
- package/src/@parsers/@text/text.getPolygonFromProduct.ts +32 -0
- package/src/@parsers/@text/text.getTextFromProduct.ts +43 -0
- package/src/@parsers/@text/text.getXML.ts +61 -0
- package/src/@parsers/@ugc/ugc.coordinates.ts +110 -0
- package/src/@parsers/@ugc/ugc.expiry.ts +32 -0
- package/src/@parsers/@ugc/ugc.extract.ts +37 -0
- package/src/@parsers/@ugc/ugc.header.ts +30 -0
- package/src/@parsers/@ugc/ugc.locations.ts +29 -0
- package/src/@parsers/@ugc/ugc.zones.ts +52 -0
- package/src/@types/type.event.ts +67 -0
- package/src/@types/type.properties.ts +75 -0
- package/src/@types/types.attributes.ts +28 -0
- package/src/@types/types.compiled.ts +35 -0
- package/src/@types/types.hash.ts +24 -0
- package/src/@types/types.hvtec.ts +25 -0
- package/src/@types/types.pvtec.ts +29 -0
- package/src/@types/types.settings.ts +71 -0
- package/src/@types/types.stanza.ts +37 -0
- package/src/@types/types.ugc.ts +24 -0
- package/src/bootstrap.ts +82 -164
- package/src/index.ts +48 -216
- package/test.js +65 -49
- package/src/@dictionaries/events.ts +0 -168
- package/src/@parsers/@events/api.ts +0 -146
- package/src/@parsers/@events/cap.ts +0 -123
- package/src/@parsers/@events/text.ts +0 -104
- package/src/@parsers/@events/ugc.ts +0 -107
- package/src/@parsers/@events/vtec.ts +0 -76
- package/src/@parsers/events.ts +0 -392
- package/src/@parsers/hvtec.ts +0 -46
- package/src/@parsers/pvtec.ts +0 -72
- package/src/@parsers/stanza.ts +0 -97
- package/src/@parsers/text.ts +0 -165
- package/src/@parsers/ugc.ts +0 -247
- package/src/@submodules/database.ts +0 -200
- package/src/@submodules/eas.ts +0 -490
- package/src/@submodules/utils.ts +0 -184
- package/src/@submodules/xmpp.ts +0 -142
- package/src/types.ts +0 -259
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import fs from 'fs'
|
|
21
|
+
import sqlite3 from 'better-sqlite3'
|
|
22
|
+
import { TypeSettings } from "../../@types/types.settings"
|
|
23
|
+
import { bootstrap } from "../../bootstrap"
|
|
24
|
+
import { setWarning } from '../@utilities/utilities.setWarning'
|
|
25
|
+
import { importShapefiles } from './database.shapefiles'
|
|
26
|
+
|
|
27
|
+
export const initializeDatabase = async (): Promise<void> => {
|
|
28
|
+
const settings = bootstrap.settings as TypeSettings;
|
|
29
|
+
try {
|
|
30
|
+
if (!fs.existsSync(settings.Database)) {
|
|
31
|
+
fs.writeFileSync(settings.Database, '')
|
|
32
|
+
setWarning({ message: `Creating new database at ${settings.Database}` })
|
|
33
|
+
}
|
|
34
|
+
bootstrap.database = new sqlite3(settings.Database);
|
|
35
|
+
bootstrap.database
|
|
36
|
+
.prepare(`CREATE TABLE IF NOT EXISTS stanzas ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, issued TEXT, stanza TEXT )`)
|
|
37
|
+
.run();
|
|
38
|
+
bootstrap.database
|
|
39
|
+
.prepare(`CREATE TABLE IF NOT EXISTS shapefiles (id TEXT PRIMARY KEY, location TEXT, geometry TEXT)`)
|
|
40
|
+
.run();
|
|
41
|
+
await importShapefiles();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
setWarning({ message: `An error occurred while initializing the database: ${error.message}` })
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import fs from 'fs'
|
|
21
|
+
import { resolve, extname} from 'path'
|
|
22
|
+
import { loadAsync } from 'jszip'
|
|
23
|
+
import { read } from 'shapefile'
|
|
24
|
+
import { TypeSettings } from "../../@types/types.settings"
|
|
25
|
+
import { bootstrap } from "../../bootstrap"
|
|
26
|
+
import { setSleep } from '../@utilities/utilities.setSleep'
|
|
27
|
+
import { setWarning } from '../@utilities/utilities.setWarning'
|
|
28
|
+
import { shapefileLinks } from '../../@dictionaries/dictionaries.shapefileLinks'
|
|
29
|
+
|
|
30
|
+
export const importShapefiles = async (): Promise<void> => {
|
|
31
|
+
const settings = bootstrap.settings as TypeSettings;
|
|
32
|
+
try {
|
|
33
|
+
const tShapefiles = bootstrap.database
|
|
34
|
+
.prepare(`SELECT COUNT(*) AS count FROM shapefiles`)
|
|
35
|
+
.get().count;
|
|
36
|
+
if (tShapefiles === 0) {
|
|
37
|
+
await setSleep({timeout: 1e3});
|
|
38
|
+
setWarning({ message: `Shapefiles are currently building, please DO NOT close your terminal. The shapefiles will not finish and will remain incomplete. If you do mess up, you will need to delete ${settings.Database} and restart the application.` })
|
|
39
|
+
for (const shapefile of shapefileLinks) {
|
|
40
|
+
const response = await fetch(shapefile.link);
|
|
41
|
+
const arrayBuff = await response.arrayBuffer();
|
|
42
|
+
const content = await loadAsync(arrayBuff);
|
|
43
|
+
const directory = resolve(__dirname, `../../shapefiles`);
|
|
44
|
+
if (!fs.existsSync(directory)) {
|
|
45
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
for (const file of Object.keys(content.files)) {
|
|
48
|
+
if (file.endsWith('.shp') || file.endsWith('.dbf')) {
|
|
49
|
+
const data = await content.files[file].async(`nodebuffer`)
|
|
50
|
+
const output = resolve(directory, `${shapefile?.name ?? ``}_${shapefile?.id ?? ``}${extname(file)}`)
|
|
51
|
+
fs.writeFileSync(output, data)
|
|
52
|
+
setWarning({ message: `Successfully downloaded and extracted ${file}` })
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const filepath = resolve(__dirname, '../../shapefiles', shapefile.name + '_' + shapefile.id);
|
|
56
|
+
const { features } = await read(
|
|
57
|
+
filepath,
|
|
58
|
+
filepath,
|
|
59
|
+
);
|
|
60
|
+
setWarning({ message: `Importing ${features.length} features from ${shapefile.name}_${shapefile.id}` })
|
|
61
|
+
const insert = bootstrap.database
|
|
62
|
+
.prepare(`INSERT OR REPLACE INTO shapefiles (id, location, geometry) VALUES (?, ?, ?)`)
|
|
63
|
+
const transaction = bootstrap.database.transaction((entries: any[]) => {
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
const { properties, geometry } = entry;
|
|
66
|
+
let final: string, location: string;
|
|
67
|
+
if (properties.FIPS) {
|
|
68
|
+
final = `${properties.STATE}${shapefile.id}${properties.FIPS.substring(2)}`;
|
|
69
|
+
location = `${properties.COUNTYNAME}, ${properties.STATE}`;
|
|
70
|
+
}
|
|
71
|
+
else if (properties.FULLSTAID) {
|
|
72
|
+
final = `${properties.ST}${shapefile.id}${properties.WFO}`;
|
|
73
|
+
location = `${properties.CITY}, ${properties.STATE}`;
|
|
74
|
+
}
|
|
75
|
+
else if (properties.STATE) {
|
|
76
|
+
final = `${properties.STATE}${shapefile.id}${properties.ZONE ?? properties.SITE_ID}`;
|
|
77
|
+
location = `${properties.NAME ?? `${properties.RFC_NAME} ${properties.RFC_CITY}`}, ${properties.STATE}`;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
final = properties.ID ?? properties.WFO
|
|
81
|
+
location = properties.NAME;
|
|
82
|
+
}
|
|
83
|
+
insert.run(final, location, JSON.stringify(geometry));
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
fs.unlinkSync(`${filepath}.shp`)
|
|
87
|
+
fs.unlinkSync(`${filepath}.dbf`)
|
|
88
|
+
setWarning({ message: `Cleaned up temporary files for ${shapefile.name}_${shapefile.id}` })
|
|
89
|
+
transaction(features)
|
|
90
|
+
}
|
|
91
|
+
setWarning({ message: `Shapefiles have finished compiling, you can now continue and close this terminal` })
|
|
92
|
+
fs.rm(resolve(__dirname, '../../shapefiles'), { recursive: true, force: true }, () => {});
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
setWarning( {message: `An error occurred while compiling shapefiles: ${error.message}` })
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
import { bootstrap } from '../../bootstrap'
|
|
22
|
+
import { setWarning } from '../@utilities/utilities.setWarning';
|
|
23
|
+
import { TypeSettings } from "../../@types/types.settings"
|
|
24
|
+
import { TypeStanzaCompiled } from '../../@types/types.compiled';
|
|
25
|
+
|
|
26
|
+
export const importStanza = async (stanza: TypeStanzaCompiled): Promise<void> => {
|
|
27
|
+
const settings = bootstrap.settings as TypeSettings;
|
|
28
|
+
try {
|
|
29
|
+
bootstrap.database
|
|
30
|
+
.prepare(`INSERT OR IGNORE INTO stanzas (type, stanza, issued) VALUES (?, ?, ?)`)
|
|
31
|
+
.run(stanza.getType.type, JSON.stringify(stanza), stanza.attributes.issue)
|
|
32
|
+
const count = bootstrap.database
|
|
33
|
+
.prepare(`SELECT COUNT(*) as total FROM stanzas`)
|
|
34
|
+
.get() as { total: number }
|
|
35
|
+
const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxDatabaseHistory;
|
|
36
|
+
if (count.total > max) {
|
|
37
|
+
const toDelete = count.total - max;
|
|
38
|
+
if (toDelete > 0) {
|
|
39
|
+
bootstrap.database
|
|
40
|
+
.prepare(`DELETE FROM stanzas WHERE id IN (SELECT id FROM stanzas ORDER BY issued ASC LIMIT ?)`)
|
|
41
|
+
.run(toDelete);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
setWarning({ message: `An error occurred while importing stanza: ${error.message}` })
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { TypeAttributes } from "../../@types/types.attributes"
|
|
21
|
+
import { eventAwipAbreviations } from "../../@dictionaries/dictionaries.eventAwipAbreviations"
|
|
22
|
+
|
|
23
|
+
interface ValidateOptions {
|
|
24
|
+
attributes: TypeAttributes
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface ValidiateResponse {
|
|
28
|
+
type: string
|
|
29
|
+
prefix: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const getAwipsType = (options: ValidateOptions): ValidiateResponse => {
|
|
33
|
+
const attributes = options.attributes;
|
|
34
|
+
if (!attributes.awipsid) {
|
|
35
|
+
return {
|
|
36
|
+
type: null,
|
|
37
|
+
prefix: null
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const [prefix, type] of Object.entries(eventAwipAbreviations)) {
|
|
41
|
+
if (attributes.awipsid.startsWith(prefix)) {
|
|
42
|
+
return { type, prefix }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { type: null, prefix: null }
|
|
46
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { TypeStanza } from "../../@types/types.stanza"
|
|
21
|
+
import { TypeStanzaCompiled } from "../../@types/types.compiled"
|
|
22
|
+
import { regExp } from "../../@dictionaries/dictionaries.regExp"
|
|
23
|
+
import { getAwipsType } from "./stanza.getAwipsType"
|
|
24
|
+
|
|
25
|
+
interface ValidateOptions {
|
|
26
|
+
stanza: TypeStanza
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const validate = (options: ValidateOptions): TypeStanzaCompiled => {
|
|
30
|
+
if (options.stanza.is(`message`)) {
|
|
31
|
+
const cb = options.stanza.getChild(`x`) as TypeStanza;
|
|
32
|
+
if (cb && cb.children) {
|
|
33
|
+
const message = unescape(cb.children[0]);
|
|
34
|
+
const attributes = cb.attrs;
|
|
35
|
+
if (attributes.awipsid && attributes.awipsid.length > 1) {
|
|
36
|
+
const isCapEvent = message.includes(`<?xml`);
|
|
37
|
+
const isCapAreaDescription = message.includes(`<areaDesc>`)
|
|
38
|
+
const isVTEC = message.match(regExp.pvtec) != null;
|
|
39
|
+
const isUGC = message.match(regExp.ugc1) != null;
|
|
40
|
+
const getType = getAwipsType({ attributes: attributes})
|
|
41
|
+
if (getType.type != null) {
|
|
42
|
+
return {
|
|
43
|
+
message, attributes, isCapEvent, isVTEC, isUGC, isCapAreaDescription, isIgnored: false, isNWWS: true, getType
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { isIgnored: true}
|
|
50
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import request from 'request'
|
|
21
|
+
|
|
22
|
+
interface ImportOptions {
|
|
23
|
+
proxy?: string
|
|
24
|
+
url?: string
|
|
25
|
+
headers?: any
|
|
26
|
+
timeout?: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const createHttp = async (options: ImportOptions): Promise<any> => {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const requestOptions = {
|
|
32
|
+
url: options.url ?? `https://api.weather.gov/alerts/active`,
|
|
33
|
+
headers: options.headers ?? {
|
|
34
|
+
"User-Agent": "AtmosphericX",
|
|
35
|
+
"Accept": "application/geo+json, text/plain, */*; q=0.9",
|
|
36
|
+
"Accept-Language": "en-US,en;q=0.9"
|
|
37
|
+
},
|
|
38
|
+
timeout: options.timeout ?? 10e3,
|
|
39
|
+
proxy: options.proxy ?? null,
|
|
40
|
+
maxRedirects: 1,
|
|
41
|
+
};
|
|
42
|
+
request(requestOptions, (error, response, body) => {
|
|
43
|
+
if (error) {
|
|
44
|
+
return resolve({
|
|
45
|
+
error: true,
|
|
46
|
+
options: requestOptions,
|
|
47
|
+
status: -1,
|
|
48
|
+
message: error.message ?? `Unknown Error`
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
if (response.statusCode !== 200) {
|
|
52
|
+
return resolve({
|
|
53
|
+
error: true,
|
|
54
|
+
options: requestOptions,
|
|
55
|
+
status: response.statusCode ?? -1,
|
|
56
|
+
message: `HTTP Status Code ${response.statusCode ?? `Unknown Status Code`}`
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
if (body == undefined || body == null) {
|
|
60
|
+
return resolve({
|
|
61
|
+
error: true,
|
|
62
|
+
options: requestOptions,
|
|
63
|
+
status: response.statusCode ?? -1,
|
|
64
|
+
message: `Empty Response Body`
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
resolve({
|
|
68
|
+
error: false,
|
|
69
|
+
options: requestOptions,
|
|
70
|
+
status: response.statusCode ?? -1,
|
|
71
|
+
message: body
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export const getFormattedTime = (date: string): string => {
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
const then = typeof date === "number" ? date : new Date(date).getTime()
|
|
24
|
+
const seconds = Math.floor((now - then) / 1000);
|
|
25
|
+
const absSeconds = Math.abs(seconds);
|
|
26
|
+
const isPast = seconds > 0;
|
|
27
|
+
const units: [string, number][] = [
|
|
28
|
+
["year", 31536000], ["month", 2592000],
|
|
29
|
+
["day", 86400], ["hour", 3600],
|
|
30
|
+
["minute", 60], ["second", 1],
|
|
31
|
+
];
|
|
32
|
+
for (const [name, value] of units) {
|
|
33
|
+
const interval = Math.floor(absSeconds / value);
|
|
34
|
+
if (interval >= 1) {
|
|
35
|
+
return isPast
|
|
36
|
+
? `${interval} ${name}${interval > 1 ? "s" : ""} ago`
|
|
37
|
+
: `in ${interval} ${name}${interval > 1 ? "s" : ""}`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return "just now";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { TypeSettings } from '../../@types/types.settings'
|
|
21
|
+
import { bootstrap } from "../../bootstrap"
|
|
22
|
+
|
|
23
|
+
export const getSettings = (): TypeSettings => {
|
|
24
|
+
return bootstrap.settings;
|
|
25
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
interface GetShapeNearestPointResponse {
|
|
21
|
+
proximity: boolean
|
|
22
|
+
point: [number, number]
|
|
23
|
+
distance: number | null
|
|
24
|
+
distanceKm?: number | null
|
|
25
|
+
distanceMeters?: number | null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const getShapeNearestPoint = (coordinates: number[][], point: [number, number]): GetShapeNearestPointResponse => {
|
|
29
|
+
if (!coordinates || !point) {
|
|
30
|
+
return { proximity: false, point: [0, 0], distance: null }
|
|
31
|
+
}
|
|
32
|
+
const normalize = (coords: any): any[] => {
|
|
33
|
+
if (!Array.isArray(coords)) return [];
|
|
34
|
+
if (typeof coords[0] === 'number' && typeof coords[1] === 'number') return [];
|
|
35
|
+
if (Array.isArray(coords[0]) && typeof coords[0][0] === 'number') {
|
|
36
|
+
return [[coords]];
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(coords[0]) && Array.isArray(coords[0][0]) && typeof coords[0][0][0] === 'number') {
|
|
39
|
+
return [coords];
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(coords[0]) && Array.isArray(coords[0][0]) && Array.isArray(coords[0][0][0]) && typeof coords[0][0][0][0] === 'number') {
|
|
42
|
+
return coords;
|
|
43
|
+
}
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const polys = normalize(coordinates);
|
|
47
|
+
if (polys.length === 0) return { proximity: false, point: [0, 0], distance: null };
|
|
48
|
+
const lon = point[0];
|
|
49
|
+
const lat = point[1];
|
|
50
|
+
const pointInRing = (pt: [number, number], ring: number[][]): boolean => {
|
|
51
|
+
let x = pt[0], y = pt[1];
|
|
52
|
+
let inside = false;
|
|
53
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
54
|
+
const xi = ring[i][0], yi = ring[i][1];
|
|
55
|
+
const xj = ring[j][0], yj = ring[j][1];
|
|
56
|
+
const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi + 0) + xi);
|
|
57
|
+
if (intersect) inside = !inside;
|
|
58
|
+
}
|
|
59
|
+
return inside;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const toRadians = (deg: number) => (deg * Math.PI) / 180;
|
|
63
|
+
const haversineMiles = (a: [number, number], b: [number, number]) => {
|
|
64
|
+
const R = 3958.8;
|
|
65
|
+
const dLat = toRadians(b[1] - a[1]);
|
|
66
|
+
const dLon = toRadians(b[0] - a[0]);
|
|
67
|
+
const lat1 = toRadians(a[1]);
|
|
68
|
+
const lat2 = toRadians(b[1]);
|
|
69
|
+
const sinDLat = Math.sin(dLat / 2);
|
|
70
|
+
const sinDLon = Math.sin(dLon / 2);
|
|
71
|
+
const c = 2 * Math.asin(Math.sqrt(sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon));
|
|
72
|
+
return R * c;
|
|
73
|
+
};
|
|
74
|
+
let minDistance = Infinity;
|
|
75
|
+
let closestPoint: [number, number] | null = null;
|
|
76
|
+
for (const poly of polys) {
|
|
77
|
+
const outer = poly[0];
|
|
78
|
+
const holes = poly.slice(1);
|
|
79
|
+
if (pointInRing(point, outer)) {
|
|
80
|
+
let inHole = false;
|
|
81
|
+
for (const hole of holes) {
|
|
82
|
+
if (pointInRing(point, hole)) { inHole = true; break; }
|
|
83
|
+
}
|
|
84
|
+
if (!inHole) {
|
|
85
|
+
return { proximity: true, point, distance: 0 };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const ring of poly) {
|
|
89
|
+
for (let i = 0; i < ring.length - 1; i++) {
|
|
90
|
+
const start = [ring[i][0], ring[i][1]] as [number, number];
|
|
91
|
+
const end = [ring[i+1][0], ring[i+1][1]] as [number, number];
|
|
92
|
+
const A = lon - start[0];
|
|
93
|
+
const B = lat - start[1];
|
|
94
|
+
const C = end[0] - start[0];
|
|
95
|
+
const D = end[1] - start[1];
|
|
96
|
+
const lenSq = C*C + D*D;
|
|
97
|
+
const t = lenSq === 0 ? 0 : Math.max(0, Math.min(1, (A*C + B*D) / lenSq));
|
|
98
|
+
const candidate: [number, number] = [start[0] + t*C, start[1] + t*D];
|
|
99
|
+
const dist = haversineMiles([lon, lat], candidate);
|
|
100
|
+
if (!isNaN(dist) && dist < minDistance) {
|
|
101
|
+
minDistance = Number(dist.toFixed(3));
|
|
102
|
+
closestPoint = candidate;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!isFinite(minDistance) || closestPoint == null) {
|
|
108
|
+
return { proximity: false, point: [0,0], distance: null };
|
|
109
|
+
}
|
|
110
|
+
const distanceMiles = minDistance;
|
|
111
|
+
const distanceKm = Number((distanceMiles * 1.609344).toFixed(3));
|
|
112
|
+
const distanceMeters = Math.round(distanceKm * 1000);
|
|
113
|
+
return { proximity: distanceMiles === 0, point: closestPoint, distance: distanceMiles, distanceKm, distanceMeters };
|
|
114
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { TypeSettings } from "../../@types/types.settings";
|
|
22
|
+
import { xReconnect } from "../@xmpp/xmpp.xReconnect"
|
|
23
|
+
import { callback } from "../../@core/core.callback"
|
|
24
|
+
import { bootstrap } from "../../bootstrap";
|
|
25
|
+
import { updateNodes } from "../../@manager/manager.updateNodes";
|
|
26
|
+
|
|
27
|
+
export const setCronSchedule = async (): Promise<void> => {
|
|
28
|
+
const settings = bootstrap.settings as TypeSettings;
|
|
29
|
+
if (settings.EnableWireService) {
|
|
30
|
+
if (settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.Enabled) {
|
|
31
|
+
void xReconnect(settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.ReconnectionInterval)
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
await callback();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { bootstrap } from "../../bootstrap"
|
|
21
|
+
import { setTimeoutAction } from "./utilities.setTimeoutAction";
|
|
22
|
+
import { setWarning } from "./utilities.setWarning";
|
|
23
|
+
|
|
24
|
+
interface SetEventEmitOptions {
|
|
25
|
+
event: string
|
|
26
|
+
metadata: any
|
|
27
|
+
message?: string
|
|
28
|
+
limited?: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const setEventEmit = (options: SetEventEmitOptions): void => {
|
|
32
|
+
if (options.limited) {
|
|
33
|
+
const isTimeout = setTimeoutAction({ identifier: `event.${options.event}`, addTime: true, max: 1, interval: 1 })
|
|
34
|
+
if (isTimeout.limited) return;
|
|
35
|
+
}
|
|
36
|
+
bootstrap.listener.emit(options.event, options.metadata)
|
|
37
|
+
if (options.event != `log`) { bootstrap.listener.emit(`*`, {event: options.event, data: options.metadata}) }
|
|
38
|
+
if (options.message) {
|
|
39
|
+
setWarning({ message: options.message })
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { bootstrap } from "../../bootstrap"
|
|
21
|
+
|
|
22
|
+
interface ImportOptions {
|
|
23
|
+
event: string,
|
|
24
|
+
callback: () => void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const setListener = (options: ImportOptions): (() => void) => {
|
|
28
|
+
bootstrap.listener.on(options.event, options.callback)
|
|
29
|
+
return () => { void bootstrap.listener.off(options.event, options.callback) };
|
|
30
|
+
}
|