Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chat support #11

Merged
merged 17 commits into from
Jan 23, 2024
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
- name: Install
run: npm install

- name: Build
run: npm run build

- name: Lint
run: npm run lint

Expand Down
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,34 @@

## Version History

### v5.0.5

- :bug: Object Defs

### v5.0.4

- :bug: Optional `_flow-tags_._attributes`

### v5.0.3

- :bug: `remarks._text` is optional

### v5.0.2

- :bug: `remarks._attributes` is optional

### v5.0.1

- :bug: Add `package.json` in `dist/`

### v5.0.0

- :tada: `schema.json` is now automatically generated from Type Defs
- :tada: Add Chat interface for easily creating Direct Messages
- :rocket: Add Flow Tag when parsed by NodeCoT
- :arrow_up: Update Typescript
- :white_check_mark: Add Chat & Flow tests

### v4.6.0

- :rocket: Decode `__group` to `.properties.group`
Expand Down
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CoT from './lib/cot.js';
export * from './lib/chat.js'

export default CoT;
73 changes: 73 additions & 0 deletions lib/chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Util from './util.js'
import CoT from './cot.js';
import JSONCoT from './types.js';
import { randomUUID } from 'node:crypto';

export type DirectChatMember = {
uid: string;
callsign: string;
}

export type DirectChatInput = {
to: DirectChatMember;
from: DirectChatMember;

message: string;

parent?: string;
chatroom?: string;
groupOwner?: boolean;
messageId?: string;
id?: string;
}

export class DirectChat extends CoT {
constructor(chat: DirectChatInput) {
const cot: JSONCoT = {
event: {
_attributes: Util.cot_event_attr('b-t-f', 'h-g-i-g-o'),
point: Util.cot_point(),
detail: {
__chat: {
_attributes: {
parent: chat.parent || 'RootContactGroup',
groupOwner: chat.groupOwner ? 'true' : 'false',
messageId: chat.messageId || randomUUID(),
chatroom: chat.chatroom || chat.to.callsign,
id: chat.to.uid,
senderCallsign: chat.from.callsign
},
chatgrp: {
_attributes: {
uid0: chat.from.uid,
uid1: chat.to.uid,
id: chat.to.uid
}
}
},
}
}
}

cot.event._attributes.uid = `GeoChat.${chat.from.uid}.${chat.to.uid}.${randomUUID()}`;

cot.event.detail.link = {
_attributes: {
uid: chat.from.uid,
type: 'a-f-G',
relation: 'p-p'
}
}

cot.event.detail.remarks = {
_attributes: {
source: chat.from.uid,
to: chat.to.uid,
time: cot.event._attributes.time
},
_text: chat.message
}

super(cot)
}
}
82 changes: 19 additions & 63 deletions lib/cot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,74 +4,18 @@ import { AllGeoJSON } from "@turf/helpers";
import Util from './util.js';
import Color from './color.js';
import PointOnFeature from '@turf/point-on-feature';
import JSONCoT from './types.js'
import AJV from 'ajv';
import fs from 'fs';

const schema = JSON.parse(String(fs.readFileSync(new URL('./schema.json', import.meta.url))));
const ajv = (new AJV({ allErrors: true }))
.compile(schema);

export interface Attributes {
version: string,
uid: string;
type: string;
how: string;
[k: string]: string;
}

export interface GenericAttributes {
_attributes: {
[k: string]: string;
}
}

export interface Track {
_attributes: TrackAttributes;
}

export interface TrackAttributes {
speed: string,
course: string,
[k: string]: string
}

export interface Detail {
contact?: GenericAttributes,
tog?: GenericAttributes,
strokeColor?: GenericAttributes,
strokeWeight?: GenericAttributes,
strokeStyle?: GenericAttributes,
labels_on?: GenericAttributes,
fillColor?: GenericAttributes,
link?: GenericAttributes[],
usericon?: GenericAttributes,
track?: Track,
TakControl?: {
TakServerVersionInfo?: GenericAttributes
},
[k: string]: unknown
}
const pkg = JSON.parse(String(fs.readFileSync(new URL('../package.json', import.meta.url))));

export interface Point {
_attributes: {
lat: string | number;
lon: string | number;
hae: string | number;
ce: string | number;
le: string | number;
[k: string]: string | number
}
}

export interface JSONCoT {
event: {
_attributes: Attributes,
detail: Detail,
point: Point,
[k: string]: unknown
},
[k: string]: unknown
}
const ajv = (new AJV({
allErrors: true,
allowUnionTypes: true
}))
.compile(schema);

/**
* Convert to and from an XML CoT message
Expand All @@ -98,6 +42,9 @@ export default class CoT {

ajv(this.raw);
if (ajv.errors) throw new Error(`${ajv.errors[0].message} (${ajv.errors[0].instancePath})`);

if (!this.raw.event.detail['_flow-tags_']) this.raw.event.detail['_flow-tags_'] = {};
this.raw.event.detail['_flow-tags_'][`NodeCoT-${pkg.version}`] = new Date().toISOString()
}

/**
Expand Down Expand Up @@ -377,6 +324,15 @@ export default class CoT {
});
}

/**
* Determines if the CoT message represents a Chat Message
*
* @return {boolean}
*/
is_chat(): boolean {
return !!(this.raw.event.detail && this.raw.event.detail.__chat);
}

/**
* Determines if the CoT message represents a Friendly Element
*
Expand Down
Loading
Loading