@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.
Files changed (116) hide show
  1. package/README.md +4 -237
  2. package/dist/cjs/index.cjs +2233 -3100
  3. package/dist/esm/index.mjs +2233 -3103
  4. package/package.json +3 -3
  5. package/src/@building/building.clean.ts +30 -0
  6. package/src/@building/building.create.ts +42 -0
  7. package/src/@building/building.enhance.ts +56 -0
  8. package/src/@building/building.geometry.ts +42 -0
  9. package/src/@building/building.headers.ts +37 -0
  10. package/src/@building/building.office.ts +43 -0
  11. package/src/@building/building.polygon.ts +71 -0
  12. package/src/@building/building.properties.ts +89 -0
  13. package/src/@building/building.signature.ts +78 -0
  14. package/src/@building/building.tags.ts +24 -0
  15. package/src/@building/building.tracking.ts +68 -0
  16. package/src/@building/building.validate.ts +132 -0
  17. package/src/@core/core.callback.ts +39 -0
  18. package/src/@core/core.getEvents.ts +25 -0
  19. package/src/@core/core.getNodes.ts +25 -0
  20. package/src/@core/core.listener.ts +24 -0
  21. package/src/@core/core.setNode.ts +81 -0
  22. package/src/@core/core.start.ts +54 -0
  23. package/src/@core/core.stop.ts +32 -0
  24. package/src/@dictionaries/dictionaries.betterEventNames.ts +85 -0
  25. package/src/@dictionaries/dictionaries.eventActions.ts +28 -0
  26. package/src/@dictionaries/{awips.ts → dictionaries.eventAwipAbreviations.ts} +12 -6
  27. package/src/@dictionaries/dictionaries.eventCancelMessages.ts +29 -0
  28. package/src/@dictionaries/dictionaries.eventCauses.ts +36 -0
  29. package/src/@dictionaries/dictionaries.eventProducts.ts +25 -0
  30. package/src/@dictionaries/dictionaries.eventRecords.ts +25 -0
  31. package/src/@dictionaries/dictionaries.eventSeverity.ts +27 -0
  32. package/src/@dictionaries/dictionaries.eventStatus.ts +31 -0
  33. package/src/@dictionaries/{signatures.ts → dictionaries.eventTags.ts} +13 -68
  34. package/src/@dictionaries/dictionaries.eventTypes.ts +82 -0
  35. package/src/@dictionaries/dictionaries.eventsOffshore.ts +31 -0
  36. package/src/@dictionaries/dictionaries.hailStrings.ts +31 -0
  37. package/src/@dictionaries/{icao.ts → dictionaries.officeICAOs.ts} +13 -6
  38. package/src/@dictionaries/dictionaries.regExp.ts +28 -0
  39. package/src/@dictionaries/dictionaries.shapefileLinks.ts +36 -0
  40. package/src/@dictionaries/dictionaries.statusCorrelationText.ts +40 -0
  41. package/src/@dictionaries/dictionaries.test_signatures.ts +23 -0
  42. package/src/@dictionaries/dictionaries.transcribedMessageReplacements.ts +68 -0
  43. package/src/@events/events.api.ts +113 -0
  44. package/src/@events/events.text.ts +79 -0
  45. package/src/@events/events.ugc.ts +83 -0
  46. package/src/@events/events.vtec.ts +87 -0
  47. package/src/@manager/manager.mkEvent.ts +79 -0
  48. package/src/@manager/manager.rmEvent.ts +44 -0
  49. package/src/@manager/manager.setHash.ts +37 -0
  50. package/src/@manager/manager.updateNodes.ts +51 -0
  51. package/src/@modules/@database/database.cache.ts +48 -0
  52. package/src/@modules/@database/database.init.ts +45 -0
  53. package/src/@modules/@database/database.shapefiles.ts +97 -0
  54. package/src/@modules/@database/database.stanza.ts +47 -0
  55. package/src/@modules/@stanza/stanza.getAwipsType.ts +46 -0
  56. package/src/@modules/@stanza/stanza.validate.ts +50 -0
  57. package/src/@modules/@utilities/utilities.createHttp.ts +75 -0
  58. package/src/@modules/@utilities/utilities.getFormattedTime.ts +43 -0
  59. package/src/@modules/@utilities/utilities.getSettings.ts +25 -0
  60. package/src/@modules/@utilities/utilities.getShapeNearestPoint.ts +114 -0
  61. package/src/@modules/@utilities/utilities.setCronSchedule.ts +38 -0
  62. package/src/@modules/@utilities/utilities.setEventEmit.ts +41 -0
  63. package/src/@modules/@utilities/utilities.setListener.ts +30 -0
  64. package/src/@modules/@utilities/utilities.setSettings.ts +42 -0
  65. package/src/@modules/@utilities/utilities.setSleep.ts +33 -0
  66. package/src/@modules/@utilities/utilities.setTimeoutAction.ts +59 -0
  67. package/src/@modules/@utilities/utilities.setWarning.ts +34 -0
  68. package/src/@modules/@xmpp/xmpp.xDeploy.ts +58 -0
  69. package/src/@modules/@xmpp/xmpp.xError.ts +38 -0
  70. package/src/@modules/@xmpp/xmpp.xOffline.ts +38 -0
  71. package/src/@modules/@xmpp/xmpp.xOnline.ts +61 -0
  72. package/src/@modules/@xmpp/xmpp.xReconnect.ts +59 -0
  73. package/src/@modules/@xmpp/xmpp.xStanza.ts +63 -0
  74. package/src/@parsers/@hvtec/hvtec.extract.ts +40 -0
  75. package/src/@parsers/@pvtec/pvtec.expires.ts +26 -0
  76. package/src/@parsers/@pvtec/pvtec.extract.ts +50 -0
  77. package/src/@parsers/@text/text.getDescriptionFromProduct.ts +53 -0
  78. package/src/@parsers/@text/text.getPolygonFromProduct.ts +32 -0
  79. package/src/@parsers/@text/text.getTextFromProduct.ts +43 -0
  80. package/src/@parsers/@text/text.getXML.ts +61 -0
  81. package/src/@parsers/@ugc/ugc.coordinates.ts +110 -0
  82. package/src/@parsers/@ugc/ugc.expiry.ts +32 -0
  83. package/src/@parsers/@ugc/ugc.extract.ts +37 -0
  84. package/src/@parsers/@ugc/ugc.header.ts +30 -0
  85. package/src/@parsers/@ugc/ugc.locations.ts +29 -0
  86. package/src/@parsers/@ugc/ugc.zones.ts +52 -0
  87. package/src/@types/type.event.ts +67 -0
  88. package/src/@types/type.properties.ts +75 -0
  89. package/src/@types/types.attributes.ts +28 -0
  90. package/src/@types/types.compiled.ts +35 -0
  91. package/src/@types/types.hash.ts +24 -0
  92. package/src/@types/types.hvtec.ts +25 -0
  93. package/src/@types/types.pvtec.ts +29 -0
  94. package/src/@types/types.settings.ts +71 -0
  95. package/src/@types/types.stanza.ts +37 -0
  96. package/src/@types/types.ugc.ts +24 -0
  97. package/src/bootstrap.ts +82 -164
  98. package/src/index.ts +48 -216
  99. package/test.js +65 -49
  100. package/src/@dictionaries/events.ts +0 -168
  101. package/src/@parsers/@events/api.ts +0 -146
  102. package/src/@parsers/@events/cap.ts +0 -123
  103. package/src/@parsers/@events/text.ts +0 -104
  104. package/src/@parsers/@events/ugc.ts +0 -107
  105. package/src/@parsers/@events/vtec.ts +0 -76
  106. package/src/@parsers/events.ts +0 -392
  107. package/src/@parsers/hvtec.ts +0 -46
  108. package/src/@parsers/pvtec.ts +0 -72
  109. package/src/@parsers/stanza.ts +0 -97
  110. package/src/@parsers/text.ts +0 -165
  111. package/src/@parsers/ugc.ts +0 -247
  112. package/src/@submodules/database.ts +0 -200
  113. package/src/@submodules/eas.ts +0 -490
  114. package/src/@submodules/utils.ts +0 -184
  115. package/src/@submodules/xmpp.ts +0 -142
  116. 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
+ }