UNPKG

@tak-ps/node-cot

Version:

Lightweight JavaScript library for parsing and manipulating TAK messages

196 lines (167 loc) 5.86 kB
import { convertLetterSidc2NumberSidc } from "@orbat-mapper/convert-symbology"; export enum Domain { ATOM = 'a', BITS = 'b', REFERENCE = 'r', TASK = 't', CAPABILITY = 'c', REPLY = 'y', } export enum StandardIdentity { PENDING = 'p', UNKNOWN = 'u', ASSUMED_FRIEND = 'a', FRIEND = 'f', NEUTRAL = 'n', SUSPECT = 's', HOSTILE = 'h', JOKER = 'j', FAKER = 'k', NONE = 'o' } export const SID_MAP: Record<string, string> = { P: "00", // pending U: "01", // unknown A: "02", // assumed friend F: "03", // friend N: "04", // neutral S: "05", // suspect H: "06", // hostile G: "10", // exercise pending W: "11", // exercise unknown M: "12", // exercise assumed friend D: "13", // exercise friend L: "14", // exercise neutral J: "15", // joker K: "16", // faker }; export const STATUS_MAP: Record<string, string> = { P: "0", // present A: "1", // anticipated/planned C: "2", // present fully capable D: "3", // present damaged X: "4", // present destroyed F: "5", // present full to capacity }; export const DIM_MAP: Record<string, string> = { P: '05', // Space A: '01', // Air G: '10', // Ground S: '30', // SeaSurface U: '35', // SubSurface F: '10', // SOF Z: '10', // Unknown X: '10' // Unknown } /** * @class * * Convert a COT Atom Type to/from Symbol Identification Code (SIDC) * Migrated to TypeScript from the original Kotlin verison * @ https://github.com/cyberpython/kotcot under the MIT License */ export default class Type2525 { /** * Check a given COT Type to see if it is compatible with conversion to SIDC * * @param cotType - Cursor On Target Type to test */ static is2525BConvertable(cotType: string): boolean { return !!cotType.match(/^a-[PUAFNSHJKOXpuafnshjkox]-[PAGSUFXZ](-\w+)*$/); } static domain(cotType: string): Domain { const unknownDomain = cotType.split('-')[0]; const d = enumFromStringValue<Domain>(Domain, unknownDomain); if (d) { return d; } else { throw new Error('Domain could not be determined'); } } static standardIdentity(cotType: string): StandardIdentity { if (!cotType.startsWith('a-')) return StandardIdentity.NONE; if (cotType.split('-').length < 2) return StandardIdentity.NONE; const unknownIdentity = cotType.split('-')[1]; const si = enumFromStringValue(StandardIdentity, unknownIdentity); if (si) { return si; } else { return StandardIdentity.NONE; } } /** * Given a COT Atom Type, return an SIDC in 2525D format * * @param cotType - Cursor On Target Type (Note must start with atomic "a") */ static to2525D(cotType: string): string { const str_sidc = this.to2525B(cotType); // Handle Short Codes Manually if (str_sidc.match(/^S[A-Z]{3}-{11}/)) { const AFF = str_sidc[1].toUpperCase() const DIM = str_sidc[2].toUpperCase() const STS = str_sidc[3].toUpperCase() return '12' + SID_MAP[AFF] + DIM_MAP[DIM] + STATUS_MAP[STS] + '0000000000000'; } else { const convert = convertLetterSidc2NumberSidc(str_sidc); if (!convert.sidc) { throw new Error(`Could not convert 2525B SIDC to 2525D`); } return convert.sidc; } } /** * Given a COT Atom Type, return an SIDC * * @param cotType - Cursor On Target Type (Note must start with atomic "a") */ static to2525B(cotType: string): string { if (!this.is2525BConvertable(cotType)) { throw new TypeError("CoT to 2525B can only be applied to well-formed Atom type CoT Events.") } const m2525bChars = cotType.substring(4).replace(/[^A-Z0-9]+/g, ""); const m2525bBattleDim = m2525bChars.substring(0, 1); const cotAffiliation = cotType.substring(2, 3); const m2525bAffiliation = (cotAffiliation === "o" || cotAffiliation === "x") ? "U" : cotAffiliation.toUpperCase(); const m2525bFuncId = m2525bChars.length > 1 ? m2525bChars.substring(1).padEnd(6, "-").substring(0, 6) : "------"; return `S${m2525bAffiliation}${m2525bBattleDim}P${m2525bFuncId}-----`; } /** * Check a given SIDC to see if it is compatible with conversion to CoT Type * * @param sidc - SIDC to test */ static isTypeConvertable(sidc: string): boolean { return !!sidc.match(/^S[PUAFNSHGWMDLJK-][PAGSUFXZ-][AP-][A-Z0-9-]{10}[AECGNS-]$/) } /** * Given an SIDC, return a CoT Type * * @param sidc - SIDC to convert */ static from2525B(sidc: string) : string { if (!this.isTypeConvertable(sidc)) { throw new Error("2525B to CoT can only be applied to well-formed warfighting 2525B SIDCs."); } const m2525bAffiliation = sidc.substring(1, 2); const cotAffiliation = ["G", "W", "M", "D", "L"].includes(m2525bAffiliation) ? "f" : m2525bAffiliation === "-" ? "o" : m2525bAffiliation.toLowerCase(); const cotBattleDim = sidc.substring(2, 3); const cotFuncId = Array.from(sidc.substring(4, 10).replace(/[^A-Z0-9]+/g, "")) .map((x) => `-${x}`) .join(""); return `a-${cotAffiliation}-${cotBattleDim}${cotFuncId}`; } } function enumFromStringValue<T> (enm: { [s: string]: T}, value: string): T | undefined { return (Object.values(enm) as unknown as string[]).includes(value) ? value as unknown as T : undefined; }