mobility-toolbox-js 1.6.3 → 1.6.4-beta.4

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.
@@ -32,7 +32,7 @@ class RoutingAPI extends API {
32
32
  *
33
33
  * @param {RoutingSearchParams} params Request parameters. See [Routing service documentation](https://developer.geops.io/apis/routing/).
34
34
  * @param {AbortController} abortController Abort controller used to cancel the request.
35
- * @returns {Promise<GeoJSONFeatureCollection>} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).
35
+ * @return {Promise<GeoJSONFeatureCollection>} An GeoJSON feature collection with coordinates in [EPSG:4326](http://epsg.io/4326).
36
36
  */
37
37
  route(params, abortController = new AbortController()) {
38
38
  return this.fetch('', params, {
@@ -29,7 +29,7 @@ class StopsAPI extends API {
29
29
  *
30
30
  * @param {StopsSearchParams} params Request parameters. See [Stops service documentation](https://developer.geops.io/apis/5dcbd702a256d90001cf1361/).
31
31
  * @param {AbortController} abortController Abort controller used to cancel the request.
32
- * @returns {Promise<Array<GeoJSONFeature>>} An array of GeoJSON features with coordinates in [EPSG:4326](http://epsg.io/4326).
32
+ * @return {Promise<Array<GeoJSONFeature>>} An array of GeoJSON features with coordinates in [EPSG:4326](http://epsg.io/4326).
33
33
  */
34
34
  search(params, abortController = {}) {
35
35
  return this.fetch('', params, {
@@ -33,7 +33,7 @@ class TrajservAPI extends API {
33
33
  *
34
34
  * @param {GetTrajectoryByIdParams} params Request parameters. See [Realtime service documentation](https://developer.geops.io/apis/5dcbd5c9a256d90001cf1360/#/default/get_trajectorybyid).
35
35
  * @param {AbortController} abortController Abort controller used to cancel the request.
36
- * @returns {Promise<TrajservTrajectory>} A trajectory.
36
+ * @return {Promise<TrajservTrajectory>} A trajectory.
37
37
  */
38
38
  fetchTrajectoryById(params, abortController = {}) {
39
39
  return this.fetch(`/trajectorybyid`, params, {
@@ -46,7 +46,7 @@ class TrajservAPI extends API {
46
46
  *
47
47
  * @param {GetTrajectoriesParams} params Request parameters. See [Realtime service documentation](https://developer.geops.io/apis/5dcbd5c9a256d90001cf1360/#/default/get_trajectory_collection).
48
48
  * @param {AbortController} abortController Abort controller used to cancel the request.
49
- * @returns {Promise<Array<Trajectory>>} A list of trajectories.
49
+ * @return {Promise<Array<Trajectory>>} A list of trajectories.
50
50
  */
51
51
  fetchTrajectories(params, abortController = {}) {
52
52
  return this.fetch(`/trajectory_collection`, params, {
@@ -61,7 +61,7 @@ class TrajservAPI extends API {
61
61
  *
62
62
  * @param {GetTrajectoryStationsParams} params Request parameters. See [Realtime service documentation](https://developer.geops.io/apis/5dcbd5c9a256d90001cf1360/#/default/get_trajstations).
63
63
  * @param {AbortController} abortController Abort controller used to cancel the request.
64
- * @returns {Promise<Array<TrajectoryStation>>} A list of stations.
64
+ * @return {Promise<Array<TrajectoryStation>>} A list of stations.
65
65
  */
66
66
  fetchTrajectoryStations(params, abortController = {}) {
67
67
  return this.fetch(`/trajstations`, params, {
@@ -2,7 +2,7 @@ import { LineString } from 'ol/geom';
2
2
 
3
3
  /**
4
4
  * Translate the response date object into a readable object.
5
- * @returns {Date[]}
5
+ * @return {Date[]}
6
6
  * @ignore
7
7
  */
8
8
  const translateDates = (dates = []) => {
@@ -21,7 +21,7 @@ const translateDates = (dates = []) => {
21
21
 
22
22
  /**
23
23
  * Translate the trajstations response into a readable object.
24
- * @returns {Object} returns a readable object
24
+ * @return {Object} returns a readable object
25
25
  * @private
26
26
  */
27
27
  export const translateTrajStationsResp = (data) => {
@@ -125,7 +125,7 @@ export const translateTrajStationsResp = (data) => {
125
125
 
126
126
  /**
127
127
  * Translate the trajectory_collection response into a js usable object.
128
- * @returns {Array} returns an array of trajectories.
128
+ * @return {Array} returns an array of trajectories.
129
129
  * @ignore
130
130
  */
131
131
  export const translateTrajCollResponse = (features = []) => {
@@ -21,7 +21,7 @@ export const TralisModes = {
21
21
  };
22
22
 
23
23
  /**
24
- * Access to Tralis service.
24
+ * This class provides convenience methods to access to the [geOps realtime api](https://developer.geops.io/apis/realtime/).
25
25
  *
26
26
  * @example
27
27
  * import { TralisAPI } from 'mobility-toolbox-js/api';
@@ -41,30 +41,14 @@ class TralisAPI {
41
41
  * Constructor
42
42
  *
43
43
  * @param {Object|string} options A string representing the url of the service or an object containing the url and the apiKey.
44
- * @param {string} options.url Service url.
45
- * @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/).
44
+ * @param {string} options.url Url to the [geOps realtime api](https://developer.geops.io/apis/realtime/).
45
+ * @param {string} options.apiKey Access key for [geOps apis](https://developer.geops.io/).
46
46
  * @param {string} [options.prefix=''] Service prefix to specify tenant.
47
- * @param {string} [options.projection] The epsg code of the projection for features.
48
- * @param {number[4]} [options.bbox=[minX, minY, maxX, maxY] The bounding box to receive data from.
47
+ * @param {string} [options.projection] The epsg code of the projection for features. Default to EPSG:3857.
48
+ * @param {number[4]} [options.bbox=[minX, minY, maxX, maxY, zoom, tenant] The bounding box to receive data from.
49
49
  */
50
50
  constructor(options = {}) {
51
- let wsUrl = null;
52
-
53
- if (typeof options === 'string') {
54
- wsUrl = options;
55
- } else {
56
- wsUrl = options.url;
57
- }
58
-
59
- if (options.apiKey) {
60
- wsUrl = `${wsUrl}?key=${options.apiKey}`;
61
- }
62
-
63
- /** @ignore */
64
- this.bbox = options.bbox;
65
-
66
- /** @ignore */
67
- this.projection = options.projection || 'EPSG:3857';
51
+ this.defineProperties(options);
68
52
 
69
53
  /** @ignore */
70
54
  this.subscribedStationUic = null;
@@ -81,37 +65,107 @@ class TralisAPI {
81
65
  /** @ignore */
82
66
  this.prefix = options.prefix || '';
83
67
 
84
- this.isUpdateBboxOnMoveEnd = options.isUpdateBboxOnMoveEnd || false;
85
-
86
68
  /** @ignore */
87
- this.conn = new WebSocketConnector(wsUrl);
69
+ this.onOpen = this.onOpen.bind(this);
70
+ }
71
+
72
+ defineProperties(options) {
73
+ let opt = options;
74
+
75
+ if (typeof options === 'string') {
76
+ opt = { url: options };
77
+ }
78
+
79
+ const { apiKey } = opt;
80
+ let { url, projection, bbox } = opt;
81
+ const conn = new WebSocketConnector();
88
82
 
89
- if (options.projection) {
90
- this.setProjection(options.projection);
83
+ if (apiKey) {
84
+ url = `${url || 'wss://tralis-tracker-api.geops.io/ws'}?key=${apiKey}`;
91
85
  }
86
+
87
+ Object.defineProperties(this, {
88
+ url: {
89
+ get: () => {
90
+ return url;
91
+ },
92
+ set: (newUrl) => {
93
+ url = newUrl;
94
+ this.open();
95
+ },
96
+ },
97
+ projection: {
98
+ get: () => {
99
+ return projection;
100
+ },
101
+ set: (newProjection) => {
102
+ if (newProjection !== projection) {
103
+ projection = newProjection;
104
+ if (this.conn) {
105
+ this.conn.send(`PROJECTION ${projection}`);
106
+ }
107
+ }
108
+ },
109
+ },
110
+ bbox: {
111
+ get: () => {
112
+ return bbox;
113
+ },
114
+ set: (newBbox) => {
115
+ if (JSON.stringify(newBbox) !== JSON.stringify(bbox)) {
116
+ bbox = newBbox;
117
+ if (this.conn) {
118
+ this.conn.send(`BBOX ${bbox.join(' ')}`);
119
+ }
120
+ }
121
+ },
122
+ },
123
+ /**
124
+ * The websocket helper class to connect the websocket.
125
+ *
126
+ * @private
127
+ */
128
+ conn: {
129
+ value: conn,
130
+ writable: true,
131
+ },
132
+ /**
133
+ * Interval between PING request in ms.
134
+ * If equal to 0, no PING request are sent.
135
+ * @type {number}
136
+ * @private
137
+ */
138
+ pingIntervalMs: {
139
+ value: options.pingIntervalMs || 10000,
140
+ writable: true,
141
+ },
142
+ /**
143
+ * Timeout in ms after an automatic reconnection when the websoscket has been closed by the server.
144
+ * @type {number}
145
+ */
146
+ reconnectTimeoutMs: {
147
+ value: options.pingIntervalMs || 100,
148
+ writable: true,
149
+ },
150
+ });
92
151
  }
93
152
 
94
- /**
95
- * Send the projection to use. Default to EPSG:3857.
96
- *
97
- * @param {string} epsgCode The EPSG code of the projection.
98
- */
99
- setProjection(epsgCode) {
100
- this.conn.send(`PROJECTION ${epsgCode}`);
153
+ open() {
154
+ this.close();
155
+ // Register BBOX and PROJECTION messages must be send before previous subscriptions.
156
+ this.conn.connect(this.url, this.onOpen);
157
+
158
+ // Register reconnection on close.
159
+ this.conn.websocket.onclose = () => {
160
+ this.onClose();
161
+ };
101
162
  }
102
163
 
103
164
  /**
104
- * Send the bbox to the service, if the first time it will also subscribe to trajectory and deleted_vehicles channels.
105
- *
106
- * @param {number[5]} bbox The bounding box and the zoom level to receive data from.
165
+ * Close the websocket connection without reconnection.
107
166
  */
108
- setBbox(bbox) {
109
- /**
110
- * The BBOX for websocket responses
111
- * @type {Array<number>}
112
- */
113
- this.bbox = bbox;
114
- this.conn.send(`BBOX ${bbox.join(' ')}`);
167
+ close() {
168
+ this.conn.close();
115
169
  }
116
170
 
117
171
  /**
@@ -122,6 +176,47 @@ class TralisAPI {
122
176
  this.conn.send('RESET');
123
177
  }
124
178
 
179
+ /**
180
+ * Callback when the websocket is opened and ready.
181
+ * It applies the bbox and the projection.
182
+ */
183
+ onOpen() {
184
+ if (this.projection) {
185
+ this.conn.send(`PROJECTION ${this.projection}`);
186
+ }
187
+ if (this.bbox) {
188
+ this.conn.send(`BBOX ${this.bbox.join(' ')}`);
189
+ }
190
+
191
+ /**
192
+ * Keep websocket alive
193
+ */
194
+ if (this.pingIntervalMs) {
195
+ window.clearInterval(this.pingInterval);
196
+ /** @ignore */
197
+ this.pingInterval = setInterval(() => {
198
+ this.conn.send('PING');
199
+ }, this.pingIntervalMs);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Callback when the websocket is closed by the server.
205
+ * It auto reconnects after a timeout.
206
+ */
207
+ onClose() {
208
+ window.clearTimeout(this.pingInterval);
209
+ window.clearTimeout(this.reconnectTimeout);
210
+
211
+ if (this.reconnectTimeoutMs) {
212
+ /** @ignore */
213
+ this.reconnectTimeout = window.setTimeout(
214
+ () => this.open(),
215
+ this.reconnectTimeoutMs,
216
+ );
217
+ }
218
+ }
219
+
125
220
  /**
126
221
  * Subscribe to a channel.
127
222
  *
@@ -162,7 +257,7 @@ class TralisAPI {
162
257
  *
163
258
  * @param {Object} depObject The object containing departures by id.
164
259
  * @param {boolean} [sortByMinArrivalTime=false] If true sort departures by arrival time.
165
- * @returns {Array<departure>} Return departures array.
260
+ * @return {Array<departure>} Return departures array.
166
261
  * @private
167
262
  */
168
263
  filterDepartures(depObject, sortByMinArrivalTime = false) {
@@ -294,7 +389,7 @@ class TralisAPI {
294
389
  *
295
390
  * @param {number} uic UIC of the station.
296
391
  * @param {TralisMode} mode Tralis mode.
297
- * @returns {Promise<Station>} A station.
392
+ * @return {Promise<Station>} A station.
298
393
  */
299
394
  getStation(uic, mode) {
300
395
  const params = {
@@ -317,14 +412,10 @@ class TralisAPI {
317
412
  * Update the model's station list for a given mode and a bbox.
318
413
  *
319
414
  * @param {TralisMode} mode Tralis mode.
320
- * @param {number[4]} bbox The extent where to request.
321
- * @returns {Promise<Array<Station>>} An array of stations.
415
+ * @return {Promise<Array<Station>>} An array of stations.
322
416
  */
323
- getStations(mode, bbox) {
417
+ getStations(mode) {
324
418
  const stations = [];
325
- if (bbox) {
326
- this.conn.setBbox(bbox);
327
- }
328
419
  const params = {
329
420
  channel: `station${getModeSuffix(mode, TralisModes)}`,
330
421
  };
@@ -350,14 +441,10 @@ class TralisAPI {
350
441
  * One message pro station.
351
442
  *
352
443
  * @param {TralisMode} mode Tralis mode.
353
- * @param {number[4]} bbox The extent where to request.
354
444
  * @param {function(station: Station)} onMessage Function called on each message of the channel.
355
445
  */
356
- subscribeStations(mode, bbox, onMessage) {
446
+ subscribeStations(mode, onMessage) {
357
447
  this.unsubscribeStations();
358
- if (bbox) {
359
- this.conn.setBbox(bbox);
360
- }
361
448
  this.subscribe(`station${getModeSuffix(mode, TralisModes)}`, (data) => {
362
449
  if (data.content) {
363
450
  onMessage(data.content);
@@ -412,14 +499,15 @@ class TralisAPI {
412
499
  *
413
500
  * @param {TralisMode} mode Tralis mode.
414
501
  * @param {function(trajectory: TralisTrajectory)} onMessage Function called on each message of the channel.
502
+ * @param {boolean} quiet If true, the subscription will not send GET and SUB requests to the websocket.
415
503
  */
416
- subscribeTrajectory(mode, onMessage) {
504
+ subscribeTrajectory(mode, onMessage, quiet = false) {
417
505
  this.unsubscribeTrajectory(onMessage);
418
506
  this.subscribe(
419
507
  `trajectory${getModeSuffix(mode, TralisModes)}`,
420
508
  onMessage,
421
509
  null,
422
- this.isUpdateBboxOnMoveEnd,
510
+ quiet,
423
511
  );
424
512
  }
425
513
 
@@ -436,14 +524,15 @@ class TralisAPI {
436
524
  *
437
525
  * @param {TralisMode} mode Tralis mode.
438
526
  * @param {function(response: { content: Vehicle })} onMessage Function called on each message of the channel.
527
+ * @param {boolean} quiet If true, the subscription will not send GET and SUB requests to the websocket.
439
528
  */
440
- subscribeDeletedVehicles(mode, onMessage) {
529
+ subscribeDeletedVehicles(mode, onMessage, quiet = false) {
441
530
  this.unsubscribeDeletedVehicles(onMessage);
442
531
  this.subscribe(
443
532
  `deleted_vehicles${getModeSuffix(mode, TralisModes)}`,
444
533
  onMessage,
445
534
  null,
446
- this.isUpdateBboxOnMoveEnd,
535
+ quiet,
447
536
  );
448
537
  }
449
538
 
@@ -460,11 +549,21 @@ class TralisAPI {
460
549
  *
461
550
  * @param {string} id A vehicle id.
462
551
  * @param {TralisMode} mode Tralis mode.
463
- * @returns {Promise<FullTrajectory>} Return a full trajectory.
552
+ * @param {string} generalizationLevel The generalization level to request. Can be one of 5 (more generalized), 10, 30, 100, undefined (less generalized).
553
+ * @return {Promise<FullTrajectory>} Return a full trajectory.
464
554
  */
465
- getFullTrajectory(id, mode) {
555
+ getFullTrajectory(id, mode, generalizationLevel) {
556
+ const channel = [`full_trajectory${getModeSuffix(mode, TralisModes)}`];
557
+ if (id) {
558
+ channel.push(id);
559
+ }
560
+
561
+ if ((!mode || mode === TralisModes.TOPOGRAPHIC) && generalizationLevel) {
562
+ channel.push(`gen${generalizationLevel}`);
563
+ }
564
+
466
565
  const params = {
467
- channel: `full_trajectory${getModeSuffix(mode, TralisModes)}_${id}`,
566
+ channel: channel.join('_'),
468
567
  };
469
568
 
470
569
  return new Promise((resolve) => {
@@ -481,11 +580,12 @@ class TralisAPI {
481
580
  *
482
581
  * @param {string[]} ids List of vehicles ids.
483
582
  * @param {TralisMode} mode Tralis mode.
484
- * @returns {Promise<Array<FullTrajectory>>} Return an array of full trajectories.
583
+ * @param {string} generalizationLevel The generalization level to request. Can be one of '', 'gen5', 'gen10', 'gen30', 'gen100'.
584
+ * @return {Promise<Array<FullTrajectory>>} Return an array of full trajectories.
485
585
  */
486
- getFullTrajectories(ids, mode) {
586
+ getFullTrajectories(ids, mode, generalizationLevel) {
487
587
  const promises = ids.map((id) => {
488
- return this.getFullTrajectory(id, mode);
588
+ return this.getFullTrajectory(id, mode, generalizationLevel);
489
589
  });
490
590
  return Promise.all(promises);
491
591
  }
@@ -526,7 +626,7 @@ class TralisAPI {
526
626
  * Get the list of stops for this vehicle.
527
627
  *
528
628
  * @param {string} id A vehicle id.
529
- * @returns {Promise<StopSequence>} Returns a stop sequence object.
629
+ * @return {Promise<StopSequence>} Returns a stop sequence object.
530
630
  */
531
631
  getStopSequence(id) {
532
632
  const params = {
@@ -557,7 +657,7 @@ class TralisAPI {
557
657
  * Get a list of stops for a list of vehicles.
558
658
  *
559
659
  * @param {string[]} ids List of vehicles ids.
560
- * @returns {Promise<Array<StopSequence>>} Return an array of stop sequences.
660
+ * @return {Promise<Array<StopSequence>>} Return an array of stop sequences.
561
661
  */
562
662
  getStopSequences(ids) {
563
663
  const promises = ids.map((id) => {
@@ -0,0 +1,75 @@
1
+ import { TralisAPI, TralisModes } from '..';
2
+
3
+ describe('TralisAPI', () => {
4
+ let tralisAPI;
5
+ let get;
6
+
7
+ beforeEach(() => {
8
+ get = jest.fn((params, cb) => {
9
+ cb({ content: 'content' });
10
+ });
11
+ tralisAPI = new TralisAPI();
12
+ tralisAPI.conn = {
13
+ get,
14
+ };
15
+ });
16
+
17
+ describe('#getFullTrajectory() calls fullTrajectory channel', () => {
18
+ test('without parameters', (done) => {
19
+ tralisAPI.getFullTrajectory().then(() => {
20
+ expect(get.mock.calls.length).toBe(1);
21
+ expect(get.mock.calls[0][0]).toEqual({
22
+ channel: 'full_trajectory',
23
+ });
24
+ done();
25
+ });
26
+ });
27
+
28
+ [null, TralisModes.TOPOGRAPHIC].forEach((mode) => {
29
+ describe(`using mode ${mode}`, () => {
30
+ test('using id', (done) => {
31
+ tralisAPI.getFullTrajectory('foo', mode).then(() => {
32
+ expect(get.mock.calls.length).toBe(1);
33
+ expect(get.mock.calls[0][0]).toEqual({
34
+ channel: 'full_trajectory_foo',
35
+ });
36
+ done();
37
+ });
38
+ });
39
+
40
+ test('using id and generalizationLevel param', (done) => {
41
+ tralisAPI.getFullTrajectory('foo', mode, 5).then(() => {
42
+ expect(get.mock.calls.length).toBe(1);
43
+ expect(get.mock.calls[0][0]).toEqual({
44
+ channel: 'full_trajectory_foo_gen5',
45
+ });
46
+ done();
47
+ });
48
+ });
49
+ });
50
+ });
51
+
52
+ describe('using schematic mode ', () => {
53
+ test('using id', (done) => {
54
+ tralisAPI.getFullTrajectory('foo', TralisModes.SCHEMATIC).then(() => {
55
+ expect(get.mock.calls.length).toBe(1);
56
+ expect(get.mock.calls[0][0]).toEqual({
57
+ channel: 'full_trajectory_schematic_foo',
58
+ });
59
+ done();
60
+ });
61
+ });
62
+ test("doesn't use generalizationLevel param", (done) => {
63
+ tralisAPI
64
+ .getFullTrajectory('foo', TralisModes.SCHEMATIC, 10)
65
+ .then(() => {
66
+ expect(get.mock.calls.length).toBe(1);
67
+ expect(get.mock.calls[0][0]).toEqual({
68
+ channel: 'full_trajectory_schematic_foo',
69
+ });
70
+ done();
71
+ });
72
+ });
73
+ });
74
+ });
75
+ });