@golemio/pid 2.1.13-dev.510658546 → 2.1.13

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 (75) hide show
  1. package/db/example/{00_truncate_tables.sql → __truncate_tables.sql} +0 -0
  2. package/db/example/{01_departure_directions.sql → departure_directions.sql} +0 -0
  3. package/db/example/{02_pid_line_example_115.sql → pid_line_example_115.sql} +0 -0
  4. package/db/example/{03_ropidgtfs_dump.sql → ropid_gtfs_dump.sql} +27 -27
  5. package/db/example/{04_ropidvymi_example.sql → ropidvymi_example.sql} +0 -0
  6. package/db/example/{07_tmp_example.sql → tmp_example.sql} +0 -0
  7. package/db/example/{pb/trip_updates.pb → trip_updates.pb} +0 -0
  8. package/db/example/{pb/vehicle_positions.pb → vehicle_positions.pb} +0 -0
  9. package/db/example/{05_vehicle_positions_dump.sql → vehicle_positions_dump.sql} +0 -0
  10. package/db/example/{99_precomputed_tables.sql → zzz_precomputed_tables.sql} +0 -0
  11. package/dist/const.d.ts +0 -4
  12. package/dist/const.js +1 -6
  13. package/dist/const.js.map +1 -1
  14. package/dist/integration-engine/ropid-gtfs/RopidGTFSScheduledTripsModel.d.ts +1 -1
  15. package/dist/integration-engine/ropid-gtfs/RopidGTFSStopTimesModel.d.ts +0 -11
  16. package/dist/integration-engine/ropid-gtfs/RopidGTFSStopTimesModel.js +0 -34
  17. package/dist/integration-engine/ropid-gtfs/RopidGTFSStopTimesModel.js.map +1 -1
  18. package/dist/integration-engine/ropid-gtfs/RopidGTFSTripsModel.js +1 -2
  19. package/dist/integration-engine/ropid-gtfs/RopidGTFSTripsModel.js.map +1 -1
  20. package/dist/integration-engine/ropid-gtfs/RopidGTFSWorker.js +2 -2
  21. package/dist/integration-engine/ropid-gtfs/RopidGTFSWorker.js.map +1 -1
  22. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsPositionsModel.d.ts → VehiclePositionsPositionsModel.d.ts} +3 -3
  23. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsPositionsModel.js → VehiclePositionsPositionsModel.js} +3 -3
  24. package/dist/integration-engine/vehicle-positions/VehiclePositionsPositionsModel.js.map +1 -0
  25. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsRunsMessagesModel.d.ts → VehiclePositionsRunsMessagesModel.d.ts} +0 -0
  26. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsRunsMessagesModel.js → VehiclePositionsRunsMessagesModel.js} +5 -5
  27. package/dist/integration-engine/vehicle-positions/VehiclePositionsRunsMessagesModel.js.map +1 -0
  28. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsRunsModel.d.ts → VehiclePositionsRunsModel.d.ts} +2 -2
  29. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsRunsModel.js → VehiclePositionsRunsModel.js} +2 -2
  30. package/dist/integration-engine/vehicle-positions/VehiclePositionsRunsModel.js.map +1 -0
  31. package/dist/integration-engine/vehicle-positions/{transformations/VehiclePositionsRunsTransformation.d.ts → VehiclePositionsRunsTransformation.d.ts} +1 -1
  32. package/dist/integration-engine/vehicle-positions/{transformations/VehiclePositionsRunsTransformation.js → VehiclePositionsRunsTransformation.js} +1 -1
  33. package/dist/integration-engine/vehicle-positions/VehiclePositionsRunsTransformation.js.map +1 -0
  34. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsStopsModel.d.ts → VehiclePositionsStopsModel.d.ts} +0 -0
  35. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsStopsModel.js → VehiclePositionsStopsModel.js} +1 -1
  36. package/dist/integration-engine/vehicle-positions/VehiclePositionsStopsModel.js.map +1 -0
  37. package/dist/integration-engine/vehicle-positions/VehiclePositionsTransformation.d.ts +49 -0
  38. package/dist/integration-engine/vehicle-positions/{transformations/VehiclePositionsTransformation.js → VehiclePositionsTransformation.js} +45 -42
  39. package/dist/integration-engine/vehicle-positions/VehiclePositionsTransformation.js.map +1 -0
  40. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsTripsModel.d.ts → VehiclePositionsTripsModel.d.ts} +7 -5
  41. package/dist/integration-engine/vehicle-positions/{models/VehiclePositionsTripsModel.js → VehiclePositionsTripsModel.js} +31 -54
  42. package/dist/integration-engine/vehicle-positions/VehiclePositionsTripsModel.js.map +1 -0
  43. package/dist/integration-engine/vehicle-positions/VehiclePositionsWorker.d.ts +90 -43
  44. package/dist/integration-engine/vehicle-positions/VehiclePositionsWorker.js +231 -366
  45. package/dist/integration-engine/vehicle-positions/VehiclePositionsWorker.js.map +1 -1
  46. package/dist/integration-engine/vehicle-positions/index.d.ts +5 -2
  47. package/dist/integration-engine/vehicle-positions/index.js +5 -2
  48. package/dist/integration-engine/vehicle-positions/index.js.map +1 -1
  49. package/dist/output-gateway/vehicle-positions/models/VehiclePositionsTripsModel.js +1 -1
  50. package/dist/output-gateway/vehicle-positions/models/VehiclePositionsTripsModel.js.map +1 -1
  51. package/dist/schema-definitions/vehicle-positions/index.d.ts +2 -9
  52. package/dist/schema-definitions/vehicle-positions/index.js +2 -18
  53. package/dist/schema-definitions/vehicle-positions/index.js.map +1 -1
  54. package/package.json +82 -83
  55. package/db/example/06_ropidgtfs_train_trips_stop_times.sql +0 -83
  56. package/dist/integration-engine/vehicle-positions/VehiclePositionsInterfaces.d.ts +0 -152
  57. package/dist/integration-engine/vehicle-positions/VehiclePositionsInterfaces.js +0 -3
  58. package/dist/integration-engine/vehicle-positions/VehiclePositionsInterfaces.js.map +0 -1
  59. package/dist/integration-engine/vehicle-positions/VehiclePositionsUtils.d.ts +0 -30
  60. package/dist/integration-engine/vehicle-positions/VehiclePositionsUtils.js +0 -58
  61. package/dist/integration-engine/vehicle-positions/VehiclePositionsUtils.js.map +0 -1
  62. package/dist/integration-engine/vehicle-positions/models/VehiclePositionsPositionsModel.js.map +0 -1
  63. package/dist/integration-engine/vehicle-positions/models/VehiclePositionsRunsMessagesModel.js.map +0 -1
  64. package/dist/integration-engine/vehicle-positions/models/VehiclePositionsRunsModel.js.map +0 -1
  65. package/dist/integration-engine/vehicle-positions/models/VehiclePositionsStopsModel.js.map +0 -1
  66. package/dist/integration-engine/vehicle-positions/models/VehiclePositionsTripsModel.js.map +0 -1
  67. package/dist/integration-engine/vehicle-positions/models/index.d.ts +0 -5
  68. package/dist/integration-engine/vehicle-positions/models/index.js +0 -18
  69. package/dist/integration-engine/vehicle-positions/models/index.js.map +0 -1
  70. package/dist/integration-engine/vehicle-positions/transformations/VehiclePositionsRunsTransformation.js.map +0 -1
  71. package/dist/integration-engine/vehicle-positions/transformations/VehiclePositionsTransformation.d.ts +0 -108
  72. package/dist/integration-engine/vehicle-positions/transformations/VehiclePositionsTransformation.js.map +0 -1
  73. package/dist/integration-engine/vehicle-positions/transformations/index.d.ts +0 -2
  74. package/dist/integration-engine/vehicle-positions/transformations/index.js +0 -15
  75. package/dist/integration-engine/vehicle-positions/transformations/index.js.map +0 -1
@@ -27,6 +27,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
27
27
  step((generator = generator.apply(thisArg, _arguments || [])).next());
28
28
  });
29
29
  };
30
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
31
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
32
+ var m = o[Symbol.asyncIterator], i;
33
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
34
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
35
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
36
+ };
30
37
  var __importDefault = (this && this.__importDefault) || function (mod) {
31
38
  return (mod && mod.__esModule) ? mod : { "default": mod };
32
39
  };
@@ -45,13 +52,12 @@ const helpers_1 = require("@golemio/core/dist/integration-engine/helpers");
45
52
  const models_1 = require("@golemio/core/dist/integration-engine/models");
46
53
  const workers_1 = require("@golemio/core/dist/integration-engine/workers");
47
54
  const ropid_gtfs_1 = require("../../schema-definitions/ropid-gtfs");
55
+ const RopidGTFSTripsModel_1 = require("../ropid-gtfs/RopidGTFSTripsModel");
48
56
  const vehicle_positions_1 = require("../../schema-definitions/vehicle-positions");
57
+ const _1 = require("./");
49
58
  const const_1 = require("../../const");
50
- const RopidGTFSTripsModel_1 = require("../ropid-gtfs/RopidGTFSTripsModel");
59
+ const VehiclePositionsRunsTransformation_1 = require("./VehiclePositionsRunsTransformation");
51
60
  const RopidGTFSStopTimesModel_1 = require("../ropid-gtfs/RopidGTFSStopTimesModel");
52
- const models_2 = require("./models");
53
- const transformations_1 = require("./transformations");
54
- const VehiclePositionsUtils_1 = require("./VehiclePositionsUtils");
55
61
  var PositionHandlerEnum;
56
62
  (function (PositionHandlerEnum) {
57
63
  PositionHandlerEnum["TRACKING"] = "TRACKING";
@@ -103,11 +109,10 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
103
109
  }
104
110
  }
105
111
  for (const key in chunks) {
106
- const positions = transformedData.positions.filter((position) => chunks[key].includes(position.trips_id));
107
- const updatedTrips = yield this.modelTrips.findAllAssocTripIds(chunks[key]);
112
+ const allIds = yield this.modelTrips.findAllAssocTripIds(chunks[key]);
108
113
  yield this.sendMessageToExchange("workers." + this.queuePrefix + ".updateDelay", JSON.stringify({
109
- positions,
110
- updatedTrips,
114
+ positions: transformedData.positions.filter((position) => chunks[key].includes(position.trips_id)),
115
+ updatedTrips: allIds,
111
116
  }));
112
117
  }
113
118
  });
@@ -126,7 +131,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
126
131
  this.updateGTFSTripId = (msg) => __awaiter(this, void 0, void 0, function* () {
127
132
  const inputData = JSON.parse(msg.content.toString());
128
133
  // unique ids in input data in key-value (id-positions) structure
129
- let positionsByIds = {};
134
+ const positionsByIds = {};
130
135
  for (const position of inputData.positions) {
131
136
  positionsByIds[position.trips_id] = position;
132
137
  }
@@ -135,13 +140,13 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
135
140
  if (!trip.origin_route_name || !trip.sequence_id || !positionsByIds[trip.id].origin_timestamp)
136
141
  return;
137
142
  const timestampLast = (0, moment_timezone_1.default)(positionsByIds[trip.id].origin_timestamp).tz("Europe/Prague").format();
138
- return this.setAndReturnScheduledTrips({
143
+ return this.getScheduledTrips({
139
144
  route_id: trip.origin_route_name,
140
145
  run_number: trip.sequence_id,
141
146
  msg_last_timestamp: timestampLast,
142
147
  });
143
148
  }));
144
- // find gtfs data for each trip
149
+ // find for each trip gtfs data
145
150
  const promiseValues = yield Promise.all(inputData.trips.map((trip) => __awaiter(this, void 0, void 0, function* () {
146
151
  try {
147
152
  return yield this.modelTrips.findGTFSTripId(trip);
@@ -151,76 +156,35 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
151
156
  return err;
152
157
  }
153
158
  })));
154
- let existingTripsPromiseValues = [], existingTripsPromiseErrors = [];
155
159
  // filter only trips with found gtfs data
156
- for (const trip of promiseValues) {
157
- if (trip instanceof golemio_errors_1.CustomError) {
158
- existingTripsPromiseErrors.push(trip);
159
- }
160
- else if (trip instanceof Array) {
161
- existingTripsPromiseValues.push(...trip);
162
- }
163
- else if ((trip === null || trip === void 0 ? void 0 : trip.constructor) === Object) {
164
- existingTripsPromiseValues.push(trip);
165
- }
166
- }
167
- let tripsByBlockId = {};
168
- for (const trip of existingTripsPromiseValues) {
169
- if (!trip.gtfs_block_id || !trip.gtfs_trip_id)
170
- continue;
171
- if (!tripsByBlockId[trip.gtfs_block_id]) {
172
- tripsByBlockId[trip.gtfs_block_id] = new Set();
173
- }
174
- tripsByBlockId[trip.gtfs_block_id].add(trip.gtfs_trip_id);
175
- }
176
- // create cache for trip stops (grouped by block id)
177
- const tripStopsSchedulesByBlockIds = yield Object.entries(tripsByBlockId).reduce((acc, [blockId, gtfsTripIds]) => __awaiter(this, void 0, void 0, function* () {
178
- const tripStops = yield acc;
179
- try {
180
- tripStops[blockId] = yield this.setAndReturnTripStopsSchedule(blockId, [...gtfsTripIds]);
181
- }
182
- catch (err) {
183
- helpers_1.IntegrationErrorHandler.handle(err);
184
- }
185
- return acc;
186
- }), Promise.resolve({}));
160
+ const foundedTripsPromiseValues = [].concat(...promiseValues.filter((result) => !(result instanceof golemio_errors_1.CustomError)));
161
+ const foundedTripsPromiseErrors = promiseValues.filter((result) => result instanceof golemio_errors_1.CustomError);
187
162
  let currentPosition;
188
- for (const trip of existingTripsPromiseValues) {
163
+ for (const trip of foundedTripsPromiseValues) {
189
164
  if (positionsByIds[trip.id]) {
190
165
  currentPosition = positionsByIds[trip.id];
191
- if (trip.gtfs_block_id) {
192
- // Determine current position tracking status
193
- currentPosition.tracking = VehiclePositionsUtils_1.VehiclePositionsUtils.determineTrackingStatus(trip.gtfs_trip_id, tripStopsSchedulesByBlockIds[trip.gtfs_block_id], currentPosition);
194
- }
195
- continue;
196
- }
197
- if (!currentPosition) {
198
- continue;
199
166
  }
200
- // Determine position duplication and new position tracking status
201
- const { shouldCreateNewPosition, trackingStatus: newPositionTrackingStatus } = VehiclePositionsUtils_1.VehiclePositionsUtils.determineNewPositionTracking(tripStopsSchedulesByBlockIds[trip.gtfs_block_id], trip, currentPosition);
202
- if (shouldCreateNewPosition) {
203
- // duplicate position with new created trip for second trip
167
+ else {
168
+ // duplicate position with new created trip for second train trip
204
169
  const newPosition = Object.assign({}, currentPosition);
205
170
  newPosition.trips_id = trip.id;
206
- newPosition.tracking = newPositionTrackingStatus;
207
171
  inputData.positions.push(newPosition);
208
172
  }
209
173
  }
210
174
  yield this.modelPositions.save(inputData.positions);
211
175
  // successfully updated gtfs ids
212
- for (let i = 0, chunkSize = 100, imax = existingTripsPromiseValues.length; i < imax; i += chunkSize) {
176
+ for (let i = 0, chunkSize = 100, imax = foundedTripsPromiseValues.length; i < imax; i += chunkSize) {
213
177
  yield this.sendMessageToExchange("workers." + this.queuePrefix + ".updateDelay", JSON.stringify({
214
178
  positions: [],
215
- updatedTrips: existingTripsPromiseValues.slice(i, i + chunkSize),
179
+ updatedTrips: foundedTripsPromiseValues.slice(i, i + chunkSize),
216
180
  }));
217
181
  }
218
182
  // gtfsId updating errors
219
- for (let i = 0, imax = existingTripsPromiseErrors.length; i < imax; i++) {
220
- helpers_1.IntegrationErrorHandler.handle(existingTripsPromiseErrors[i]);
183
+ for (let i = 0, imax = foundedTripsPromiseErrors.length; i < imax; i++) {
184
+ helpers_1.IntegrationErrorHandler.handle(foundedTripsPromiseErrors[i]);
221
185
  }
222
186
  });
223
- this.generateGtfsRt = () => __awaiter(this, void 0, void 0, function* () {
187
+ this.generateGtfsRt = (msg) => __awaiter(this, void 0, void 0, function* () {
224
188
  const results = yield this.modelTrips.findAllForGTFSRt();
225
189
  const updatesMessage = gtfsRealtime.FeedMessage.create();
226
190
  const positionsMessage = gtfsRealtime.FeedMessage.create();
@@ -241,7 +205,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
241
205
  tripId: r.gtfs_trip_id,
242
206
  routeId: r.gtfs_route_id,
243
207
  };
244
- const vehicleDescriptor = Object.assign({ id: r.gtfs_route_type === models_2.GTFSRouteTypeEnum.TRAIN
208
+ const vehicleDescriptor = Object.assign({ id: r.gtfs_route_type === _1.GTFSRouteTypeEnum.TRAIN
245
209
  ? "train-" + r.cis_trip_number
246
210
  : "service-" + r.gtfs_route_type + "-" + r.vehicle_registration_number }, (r.vehicle_registration_number && {
247
211
  label: r.vehicle_registration_number,
@@ -370,67 +334,32 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
370
334
  const tripIds = inputData.updatedTrips.map((trip) => trip.id);
371
335
  if (((_b = inputData.positions) === null || _b === void 0 ? void 0 : _b.length) > 0) {
372
336
  // unique ids in input data in key-value (id-positions) structure
373
- let positionsByIds = {};
374
- for (const position of inputData.positions) {
375
- positionsByIds[position.trips_id] = position;
376
- }
377
- // unique block_ids and its parent input trips_id in key-value structure
378
- let tripsIdsByBlockIds = {};
379
- // unique block_ids and its parent gtfs_trip_id in key-value structure
380
- let gtfsTripIdsByBlockIds = {};
381
- for (const trip of inputData.updatedTrips) {
382
- if (!trip.gtfs_block_id) {
383
- continue;
384
- }
385
- if (!tripsIdsByBlockIds[trip.gtfs_block_id]) {
386
- tripsIdsByBlockIds[trip.gtfs_block_id] = trip.id;
337
+ const positionsByIds = inputData.positions.reduce((acc, position) => {
338
+ acc[position.trips_id] = position;
339
+ return acc;
340
+ }, {});
341
+ // unique block_id's and its parent input trips_id in key-value (block_id-trips_id) structure
342
+ const blockIdsToParentTripsId = inputData.updatedTrips.reduce((acc, currentTrip) => {
343
+ if (!acc[currentTrip.gtfs_block_id]) {
344
+ // init key value pair if not exists
345
+ acc[currentTrip.gtfs_block_id] = currentTrip.id;
387
346
  }
388
347
  else {
389
- // save only the shorter trip_id (it is the raw input id with no suffixes)
390
- tripsIdsByBlockIds[trip.gtfs_block_id] =
391
- tripsIdsByBlockIds[trip.gtfs_block_id] > trip.id ? trip.id : tripsIdsByBlockIds[trip.gtfs_block_id];
392
- }
393
- if (!gtfsTripIdsByBlockIds[trip.gtfs_block_id]) {
394
- gtfsTripIdsByBlockIds[trip.gtfs_block_id] = new Set();
395
- }
396
- if (trip.gtfs_trip_id) {
397
- gtfsTripIdsByBlockIds[trip.gtfs_block_id].add(trip.gtfs_trip_id);
398
- }
399
- }
400
- // Get cached schedule for each unique block_id
401
- const tripStopsSchedulesByBlockIds = yield Object.entries(gtfsTripIdsByBlockIds).reduce((acc, [blockId, gtfsTripIds]) => __awaiter(this, void 0, void 0, function* () {
402
- const tripStops = yield acc;
403
- try {
404
- const schedule = yield this.setAndReturnTripStopsSchedule(blockId, [...gtfsTripIds]);
405
- tripStops[blockId] = schedule;
406
- }
407
- catch (err) {
408
- helpers_1.IntegrationErrorHandler.handle(err);
348
+ // otherwise save only the shorter trip_id (it is the raw input id with no suffixes)
349
+ acc[currentTrip.gtfs_block_id] =
350
+ acc[currentTrip.gtfs_block_id] > currentTrip.id
351
+ ? currentTrip.id
352
+ : acc[currentTrip.gtfs_block_id];
409
353
  }
410
354
  return acc;
411
- }), Promise.resolve({}));
355
+ }, {});
412
356
  // duplicate positions for trips with block_ids
413
357
  for (const trip of inputData.updatedTrips) {
414
- if (positionsByIds[trip.id]) {
415
- if (trip.gtfs_block_id) {
416
- // Determine current position tracking status
417
- positionsByIds[trip.id].tracking = VehiclePositionsUtils_1.VehiclePositionsUtils.determineTrackingStatus(trip.gtfs_trip_id, tripStopsSchedulesByBlockIds[trip.gtfs_block_id], positionsByIds[trip.id]);
418
- }
419
- continue;
420
- }
421
- const currentPosition = inputData.positions.find((position) => {
422
- return position.trips_id === tripsIdsByBlockIds[trip.gtfs_block_id];
423
- });
424
- if (!currentPosition) {
425
- continue;
426
- }
427
- // Determine position duplication and new position tracking status
428
- const { shouldCreateNewPosition, trackingStatus: newPositionTrackingStatus } = VehiclePositionsUtils_1.VehiclePositionsUtils.determineNewPositionTracking(tripStopsSchedulesByBlockIds[trip.gtfs_block_id], trip, currentPosition);
429
- if (shouldCreateNewPosition) {
430
- // duplicate position with new created trip for second trip
431
- const newPosition = Object.assign({}, currentPosition);
358
+ if (!positionsByIds[trip.id]) {
359
+ const newPosition = Object.assign({}, inputData.positions.find((position) => {
360
+ return position.trips_id === blockIdsToParentTripsId[trip.gtfs_block_id];
361
+ }));
432
362
  newPosition.trips_id = trip.id;
433
- newPosition.tracking = newPositionTrackingStatus;
434
363
  inputData.positions.push(newPosition);
435
364
  }
436
365
  }
@@ -453,7 +382,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
453
382
  helpers_1.log.debug("Delay Computation data (Redis) was not found. (gtfsTripId = " + trip.gtfs_trip_id + ")");
454
383
  try {
455
384
  const gtfs = yield this.getResultObjectForDelayCalculation(trip.gtfs_trip_id);
456
- yield this.delayComputationTripsModel.set("trip_id", gtfs, VehiclePositionsUtils_1.VehiclePositionsUtils.DELAY_COMPUTATION_CACHE_TTL);
385
+ yield this.delayComputationTripsModel.set("trip_id", gtfs, 7200);
457
386
  trip.gtfsData = gtfs;
458
387
  }
459
388
  catch (err) {
@@ -470,7 +399,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
470
399
  }));
471
400
  }
472
401
  catch (err) {
473
- throw new golemio_errors_1.CustomError(`Error while updating delay. For trip ids:${tripIds.slice(0, 10).join(",")}`, true, this.constructor.name, 5001, err);
402
+ throw new golemio_errors_1.CustomError(`Error while updating delay.`, true, this.constructor.name, 5001, err);
474
403
  }
475
404
  }
476
405
  });
@@ -527,8 +456,9 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
527
456
  * @returns {void}
528
457
  */
529
458
  this.updateRunsGTFSTripId = (msg) => __awaiter(this, void 0, void 0, function* () {
459
+ var e_1, _e;
530
460
  const input = JSON.parse(msg.content.toString());
531
- const schedule = yield this.setAndReturnScheduledTrips(input.run);
461
+ const schedule = yield this.getScheduledTrips(input.run);
532
462
  const { actual_stop_timestamp_scheduled: actualStopTimestampScheduled, msg_timestamp: msgTimestamp, events: event, } = input.run_message;
533
463
  const delayMsg = {
534
464
  updatedTrips: [],
@@ -543,51 +473,62 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
543
473
  }
544
474
  return;
545
475
  }
546
- if (!actualStopTimestampScheduled) {
547
- helpers_1.log.warn(`updateRunsGTFSTripId: actualStopTimestampScheduled is not provided for current run: ${JSON.stringify(input.run)}`);
548
- return;
549
- }
550
- const asts = (0, moment_timezone_1.default)(+actualStopTimestampScheduled);
551
- // current gtfs trip for run
552
- const gtfsCurrentTrip = schedule.find((el, i) => {
553
- return asts.isBetween((0, moment_timezone_1.default)(el.start_timestamp), (0, moment_timezone_1.default)(el.end_timestamp), "second", "[]");
554
- });
555
- let isCurrentTripTracking = false;
556
- if (gtfsCurrentTrip &&
557
- // tram is always on track while pushes messages only on stops
558
- (gtfsCurrentTrip.route_type === models_2.GTFSRouteTypeEnum.TRAM ||
559
- // when bus announces DEPARTURE TCP event, it means that trip is on track
560
- (gtfsCurrentTrip.route_type === models_2.GTFSRouteTypeEnum.BUS && event === const_1.TCPEventEnum.DEPARTURED) ||
561
- // when trip has set first stop time, and message timestamp is after scheduled start, set as tracking
562
- (asts.isSame((0, moment_timezone_1.default)(gtfsCurrentTrip.start_timestamp)) &&
563
- (0, moment_timezone_1.default)(msgTimestamp).isSameOrAfter((0, moment_timezone_1.default)(gtfsCurrentTrip.start_timestamp))) ||
564
- // of course when trip announcing some next stop time in schedule, then set as tracking
565
- asts.isAfter((0, moment_timezone_1.default)(gtfsCurrentTrip.start_timestamp)))) {
566
- isCurrentTripTracking = true;
567
- }
568
- const gtfsCurrentTripId = gtfsCurrentTrip && gtfsCurrentTrip.trip_id;
569
- if (!gtfsCurrentTripId) {
570
- helpers_1.log.warn(`updateRunsGTFSTripId: could not find current gtfsTrip for run: ${JSON.stringify(input)}`);
476
+ if (actualStopTimestampScheduled) {
477
+ const asts = (0, moment_timezone_1.default)(+actualStopTimestampScheduled);
478
+ // current gtfs trip for run
479
+ const gtfsCurrentTrip = schedule.find((el, i) => {
480
+ return asts.isBetween((0, moment_timezone_1.default)(el.start_timestamp), (0, moment_timezone_1.default)(el.end_timestamp), "second", "[]");
481
+ });
482
+ let isCurrentTripTracking = false;
483
+ if (gtfsCurrentTrip &&
484
+ // tram is always on track while pushes messages only on stops
485
+ (gtfsCurrentTrip.route_type === _1.GTFSRouteTypeEnum.TRAM ||
486
+ // when bus announces DEPARTURE TCP event, it means that trip is on track
487
+ (gtfsCurrentTrip.route_type === _1.GTFSRouteTypeEnum.BUS && event === const_1.TCPEventEnum.DEPARTURED) ||
488
+ // when trip has set first stop time, and message timestamp is after scheduled start, set as tracking
489
+ (asts.isSame((0, moment_timezone_1.default)(gtfsCurrentTrip.start_timestamp)) &&
490
+ (0, moment_timezone_1.default)(msgTimestamp).isSameOrAfter((0, moment_timezone_1.default)(gtfsCurrentTrip.start_timestamp))) ||
491
+ // of course when trip announcing some next stop time in schedule, then set as tracking
492
+ asts.isAfter((0, moment_timezone_1.default)(gtfsCurrentTrip.start_timestamp)))) {
493
+ isCurrentTripTracking = true;
494
+ }
495
+ const gtfsCurrentTripId = gtfsCurrentTrip && gtfsCurrentTrip.trip_id;
496
+ if (!gtfsCurrentTripId) {
497
+ helpers_1.log.warn(`updateRunsGTFSTripId: could not find current gtfsTrip for run: ${JSON.stringify(input)}`);
498
+ }
499
+ else {
500
+ const currentTrip = yield this.modelTrips.upsertRunTrip(input, gtfsCurrentTrip);
501
+ yield this.modelPositions.upsertRunPosition(input, gtfsCurrentTrip, isCurrentTripTracking);
502
+ delayMsg.updatedTrips.push(currentTrip);
503
+ }
504
+ // last/next gtfs trip for run
505
+ const gtfsLastNextTrips = schedule.filter((el) => {
506
+ return (((asts.clone().subtract(15, "minutes") <= (0, moment_timezone_1.default)(el.end_timestamp) && (0, moment_timezone_1.default)(el.end_timestamp) <= asts) ||
507
+ (asts <= (0, moment_timezone_1.default)(el.start_timestamp) && (0, moment_timezone_1.default)(el.start_timestamp) <= asts.clone().add(60, "minutes"))) &&
508
+ el.trip_id !== (gtfsCurrentTrip === null || gtfsCurrentTrip === void 0 ? void 0 : gtfsCurrentTrip.trip_id));
509
+ });
510
+ try {
511
+ for (var gtfsLastNextTrips_1 = __asyncValues(gtfsLastNextTrips), gtfsLastNextTrips_1_1; gtfsLastNextTrips_1_1 = yield gtfsLastNextTrips_1.next(), !gtfsLastNextTrips_1_1.done;) {
512
+ const gtfsTrip = gtfsLastNextTrips_1_1.value;
513
+ const trip = yield this.modelTrips.upsertRunTrip(input, gtfsTrip);
514
+ yield this.modelPositions.upsertRunPosition(input, gtfsTrip, false);
515
+ delayMsg.updatedTrips.push(trip);
516
+ }
517
+ }
518
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
519
+ finally {
520
+ try {
521
+ if (gtfsLastNextTrips_1_1 && !gtfsLastNextTrips_1_1.done && (_e = gtfsLastNextTrips_1.return)) yield _e.call(gtfsLastNextTrips_1);
522
+ }
523
+ finally { if (e_1) throw e_1.error; }
524
+ }
525
+ // send to updateDelay only if there are some trips updated
526
+ if (delayMsg.updatedTrips.length > 0) {
527
+ yield this.sendMessageToExchange("workers." + this.queuePrefix + ".updateDelay", JSON.stringify(delayMsg));
528
+ }
571
529
  }
572
530
  else {
573
- const currentTrip = yield this.modelTrips.upsertRunTrip(input, gtfsCurrentTrip);
574
- yield this.modelPositions.upsertRunPosition(input, gtfsCurrentTrip, isCurrentTripTracking);
575
- delayMsg.updatedTrips.push(currentTrip);
576
- }
577
- // last/next gtfs trip for run
578
- const gtfsLastNextTrips = schedule.filter((el) => {
579
- return (((asts.clone().subtract(15, "minutes") <= (0, moment_timezone_1.default)(el.end_timestamp) && (0, moment_timezone_1.default)(el.end_timestamp) <= asts) ||
580
- (asts <= (0, moment_timezone_1.default)(el.start_timestamp) && (0, moment_timezone_1.default)(el.start_timestamp) <= asts.clone().add(60, "minutes"))) &&
581
- el.trip_id !== (gtfsCurrentTrip === null || gtfsCurrentTrip === void 0 ? void 0 : gtfsCurrentTrip.trip_id));
582
- });
583
- for (const gtfsTrip of gtfsLastNextTrips) {
584
- const trip = yield this.modelTrips.upsertRunTrip(input, gtfsTrip);
585
- yield this.modelPositions.upsertRunPosition(input, gtfsTrip, false);
586
- delayMsg.updatedTrips.push(trip);
587
- }
588
- // send to updateDelay only if there are some trips updated
589
- if (delayMsg.updatedTrips.length > 0) {
590
- yield this.sendMessageToExchange("workers." + this.queuePrefix + ".updateDelay", JSON.stringify(delayMsg));
531
+ helpers_1.log.warn(`updateRunsGTFSTripId: actualStopTimestampScheduled is not provided for current run: ${JSON.stringify(input.run)}`);
591
532
  }
592
533
  });
593
534
  /**
@@ -617,7 +558,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
617
558
  *
618
559
  * @returns {string[]} array of tripIds
619
560
  */
620
- this.setAndReturnScheduledTrips = (scheduleData) => __awaiter(this, void 0, void 0, function* () {
561
+ this.getScheduledTrips = (scheduleData) => __awaiter(this, void 0, void 0, function* () {
621
562
  const { route_id, run_number, msg_last_timestamp } = scheduleData;
622
563
  const scheduledTripIds = yield this.runTripsModel.get(`${route_id}_${run_number}`);
623
564
  if (!(scheduledTripIds === null || scheduledTripIds === void 0 ? void 0 : scheduledTripIds.schedule)) {
@@ -627,36 +568,11 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
627
568
  el.start_timestamp = (0, moment_timezone_1.default)(el.start_timestamp).tz("Europe/Prague").format();
628
569
  el.end_timestamp = (0, moment_timezone_1.default)(el.end_timestamp).tz("Europe/Prague").format();
629
570
  });
630
- yield this.runTripsModel.set(`${route_id}_${run_number}`, { schedule: result }, VehiclePositionsUtils_1.VehiclePositionsUtils.RUN_TRIPS_CACHE_TTL);
571
+ yield this.runTripsModel.set(`${route_id}_${run_number}`, { schedule: result }, 21600);
631
572
  return result;
632
573
  }
633
574
  return scheduledTripIds.schedule;
634
575
  });
635
- /**
636
- * Get trip stops schedule by block id
637
- *
638
- * @param {string} blockId - Target gtfs block id
639
- * @param {string} tripIds - List of inserted gtfs trip ids
640
- */
641
- this.setAndReturnTripStopsSchedule = (blockId, tripIds) => __awaiter(this, void 0, void 0, function* () {
642
- const schedule = yield this.tripStopsModel.get(blockId);
643
- if (schedule) {
644
- return schedule;
645
- }
646
- try {
647
- const tripStops = yield this.modelGTFSStopTimes.findTripStops(tripIds);
648
- const tripStopsSchedule = tripStops.reduce((acc, curr) => {
649
- acc[curr.trip_id] = { trip_stops: curr.trip_stops };
650
- return acc;
651
- }, {});
652
- yield this.tripStopsModel.set(blockId, tripStopsSchedule, VehiclePositionsUtils_1.VehiclePositionsUtils.TRIP_STOPS_CACHE_TTL);
653
- return tripStopsSchedule;
654
- }
655
- catch (err) {
656
- helpers_1.log.warn("Unable to retrieve trip stops", err);
657
- return {};
658
- }
659
- });
660
576
  /**
661
577
  * Takes all newly computed positions and saves it, then save the last ones to the trips
662
578
  *
@@ -764,9 +680,9 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
764
680
  return PositionHandlerEnum.DO_NOTHING;
765
681
  if (position.is_canceled)
766
682
  return PositionHandlerEnum.CANCELED;
767
- if (position.lat && position.lng && position.tracking === const_1.PositionTrackingEnum.TRACKING)
683
+ if (position.lat && position.lng && position.tracking === 2)
768
684
  return PositionHandlerEnum.TRACKING;
769
- if (position.tracking !== const_1.PositionTrackingEnum.TRACKING)
685
+ if (position.tracking !== 2)
770
686
  return PositionHandlerEnum.NOT_TRACKING;
771
687
  return PositionHandlerEnum.NOT_TRACKING;
772
688
  };
@@ -816,7 +732,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
816
732
  }
817
733
  else {
818
734
  // if there is tracking 2 position with same origin_timestamp then this position is duplicate
819
- const statePosition = tripPositions.positions.find((e) => e.origin_timestamp === position.origin_timestamp && e.tracking === const_1.PositionTrackingEnum.TRACKING)
735
+ const statePosition = tripPositions.positions.find((e) => e.origin_timestamp === position.origin_timestamp && e.tracking === 2)
820
736
  ? const_1.StatePositionEnum.DUPLICATE
821
737
  : const_1.StatePositionEnum.AFTER_TRACK;
822
738
  const lastShapesAnchorPoint = tripPositions.gtfsData.shapes_anchor_points[tripPositions.gtfsData.shapes_anchor_points.length - 1];
@@ -909,6 +825,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
909
825
  .valueOf();
910
826
  };
911
827
  // FIND ALL SHAPE POINTS IN POLYGON CIRCLE, GET SEGMENTS WITH CONSEQUENTING POINTS
828
+ // TODO this should a class method
912
829
  this.getShapePointsAroundPosition = (tripShapePoints, radius) => __awaiter(this, void 0, void 0, function* () {
913
830
  const ptsInRadius = [];
914
831
  let segmentIndex = 0;
@@ -1066,9 +983,9 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
1066
983
  if (Math.abs(timeRealDiff) < Math.abs(minTimeRealDiff)) {
1067
984
  minTimeRealDiff = timeRealDiff;
1068
985
  // push trip into nearest at_stop shape anchor point if trip "P" event (tram) / "V" event (bus)
1069
- if (((gtfsRouteType === models_2.GTFSRouteTypeEnum.TRAM &&
986
+ if (((gtfsRouteType === _1.GTFSRouteTypeEnum.TRAM &&
1070
987
  currentPosition.properties.tcp_event === const_1.TCPEventEnum.ARRIVAL_ANNOUNCED) ||
1071
- (gtfsRouteType === models_2.GTFSRouteTypeEnum.BUS && currentPosition.properties.tcp_event === const_1.TCPEventEnum.V)) &&
988
+ (gtfsRouteType === _1.GTFSRouteTypeEnum.BUS && currentPosition.properties.tcp_event === const_1.TCPEventEnum.V)) &&
1072
989
  thisClosestPoint.this_stop_sequence === null) {
1073
990
  let movingShapePointIndex = thisClosestPoint.index;
1074
991
  while (thisClosestPoint.this_stop_sequence === null && movingShapePointIndex < lastTripShapePoint.index) {
@@ -1083,7 +1000,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
1083
1000
  statePosition = const_1.StatePositionEnum.ON_TRACK;
1084
1001
  }
1085
1002
  // if tram position has "V" avent tram is after track
1086
- if (gtfsRouteType === models_2.GTFSRouteTypeEnum.TRAM && currentPosition.properties.tcp_event === const_1.TCPEventEnum.V) {
1003
+ if (gtfsRouteType === _1.GTFSRouteTypeEnum.TRAM && currentPosition.properties.tcp_event === const_1.TCPEventEnum.V) {
1087
1004
  statePosition = const_1.StatePositionEnum.AFTER_TRACK;
1088
1005
  thisClosestPoint = lastTripShapePoint;
1089
1006
  timeDelay = null;
@@ -1145,17 +1062,17 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
1145
1062
  * @returns {IPositionToUpdate} - Position object to update
1146
1063
  */
1147
1064
  this.getEstimatedPoint = (tripGtfsData, currentPosition, context, startDayTimestamp, gtfsRouteType) => __awaiter(this, void 0, void 0, function* () {
1148
- var _e, _f, _g, _h, _j, _k;
1065
+ var _f, _g, _h, _j, _k, _l;
1149
1066
  // init radius around GPS position ( 200 meters radius, 16 points polygon aka circle)
1150
1067
  const radius = turf.circle(currentPosition, 0.2, { steps: 16 });
1151
1068
  //Initial value
1152
1069
  let estimatedPoint = Object.assign({ id: currentPosition.properties.id, state_position: const_1.StatePositionEnum.OFF_TRACK, state_process: const_1.StateProcessEnum.PROCESSED, tcp_event: currentPosition.properties.tcp_event }, (context &&
1153
- ((_e = context.lastPositionTracking) === null || _e === void 0 ? void 0 : _e.properties.last_stop_sequence) && {
1154
- shape_dist_traveled: (_f = context.lastPositionTracking) === null || _f === void 0 ? void 0 : _f.properties.shape_dist_traveled,
1155
- last_stop_arrival_time: (_g = context.lastPositionTracking) === null || _g === void 0 ? void 0 : _g.properties.last_stop_arrival_time,
1156
- last_stop_departure_time: (_h = context.lastPositionTracking) === null || _h === void 0 ? void 0 : _h.properties.last_stop_departure_time,
1157
- last_stop_sequence: (_j = context.lastPositionTracking) === null || _j === void 0 ? void 0 : _j.properties.last_stop_sequence,
1158
- last_stop_id: (_k = context.lastPositionTracking) === null || _k === void 0 ? void 0 : _k.properties.last_stop_id,
1070
+ ((_f = context.lastPositionTracking) === null || _f === void 0 ? void 0 : _f.properties.last_stop_sequence) && {
1071
+ shape_dist_traveled: (_g = context.lastPositionTracking) === null || _g === void 0 ? void 0 : _g.properties.shape_dist_traveled,
1072
+ last_stop_arrival_time: (_h = context.lastPositionTracking) === null || _h === void 0 ? void 0 : _h.properties.last_stop_arrival_time,
1073
+ last_stop_departure_time: (_j = context.lastPositionTracking) === null || _j === void 0 ? void 0 : _j.properties.last_stop_departure_time,
1074
+ last_stop_sequence: (_k = context.lastPositionTracking) === null || _k === void 0 ? void 0 : _k.properties.last_stop_sequence,
1075
+ last_stop_id: (_l = context.lastPositionTracking) === null || _l === void 0 ? void 0 : _l.properties.last_stop_id,
1159
1076
  }));
1160
1077
  // returns array of segments (row of points) of shape anchor points around gps
1161
1078
  const ptsInRadius = yield this.getShapePointsAroundPosition(tripGtfsData.shapes_anchor_points, radius);
@@ -1186,13 +1103,59 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
1186
1103
  if (!stopTimes || !stopTimes.stop_times || stopTimes.stop_times.length === 0) {
1187
1104
  throw new Error(`"trip.stop_times" was not found for id ${tripId}.`);
1188
1105
  }
1189
- const shapesGeometryAnchorPoints = this.getShapesGeometryAnchorPoints(stopTimes.shape_id, shapes.shapes, stopTimes.stop_times);
1106
+ // { <tripData>, stop_times: [ <stopTimesDataWithStop> ], shapes: [ <shapesData> ] }
1107
+ const shapesGeometryAnchorPoints = yield this.getShapesGeometryAnchorPoints(stopTimes.shape_id, shapes.shapes);
1108
+ // ----------------------------------------------
1109
+ // TEMP constS
1110
+ const stopSequenceMaximum = stopTimes.stop_times.length;
1190
1111
  // MAKING COPY
1191
1112
  const shapePoints = [];
1192
1113
  // const to determine shape points of stops (in meters)
1193
- const distanceBefore = 0.1;
1194
- const distanceAfter = 0.05;
1195
- for (let i = 0; i < shapesGeometryAnchorPoints.length; i++) {
1114
+ const distanceBefore = 100;
1115
+ const distanceAfter = 50;
1116
+ // TODO this should a class method
1117
+ const shapesAnchorPointsIterator = (i, cb) => {
1118
+ // end of iteration
1119
+ if (shapesGeometryAnchorPoints.length === i) {
1120
+ return cb();
1121
+ }
1122
+ // find stop in near distance
1123
+ const stopNearby = stopTimes.stop_times.reduce((r, s, j) => {
1124
+ if (shapesGeometryAnchorPoints[i].shape_dist_traveled >=
1125
+ s.shape_dist_traveled - (distanceBefore * 1.0) / 1000 &&
1126
+ shapesGeometryAnchorPoints[i].shape_dist_traveled <=
1127
+ s.shape_dist_traveled + (distanceAfter * 1.0) / 1000) {
1128
+ const thisDistanceToStop = Math.abs(shapesGeometryAnchorPoints[i].shape_dist_traveled - s.shape_dist_traveled);
1129
+ if (r.distanceToStop > thisDistanceToStop) {
1130
+ r.distanceToStop = thisDistanceToStop;
1131
+ r.this_stop_sequence = s.stop_sequence;
1132
+ r.at_stop = true;
1133
+ }
1134
+ }
1135
+ return r;
1136
+ }, { at_stop: false, stop_sequence: null, distanceToStop: Infinity, this_stop_sequence: null });
1137
+ let lastStopSequence;
1138
+ let nextStopSequence;
1139
+ // SET THIS STOP
1140
+ if (stopNearby.at_stop) {
1141
+ lastStopSequence = Math.min(stopNearby.this_stop_sequence, stopSequenceMaximum);
1142
+ nextStopSequence = Math.min(stopNearby.this_stop_sequence + 1, stopSequenceMaximum);
1143
+ }
1144
+ else {
1145
+ const lastNextSequences = stopTimes.stop_times.reduce((r, s, j) => {
1146
+ if (j < stopTimes.stop_times.length - 1) {
1147
+ if (shapesGeometryAnchorPoints[i].shape_dist_traveled >= s.shape_dist_traveled &&
1148
+ shapesGeometryAnchorPoints[i].shape_dist_traveled <=
1149
+ stopTimes.stop_times[j + 1].shape_dist_traveled) {
1150
+ r.last_stop_sequence = j + 1;
1151
+ r.next_stop_sequence = j + 1 + 1;
1152
+ }
1153
+ }
1154
+ return r;
1155
+ }, { last_stop_sequence: 1, next_stop_sequence: 2 });
1156
+ lastStopSequence = lastNextSequences.last_stop_sequence;
1157
+ nextStopSequence = lastNextSequences.next_stop_sequence;
1158
+ }
1196
1159
  let bearing = 0;
1197
1160
  // add bearing from shape computed for previous shapePoint
1198
1161
  if (i > 0) {
@@ -1210,37 +1173,13 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
1210
1173
  bearing = shapePoints[i - 1].bearing;
1211
1174
  }
1212
1175
  }
1213
- // init values
1214
- let thisStopSequence = null;
1215
- let lastStopSequence = shapesGeometryAnchorPoints[i].last_stop_sequence;
1216
- let nextStopSequence = shapesGeometryAnchorPoints[i].next_stop_sequence;
1217
- // these are origin stop_times shape point fron shapes table, clearly at stops points
1218
- if (shapesGeometryAnchorPoints[i].this_stop_sequence) {
1219
- thisStopSequence = shapesGeometryAnchorPoints[i].this_stop_sequence;
1220
- }
1221
- // if is shape anchor point in close distance AFTER LAST stop, then set it also AT STOP
1222
- else if (i > 0 &&
1223
- shapesGeometryAnchorPoints[i].shape_dist_traveled -
1224
- stopTimes.stop_times[shapesGeometryAnchorPoints[i].last_stop_sequence - 1].shape_dist_traveled <=
1225
- distanceAfter) {
1226
- thisStopSequence = shapesGeometryAnchorPoints[i].last_stop_sequence;
1227
- }
1228
- // if is shape anchor point in close distance BEFORE NEXT stop, then set it also AT STOP
1229
- else if (i < shapesGeometryAnchorPoints.length - 1 &&
1230
- stopTimes.stop_times[shapesGeometryAnchorPoints[i].next_stop_sequence - 1].shape_dist_traveled -
1231
- shapesGeometryAnchorPoints[i].shape_dist_traveled <=
1232
- distanceBefore) {
1233
- thisStopSequence = shapesGeometryAnchorPoints[i].next_stop_sequence;
1234
- lastStopSequence = shapesGeometryAnchorPoints[i].next_stop_sequence;
1235
- nextStopSequence = Math.min(shapesGeometryAnchorPoints[i].next_stop_sequence + 1, stopTimes.stop_times.length);
1236
- }
1237
1176
  const distanceFromLastStop = Math.round((shapesGeometryAnchorPoints[i].shape_dist_traveled -
1238
1177
  stopTimes.stop_times[lastStopSequence - 1].shape_dist_traveled) *
1239
1178
  1000) / 1000;
1240
1179
  // if is trip at stop than set departure by this stop
1241
1180
  // between stops do linear interpolation from departure from last stop and arrival of next stop
1242
- const timeScheduledSeconds = thisStopSequence !== null
1243
- ? stopTimes.stop_times[lastStopSequence - 1].arrival_time_seconds
1181
+ const timeScheduledSeconds = stopNearby.at_stop
1182
+ ? stopTimes.stop_times[lastStopSequence - 1].departure_time_seconds
1244
1183
  : stopTimes.stop_times[lastStopSequence - 1].departure_time_seconds +
1245
1184
  Math.round(((stopTimes.stop_times[nextStopSequence - 1].arrival_time_seconds -
1246
1185
  stopTimes.stop_times[lastStopSequence - 1].departure_time_seconds) *
@@ -1249,22 +1188,29 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
1249
1188
  stopTimes.stop_times[lastStopSequence - 1].shape_dist_traveled));
1250
1189
  shapePoints.push({
1251
1190
  index: i,
1252
- at_stop: thisStopSequence !== null,
1191
+ at_stop: stopNearby.at_stop,
1253
1192
  bearing,
1254
1193
  coordinates: shapesGeometryAnchorPoints[i].coordinates,
1255
1194
  distance_from_last_stop: distanceFromLastStop,
1256
1195
  last_stop_sequence: lastStopSequence,
1257
1196
  next_stop_sequence: nextStopSequence,
1258
- shape_dist_traveled: Math.round(shapesGeometryAnchorPoints[i].shape_dist_traveled * 100000) / 100000,
1259
- this_stop_sequence: thisStopSequence,
1197
+ shape_dist_traveled: shapesGeometryAnchorPoints[i].shape_dist_traveled,
1198
+ this_stop_sequence: stopNearby.at_stop ? stopNearby.this_stop_sequence : null,
1260
1199
  time_scheduled_seconds: timeScheduledSeconds,
1261
1200
  });
1262
- }
1263
- return {
1264
- trip_id: tripId,
1265
- stop_times: stopTimes.stop_times,
1266
- shapes_anchor_points: shapePoints,
1201
+ // next step
1202
+ shapesAnchorPointsIterator(i + 1, cb);
1267
1203
  };
1204
+ return new Promise((resolve, reject) => {
1205
+ shapesAnchorPointsIterator(0, () => {
1206
+ // FINAL OBJECT
1207
+ resolve({
1208
+ trip_id: tripId,
1209
+ stop_times: stopTimes.stop_times,
1210
+ shapes_anchor_points: shapePoints,
1211
+ });
1212
+ });
1213
+ });
1268
1214
  }
1269
1215
  catch (err) {
1270
1216
  helpers_1.log.error(err);
@@ -1276,156 +1222,75 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
1276
1222
  *
1277
1223
  * @param {string} shapeId - GTFS shape id
1278
1224
  * @param {ITransformedTripShape[]} shapes - GTFS shape points
1279
- * @param {IStopTime[]} stops
1280
1225
  * @returns {IShapeGeometryAnchorPoint[]} - Result array of geometry points along trip track shape
1281
1226
  */
1282
- this.getShapesGeometryAnchorPoints = (shapeId, shapes, stops) => {
1227
+ this.getShapesGeometryAnchorPoints = (shapeId, shapes) => __awaiter(this, void 0, void 0, function* () {
1228
+ var _m;
1229
+ const shapesAnchorPoints = [];
1283
1230
  try {
1284
- let segmentShapes = [];
1285
- // Splits shapes array to multiple arrays "delimited" by stops
1286
- for (let st = 0; st < stops.length; st++) {
1287
- let currentSegment = [];
1288
- for (let sh = 0; sh < shapes.length; sh++) {
1289
- let shapePoint = Object.assign(Object.assign({}, shapes[sh]), { shape_at_stop: false });
1290
- if (stops[st].shape_dist_traveled === shapes[sh].shape_dist_traveled) {
1291
- shapePoint.shape_at_stop = true;
1292
- }
1293
- if (st < stops.length - 1 &&
1294
- shapePoint.shape_dist_traveled >= stops[st].shape_dist_traveled &&
1295
- shapePoint.shape_dist_traveled <= stops[st + 1].shape_dist_traveled) {
1296
- currentSegment.push(shapePoint);
1297
- }
1298
- }
1299
- if (currentSegment.length) {
1300
- segmentShapes.push(currentSegment);
1301
- }
1302
- }
1303
- let segmentArr = [];
1304
- // concat arrays of stop divided segments with distributed shape points
1305
- for (const segment of segmentShapes) {
1306
- segmentArr = [...segmentArr, ...this.divideSegmentLine(segment)];
1307
- }
1308
- // Make initial shapesGeometryAnchorPoints
1309
- let stopCounter = 0;
1310
- const resultArr = segmentArr.map((segment, index) => {
1311
- let this_stop_sequence;
1312
- let last_stop_sequence;
1313
- let next_stop_sequence;
1314
- if (segment.shape_at_stop) {
1315
- stopCounter++;
1316
- this_stop_sequence = stopCounter;
1317
- }
1318
- else {
1319
- this_stop_sequence = null;
1231
+ // CREATE turf LineString OBJECT FOR GIVEN COORDINATES
1232
+ const line = turf.lineString(shapes.map((p) => {
1233
+ return [p.shape_pt_lon, p.shape_pt_lat];
1234
+ }));
1235
+ // DEFAULT step BETWEEN TWO POINTS ON PATH [km] - SHORT DISTANCE IMPACTS PROCESS DURATION
1236
+ const step = config_1.config.vehiclePositions.stepBetweenPoints;
1237
+ const distance = ruler.lineDistance((_m = line.geometry) === null || _m === void 0 ? void 0 : _m.coordinates);
1238
+ // TODO this should a class method
1239
+ const lineIterator = (i, cb) => {
1240
+ var _a;
1241
+ // end of iteration
1242
+ if (i >= distance) {
1243
+ return cb();
1320
1244
  }
1321
- last_stop_sequence = stopCounter;
1322
- next_stop_sequence = stopCounter + 1;
1323
- return {
1324
- index,
1325
- coordinates: [
1326
- Math.round(segment.shape_pt_lon * 100000) / 100000,
1327
- Math.round(segment.shape_pt_lat * 100000) / 100000,
1328
- ],
1329
- last_stop_sequence,
1330
- next_stop_sequence,
1331
- shape_dist_traveled: Math.round(segment.shape_dist_traveled * 1000) / 1000,
1332
- this_stop_sequence,
1333
- };
1334
- });
1335
- stopCounter++;
1336
- // and lastly shape point for last stop as there is no segment for last stop
1337
- resultArr.push({
1338
- index: resultArr.length,
1339
- coordinates: [
1340
- Math.round(shapes[shapes.length - 1].shape_pt_lon * 100000) / 100000,
1341
- Math.round(shapes[shapes.length - 1].shape_pt_lat * 100000) / 100000,
1342
- ],
1343
- last_stop_sequence: stopCounter,
1344
- next_stop_sequence: stopCounter,
1345
- shape_dist_traveled: Math.round(shapes[shapes.length - 1].shape_dist_traveled * 1000) / 1000,
1346
- this_stop_sequence: stopCounter,
1245
+ // ADD ALL POINTS TO shapes_anchor_points
1246
+ shapesAnchorPoints.push({
1247
+ // RETURNS coordinates ALONG path WITH GIVER i (DISTANCE) IN 5 DECIMAL PLACES
1248
+ coordinates: ruler.along((_a = line.geometry) === null || _a === void 0 ? void 0 : _a.coordinates, i).map((c) => {
1249
+ return Math.round(c * 100000) / 100000;
1250
+ }),
1251
+ // shape_dist_traveled IS IMPORTANT FOR DECIDING LAST STOP
1252
+ shape_dist_traveled: Math.round(i * 1000) / 1000, // 1 METER PRECISSION
1253
+ });
1254
+ // next step
1255
+ lineIterator(i + step, cb);
1256
+ };
1257
+ return new Promise((resolve, reject) => {
1258
+ lineIterator(0, () => {
1259
+ resolve(shapesAnchorPoints);
1260
+ });
1347
1261
  });
1348
- return resultArr;
1349
1262
  }
1350
1263
  catch (err) {
1351
1264
  helpers_1.log.error(err);
1352
1265
  helpers_1.log.error(shapeId);
1353
- return [];
1266
+ return shapesAnchorPoints;
1354
1267
  }
1355
- };
1356
- /**
1357
- * Generates new shape points from segment of trip shape along original one
1358
- * - preserving start and end shape points belonging to stops
1359
- * - creates new set of shape points between stops to get same point distance along original shape
1360
- *
1361
- * @param {ISegmentShape[]} segmentsArr - Original shape points segment between two stops
1362
- * @param {number} distance - Minimal distance for two consequent shape points
1363
- * @returns {ISegmentShape[]} - Result array of new shape points
1364
- */
1365
- this.divideSegmentLine = (segmentArr, distance = config_1.config.vehiclePositions.stepBetweenPoints) => {
1366
- const shapeId = segmentArr[0].shape_id;
1367
- const shapeCount = segmentArr.length;
1368
- const startShapeDistTraveled = segmentArr[0].shape_dist_traveled;
1369
- const endShapeDistTraveled = segmentArr[shapeCount - 1].shape_dist_traveled;
1370
- const shapeDistLength = endShapeDistTraveled - startShapeDistTraveled;
1371
- const segmentLine = turf.lineString(segmentArr.map((s) => {
1372
- return [s.shape_pt_lon, s.shape_pt_lat];
1373
- }));
1374
- // because we dont believe source shape distances, rather compute length with turf.js
1375
- const segmentLength = turf.length(segmentLine);
1376
- const middlePointsCount = Math.floor(segmentLength / distance);
1377
- const distanceOffset = (segmentLength - distance * middlePointsCount) / 2;
1378
- // put first shape point
1379
- const resultSegmentPoints = [
1380
- Object.assign(Object.assign({}, segmentArr[0]), { shape_pt_sequence: 1 }),
1381
- ];
1382
- // for each middle point create acording shape point with interpolated origin shape dist traveled
1383
- for (let i = 0; i < middlePointsCount; i++) {
1384
- const currentDistance = i * distance + distanceOffset;
1385
- const currentDistDistance = (shapeDistLength / segmentLength) * currentDistance;
1386
- const newPoint = turf.along(segmentLine, i * distance + distanceOffset);
1387
- resultSegmentPoints.push({
1388
- shape_id: shapeId,
1389
- shape_at_stop: false,
1390
- shape_pt_sequence: resultSegmentPoints.length + 1,
1391
- shape_pt_lat: newPoint.geometry.coordinates[1],
1392
- shape_pt_lon: newPoint.geometry.coordinates[0],
1393
- shape_dist_traveled: startShapeDistTraveled + currentDistDistance,
1394
- });
1395
- }
1396
- return resultSegmentPoints;
1397
- };
1398
- this.modelPositions = new models_2.VehiclePositionsPositionsModel();
1399
- this.modelStops = new models_2.VehiclePositionsStopsModel();
1400
- this.modelRuns = new models_2.VehiclePositionsRunsModel();
1401
- this.transformationRuns = new transformations_1.VehiclePositionsRunsTransformation();
1402
- this.modelTrips = new models_2.VehiclePositionsTripsModel();
1403
- this.transformation = new transformations_1.VehiclePositionsTransformation();
1268
+ });
1269
+ this.modelPositions = new _1.VehiclePositionsPositionsModel();
1270
+ this.modelStops = new _1.VehiclePositionsStopsModel();
1271
+ this.modelRuns = new _1.VehiclePositionsRunsModel();
1272
+ this.transformationRuns = new VehiclePositionsRunsTransformation_1.VehiclePositionsRunsTransformation();
1273
+ this.modelTrips = new _1.VehiclePositionsTripsModel();
1274
+ this.transformation = new _1.VehiclePositionsTransformation();
1404
1275
  this.delayComputationTripsModel = new models_1.RedisModel(ropid_gtfs_1.RopidGTFS.delayComputationTrips.name + "Model", {
1405
1276
  decodeDataAfterGet: JSON.parse,
1406
1277
  encodeDataBeforeSave: JSON.stringify,
1407
1278
  isKeyConstructedFromData: true,
1408
1279
  prefix: ropid_gtfs_1.RopidGTFS.delayComputationTrips.mongoCollectionName,
1409
1280
  }, new golemio_validator_1.Validator(ropid_gtfs_1.RopidGTFS.delayComputationTrips.name + "ModelValidator", ropid_gtfs_1.RopidGTFS.delayComputationTrips.outputMongooseSchemaObject));
1410
- this.runTripsModel = new models_1.RedisModel(vehicle_positions_1.VehiclePositions.runsTrips.name + "Model", {
1281
+ this.runTripsModel = new models_1.RedisModel(vehicle_positions_1.VehiclePositions.runs_trips.name + "Model", {
1411
1282
  decodeDataAfterGet: JSON.parse,
1412
1283
  encodeDataBeforeSave: JSON.stringify,
1413
1284
  isKeyConstructedFromData: false,
1414
- prefix: vehicle_positions_1.VehiclePositions.runsTrips.namespacePrefix,
1415
- }, new golemio_validator_1.Validator(vehicle_positions_1.VehiclePositions.runsTrips.name + "ModelValidator", vehicle_positions_1.VehiclePositions.runsTrips.outputMongooseSchemaObject));
1285
+ prefix: vehicle_positions_1.VehiclePositions.runs_trips.namespacePrefix,
1286
+ }, new golemio_validator_1.Validator(vehicle_positions_1.VehiclePositions.runs_trips.name + "ModelValidator", vehicle_positions_1.VehiclePositions.runs_trips.outputMongooseSchemaObject));
1416
1287
  this.queuePrefix = config_1.config.RABBIT_EXCHANGE_NAME + "." + vehicle_positions_1.VehiclePositions.name.toLowerCase();
1417
1288
  this.gtfsRtModel = new models_1.RedisModel("GTFSRealTimeModel", {
1418
1289
  isKeyConstructedFromData: false,
1419
1290
  prefix: "files:gtfsRt",
1420
1291
  });
1421
- this.tripStopsModel = new models_1.RedisModel(vehicle_positions_1.VehiclePositions.tripStops.name + "Model", {
1422
- decodeDataAfterGet: JSON.parse,
1423
- encodeDataBeforeSave: JSON.stringify,
1424
- isKeyConstructedFromData: false,
1425
- prefix: vehicle_positions_1.VehiclePositions.tripStops.namespacePrefix,
1426
- }, new golemio_validator_1.Validator(vehicle_positions_1.VehiclePositions.tripStops.name + "ModelValidator", vehicle_positions_1.VehiclePositions.tripStops.outputMongooseSchemaObject));
1427
- this.modelGTFSTrips = new RopidGTFSTripsModel_1.RopidGTFSTripsModel();
1428
1292
  this.modelGTFSStopTimes = new RopidGTFSStopTimesModel_1.RopidGTFSStopTimesModel();
1293
+ this.modelGTFSTrips = new RopidGTFSTripsModel_1.RopidGTFSTripsModel();
1429
1294
  // Create trips upsert queue for preventing transaction deadlocks
1430
1295
  this.upsertTripsFQ = fastq_1.default.promise(this.modelTrips.bulkUpsert, 1);
1431
1296
  }