-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
task.ts
132 lines (112 loc) · 4.14 KB
/
task.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import Simplify from '@turf/simplify';
import { FeatureCollection, Feature } from 'geojson';
import { Type, TSchema } from '@sinclair/typebox';
import ETL, { Event, SchemaType, handler as internal, local, env } from '@tak-ps/etl';
const Environment = Type.Object({
URL: Type.String(),
QueryParams: Type.Optional(Type.Array(Type.Object({
key: Type.String(),
value: Type.String()
}))),
Headers: Type.Optional(Type.Array(Type.Object({
key: Type.String(),
value: Type.String()
}))),
RemoveID: Type.Boolean({
default: false,
description: 'Remove the provided ID falling back to an Object Hash or Style Override'
}),
ShowTrackHistory: Type.Boolean({
default: true,
description: 'If true pass through historic track'
}),
SimplifyTrackHistory: Type.Boolean({
default: false,
description: 'Apply a simplification algo to the track history'
}),
SimplifyTrackHistoryTolerance: Type.String({
default: '1',
description: 'Simplification tolerance for Ramer-Douglas-Peucker algorithm'
})
});
export default class Task extends ETL {
async schema(type: SchemaType = SchemaType.Input): Promise<TSchema> {
if (type === SchemaType.Input) {
return Environment
} else {
return Type.Object({})
}
}
async control(): Promise<void> {
const env = await this.env(Environment);
const url = new URL(env.URL);
for (const param of env.QueryParams || []) {
url.searchParams.append(param.key, param.value);
}
const headers: Record<string, string> = {};
for (const header of env.Headers || []) {
headers[header.key] = header.value;
}
const res = await fetch(url, {
method: 'GET',
headers
});
// TODO: Type the response
const body: any = await res.json();
// This should be done by the API but it doesn't seem consistent
if (url.searchParams.get('satellite')) {
const satellite = url.searchParams.get('satellite');
body.features = body.features.filter((f: Feature) => {
return f.properties.name.toLowerCase() === satellite.toLowerCase();
});
}
if (body.type !== 'FeatureCollection') {
throw new Error('Only FeatureCollection is supported');
}
const fc: FeatureCollection = {
type: 'FeatureCollection',
features: []
};
if (body.features.length > 2) {
throw new Error('API Should only return 2 features');
}
for (const feat of body.features) {
if (env.RemoveID) delete feat.id;
if (feat.geometry.type === 'Point') {
feat.geometry.coordinates.push(feat.properties.altitude);
fc.features.push({
id: `strato-${feat.properties.name}-current`,
type: 'Feature',
properties: {
course: feat.properties.course,
speed: feat.properties.speed,
metadata: feat.properties
},
geometry: feat.geometry
});
} else if (env.ShowTrackHistory) {
if (env.SimplifyTrackHistory) {
Simplify(feat, {
tolerance: Number(env.SimplifyTrackHistoryTolerance) || 1,
mutate: true
})
}
fc.features.push({
id: `strato-${feat.properties.name}-history`,
type: 'Feature',
properties: {
metadata: feat.properties
},
geometry: feat.geometry
});
}
}
console.log(`ok - obtained ${fc.features.length} features`);
await this.submit(fc);
}
}
env(import.meta.url)
await local(new Task(), import.meta.url);
export async function handler(event: Event = {}) {
return await internal(new Task(), event);
}