@golemio/pid 2.1.13 → 2.1.14-dev.511689839
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.
- package/db/example/{__truncate_tables.sql → 00_truncate_tables.sql} +0 -0
- package/db/example/{departure_directions.sql → 01_departure_directions.sql} +0 -0
- package/db/example/{pid_line_example_115.sql → 02_pid_line_example_115.sql} +0 -0
- package/db/example/{ropid_gtfs_dump.sql → 03_ropidgtfs_dump.sql} +27 -27
- package/db/example/{ropidvymi_example.sql → 04_ropidvymi_example.sql} +0 -0
- package/db/example/{vehicle_positions_dump.sql → 05_vehicle_positions_dump.sql} +0 -0
- package/db/example/06_ropidgtfs_train_trips_stop_times.sql +83 -0
- package/db/example/{tmp_example.sql → 07_tmp_example.sql} +0 -0
- package/db/example/{zzz_precomputed_tables.sql → 99_precomputed_tables.sql} +0 -0
- package/db/example/{trip_updates.pb → pb/trip_updates.pb} +0 -0
- package/db/example/{vehicle_positions.pb → pb/vehicle_positions.pb} +0 -0
- package/dist/const.d.ts +4 -0
- package/dist/const.js +6 -1
- package/dist/const.js.map +1 -1
- package/dist/integration-engine/ropid-gtfs/RopidGTFSScheduledTripsModel.d.ts +1 -1
- package/dist/integration-engine/ropid-gtfs/RopidGTFSStopTimesModel.d.ts +11 -0
- package/dist/integration-engine/ropid-gtfs/RopidGTFSStopTimesModel.js +34 -0
- package/dist/integration-engine/ropid-gtfs/RopidGTFSStopTimesModel.js.map +1 -1
- package/dist/integration-engine/ropid-gtfs/RopidGTFSTripsModel.js +2 -1
- package/dist/integration-engine/ropid-gtfs/RopidGTFSTripsModel.js.map +1 -1
- package/dist/integration-engine/ropid-gtfs/RopidGTFSWorker.js +2 -2
- package/dist/integration-engine/ropid-gtfs/RopidGTFSWorker.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/VehiclePositionsInterfaces.d.ts +152 -0
- package/dist/integration-engine/vehicle-positions/VehiclePositionsInterfaces.js +3 -0
- package/dist/integration-engine/vehicle-positions/VehiclePositionsInterfaces.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/VehiclePositionsUtils.d.ts +30 -0
- package/dist/integration-engine/vehicle-positions/VehiclePositionsUtils.js +58 -0
- package/dist/integration-engine/vehicle-positions/VehiclePositionsUtils.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/VehiclePositionsWorker.d.ts +43 -90
- package/dist/integration-engine/vehicle-positions/VehiclePositionsWorker.js +366 -231
- package/dist/integration-engine/vehicle-positions/VehiclePositionsWorker.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/index.d.ts +2 -5
- package/dist/integration-engine/vehicle-positions/index.js +2 -5
- package/dist/integration-engine/vehicle-positions/index.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsPositionsModel.d.ts → models/VehiclePositionsPositionsModel.d.ts} +3 -3
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsPositionsModel.js → models/VehiclePositionsPositionsModel.js} +3 -3
- package/dist/integration-engine/vehicle-positions/models/VehiclePositionsPositionsModel.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsRunsMessagesModel.d.ts → models/VehiclePositionsRunsMessagesModel.d.ts} +0 -0
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsRunsMessagesModel.js → models/VehiclePositionsRunsMessagesModel.js} +5 -5
- package/dist/integration-engine/vehicle-positions/models/VehiclePositionsRunsMessagesModel.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsRunsModel.d.ts → models/VehiclePositionsRunsModel.d.ts} +2 -2
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsRunsModel.js → models/VehiclePositionsRunsModel.js} +2 -2
- package/dist/integration-engine/vehicle-positions/models/VehiclePositionsRunsModel.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsStopsModel.d.ts → models/VehiclePositionsStopsModel.d.ts} +0 -0
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsStopsModel.js → models/VehiclePositionsStopsModel.js} +1 -1
- package/dist/integration-engine/vehicle-positions/models/VehiclePositionsStopsModel.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsTripsModel.d.ts → models/VehiclePositionsTripsModel.d.ts} +5 -7
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsTripsModel.js → models/VehiclePositionsTripsModel.js} +54 -31
- package/dist/integration-engine/vehicle-positions/models/VehiclePositionsTripsModel.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/models/index.d.ts +5 -0
- package/dist/integration-engine/vehicle-positions/models/index.js +18 -0
- package/dist/integration-engine/vehicle-positions/models/index.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsRunsTransformation.d.ts → transformations/VehiclePositionsRunsTransformation.d.ts} +1 -1
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsRunsTransformation.js → transformations/VehiclePositionsRunsTransformation.js} +1 -1
- package/dist/integration-engine/vehicle-positions/transformations/VehiclePositionsRunsTransformation.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/transformations/VehiclePositionsTransformation.d.ts +108 -0
- package/dist/integration-engine/vehicle-positions/{VehiclePositionsTransformation.js → transformations/VehiclePositionsTransformation.js} +42 -45
- package/dist/integration-engine/vehicle-positions/transformations/VehiclePositionsTransformation.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/transformations/index.d.ts +2 -0
- package/dist/integration-engine/vehicle-positions/transformations/index.js +15 -0
- package/dist/integration-engine/vehicle-positions/transformations/index.js.map +1 -0
- package/dist/output-gateway/vehicle-positions/models/VehiclePositionsTripsModel.js +1 -1
- package/dist/output-gateway/vehicle-positions/models/VehiclePositionsTripsModel.js.map +1 -1
- package/dist/schema-definitions/vehicle-positions/index.d.ts +9 -2
- package/dist/schema-definitions/vehicle-positions/index.js +18 -2
- package/dist/schema-definitions/vehicle-positions/index.js.map +1 -1
- package/package.json +83 -82
- package/dist/integration-engine/vehicle-positions/VehiclePositionsPositionsModel.js.map +0 -1
- package/dist/integration-engine/vehicle-positions/VehiclePositionsRunsMessagesModel.js.map +0 -1
- package/dist/integration-engine/vehicle-positions/VehiclePositionsRunsModel.js.map +0 -1
- package/dist/integration-engine/vehicle-positions/VehiclePositionsRunsTransformation.js.map +0 -1
- package/dist/integration-engine/vehicle-positions/VehiclePositionsStopsModel.js.map +0 -1
- package/dist/integration-engine/vehicle-positions/VehiclePositionsTransformation.d.ts +0 -49
- package/dist/integration-engine/vehicle-positions/VehiclePositionsTransformation.js.map +0 -1
- package/dist/integration-engine/vehicle-positions/VehiclePositionsTripsModel.js.map +0 -1
|
@@ -27,13 +27,6 @@ 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
|
-
};
|
|
37
30
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
38
31
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
39
32
|
};
|
|
@@ -52,12 +45,13 @@ const helpers_1 = require("@golemio/core/dist/integration-engine/helpers");
|
|
|
52
45
|
const models_1 = require("@golemio/core/dist/integration-engine/models");
|
|
53
46
|
const workers_1 = require("@golemio/core/dist/integration-engine/workers");
|
|
54
47
|
const ropid_gtfs_1 = require("../../schema-definitions/ropid-gtfs");
|
|
55
|
-
const RopidGTFSTripsModel_1 = require("../ropid-gtfs/RopidGTFSTripsModel");
|
|
56
48
|
const vehicle_positions_1 = require("../../schema-definitions/vehicle-positions");
|
|
57
|
-
const _1 = require("./");
|
|
58
49
|
const const_1 = require("../../const");
|
|
59
|
-
const
|
|
50
|
+
const RopidGTFSTripsModel_1 = require("../ropid-gtfs/RopidGTFSTripsModel");
|
|
60
51
|
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");
|
|
61
55
|
var PositionHandlerEnum;
|
|
62
56
|
(function (PositionHandlerEnum) {
|
|
63
57
|
PositionHandlerEnum["TRACKING"] = "TRACKING";
|
|
@@ -109,10 +103,11 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
109
103
|
}
|
|
110
104
|
}
|
|
111
105
|
for (const key in chunks) {
|
|
112
|
-
const
|
|
106
|
+
const positions = transformedData.positions.filter((position) => chunks[key].includes(position.trips_id));
|
|
107
|
+
const updatedTrips = yield this.modelTrips.findAllAssocTripIds(chunks[key]);
|
|
113
108
|
yield this.sendMessageToExchange("workers." + this.queuePrefix + ".updateDelay", JSON.stringify({
|
|
114
|
-
positions
|
|
115
|
-
updatedTrips
|
|
109
|
+
positions,
|
|
110
|
+
updatedTrips,
|
|
116
111
|
}));
|
|
117
112
|
}
|
|
118
113
|
});
|
|
@@ -131,7 +126,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
131
126
|
this.updateGTFSTripId = (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
132
127
|
const inputData = JSON.parse(msg.content.toString());
|
|
133
128
|
// unique ids in input data in key-value (id-positions) structure
|
|
134
|
-
|
|
129
|
+
let positionsByIds = {};
|
|
135
130
|
for (const position of inputData.positions) {
|
|
136
131
|
positionsByIds[position.trips_id] = position;
|
|
137
132
|
}
|
|
@@ -140,13 +135,13 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
140
135
|
if (!trip.origin_route_name || !trip.sequence_id || !positionsByIds[trip.id].origin_timestamp)
|
|
141
136
|
return;
|
|
142
137
|
const timestampLast = (0, moment_timezone_1.default)(positionsByIds[trip.id].origin_timestamp).tz("Europe/Prague").format();
|
|
143
|
-
return this.
|
|
138
|
+
return this.setAndReturnScheduledTrips({
|
|
144
139
|
route_id: trip.origin_route_name,
|
|
145
140
|
run_number: trip.sequence_id,
|
|
146
141
|
msg_last_timestamp: timestampLast,
|
|
147
142
|
});
|
|
148
143
|
}));
|
|
149
|
-
// find for each trip
|
|
144
|
+
// find gtfs data for each trip
|
|
150
145
|
const promiseValues = yield Promise.all(inputData.trips.map((trip) => __awaiter(this, void 0, void 0, function* () {
|
|
151
146
|
try {
|
|
152
147
|
return yield this.modelTrips.findGTFSTripId(trip);
|
|
@@ -156,35 +151,76 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
156
151
|
return err;
|
|
157
152
|
}
|
|
158
153
|
})));
|
|
154
|
+
let existingTripsPromiseValues = [], existingTripsPromiseErrors = [];
|
|
159
155
|
// filter only trips with found gtfs data
|
|
160
|
-
const
|
|
161
|
-
|
|
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({}));
|
|
162
187
|
let currentPosition;
|
|
163
|
-
for (const trip of
|
|
188
|
+
for (const trip of existingTripsPromiseValues) {
|
|
164
189
|
if (positionsByIds[trip.id]) {
|
|
165
190
|
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;
|
|
166
196
|
}
|
|
167
|
-
|
|
168
|
-
|
|
197
|
+
if (!currentPosition) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
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
|
|
169
204
|
const newPosition = Object.assign({}, currentPosition);
|
|
170
205
|
newPosition.trips_id = trip.id;
|
|
206
|
+
newPosition.tracking = newPositionTrackingStatus;
|
|
171
207
|
inputData.positions.push(newPosition);
|
|
172
208
|
}
|
|
173
209
|
}
|
|
174
210
|
yield this.modelPositions.save(inputData.positions);
|
|
175
211
|
// successfully updated gtfs ids
|
|
176
|
-
for (let i = 0, chunkSize = 100, imax =
|
|
212
|
+
for (let i = 0, chunkSize = 100, imax = existingTripsPromiseValues.length; i < imax; i += chunkSize) {
|
|
177
213
|
yield this.sendMessageToExchange("workers." + this.queuePrefix + ".updateDelay", JSON.stringify({
|
|
178
214
|
positions: [],
|
|
179
|
-
updatedTrips:
|
|
215
|
+
updatedTrips: existingTripsPromiseValues.slice(i, i + chunkSize),
|
|
180
216
|
}));
|
|
181
217
|
}
|
|
182
218
|
// gtfsId updating errors
|
|
183
|
-
for (let i = 0, imax =
|
|
184
|
-
helpers_1.IntegrationErrorHandler.handle(
|
|
219
|
+
for (let i = 0, imax = existingTripsPromiseErrors.length; i < imax; i++) {
|
|
220
|
+
helpers_1.IntegrationErrorHandler.handle(existingTripsPromiseErrors[i]);
|
|
185
221
|
}
|
|
186
222
|
});
|
|
187
|
-
this.generateGtfsRt = (
|
|
223
|
+
this.generateGtfsRt = () => __awaiter(this, void 0, void 0, function* () {
|
|
188
224
|
const results = yield this.modelTrips.findAllForGTFSRt();
|
|
189
225
|
const updatesMessage = gtfsRealtime.FeedMessage.create();
|
|
190
226
|
const positionsMessage = gtfsRealtime.FeedMessage.create();
|
|
@@ -205,7 +241,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
205
241
|
tripId: r.gtfs_trip_id,
|
|
206
242
|
routeId: r.gtfs_route_id,
|
|
207
243
|
};
|
|
208
|
-
const vehicleDescriptor = Object.assign({ id: r.gtfs_route_type ===
|
|
244
|
+
const vehicleDescriptor = Object.assign({ id: r.gtfs_route_type === models_2.GTFSRouteTypeEnum.TRAIN
|
|
209
245
|
? "train-" + r.cis_trip_number
|
|
210
246
|
: "service-" + r.gtfs_route_type + "-" + r.vehicle_registration_number }, (r.vehicle_registration_number && {
|
|
211
247
|
label: r.vehicle_registration_number,
|
|
@@ -334,32 +370,67 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
334
370
|
const tripIds = inputData.updatedTrips.map((trip) => trip.id);
|
|
335
371
|
if (((_b = inputData.positions) === null || _b === void 0 ? void 0 : _b.length) > 0) {
|
|
336
372
|
// unique ids in input data in key-value (id-positions) structure
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
// unique
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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;
|
|
346
387
|
}
|
|
347
388
|
else {
|
|
348
|
-
//
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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);
|
|
353
409
|
}
|
|
354
410
|
return acc;
|
|
355
|
-
}, {});
|
|
411
|
+
}), Promise.resolve({}));
|
|
356
412
|
// duplicate positions for trips with block_ids
|
|
357
413
|
for (const trip of inputData.updatedTrips) {
|
|
358
|
-
if (
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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);
|
|
362
432
|
newPosition.trips_id = trip.id;
|
|
433
|
+
newPosition.tracking = newPositionTrackingStatus;
|
|
363
434
|
inputData.positions.push(newPosition);
|
|
364
435
|
}
|
|
365
436
|
}
|
|
@@ -382,7 +453,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
382
453
|
helpers_1.log.debug("Delay Computation data (Redis) was not found. (gtfsTripId = " + trip.gtfs_trip_id + ")");
|
|
383
454
|
try {
|
|
384
455
|
const gtfs = yield this.getResultObjectForDelayCalculation(trip.gtfs_trip_id);
|
|
385
|
-
yield this.delayComputationTripsModel.set("trip_id", gtfs,
|
|
456
|
+
yield this.delayComputationTripsModel.set("trip_id", gtfs, VehiclePositionsUtils_1.VehiclePositionsUtils.DELAY_COMPUTATION_CACHE_TTL);
|
|
386
457
|
trip.gtfsData = gtfs;
|
|
387
458
|
}
|
|
388
459
|
catch (err) {
|
|
@@ -399,7 +470,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
399
470
|
}));
|
|
400
471
|
}
|
|
401
472
|
catch (err) {
|
|
402
|
-
throw new golemio_errors_1.CustomError(`Error while updating delay
|
|
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);
|
|
403
474
|
}
|
|
404
475
|
}
|
|
405
476
|
});
|
|
@@ -456,9 +527,8 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
456
527
|
* @returns {void}
|
|
457
528
|
*/
|
|
458
529
|
this.updateRunsGTFSTripId = (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
459
|
-
var e_1, _e;
|
|
460
530
|
const input = JSON.parse(msg.content.toString());
|
|
461
|
-
const schedule = yield this.
|
|
531
|
+
const schedule = yield this.setAndReturnScheduledTrips(input.run);
|
|
462
532
|
const { actual_stop_timestamp_scheduled: actualStopTimestampScheduled, msg_timestamp: msgTimestamp, events: event, } = input.run_message;
|
|
463
533
|
const delayMsg = {
|
|
464
534
|
updatedTrips: [],
|
|
@@ -473,62 +543,51 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
473
543
|
}
|
|
474
544
|
return;
|
|
475
545
|
}
|
|
476
|
-
if (actualStopTimestampScheduled) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
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
|
-
}
|
|
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)}`);
|
|
529
571
|
}
|
|
530
572
|
else {
|
|
531
|
-
|
|
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));
|
|
532
591
|
}
|
|
533
592
|
});
|
|
534
593
|
/**
|
|
@@ -558,7 +617,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
558
617
|
*
|
|
559
618
|
* @returns {string[]} array of tripIds
|
|
560
619
|
*/
|
|
561
|
-
this.
|
|
620
|
+
this.setAndReturnScheduledTrips = (scheduleData) => __awaiter(this, void 0, void 0, function* () {
|
|
562
621
|
const { route_id, run_number, msg_last_timestamp } = scheduleData;
|
|
563
622
|
const scheduledTripIds = yield this.runTripsModel.get(`${route_id}_${run_number}`);
|
|
564
623
|
if (!(scheduledTripIds === null || scheduledTripIds === void 0 ? void 0 : scheduledTripIds.schedule)) {
|
|
@@ -568,11 +627,36 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
568
627
|
el.start_timestamp = (0, moment_timezone_1.default)(el.start_timestamp).tz("Europe/Prague").format();
|
|
569
628
|
el.end_timestamp = (0, moment_timezone_1.default)(el.end_timestamp).tz("Europe/Prague").format();
|
|
570
629
|
});
|
|
571
|
-
yield this.runTripsModel.set(`${route_id}_${run_number}`, { schedule: result },
|
|
630
|
+
yield this.runTripsModel.set(`${route_id}_${run_number}`, { schedule: result }, VehiclePositionsUtils_1.VehiclePositionsUtils.RUN_TRIPS_CACHE_TTL);
|
|
572
631
|
return result;
|
|
573
632
|
}
|
|
574
633
|
return scheduledTripIds.schedule;
|
|
575
634
|
});
|
|
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
|
+
});
|
|
576
660
|
/**
|
|
577
661
|
* Takes all newly computed positions and saves it, then save the last ones to the trips
|
|
578
662
|
*
|
|
@@ -680,9 +764,9 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
680
764
|
return PositionHandlerEnum.DO_NOTHING;
|
|
681
765
|
if (position.is_canceled)
|
|
682
766
|
return PositionHandlerEnum.CANCELED;
|
|
683
|
-
if (position.lat && position.lng && position.tracking ===
|
|
767
|
+
if (position.lat && position.lng && position.tracking === const_1.PositionTrackingEnum.TRACKING)
|
|
684
768
|
return PositionHandlerEnum.TRACKING;
|
|
685
|
-
if (position.tracking !==
|
|
769
|
+
if (position.tracking !== const_1.PositionTrackingEnum.TRACKING)
|
|
686
770
|
return PositionHandlerEnum.NOT_TRACKING;
|
|
687
771
|
return PositionHandlerEnum.NOT_TRACKING;
|
|
688
772
|
};
|
|
@@ -732,7 +816,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
732
816
|
}
|
|
733
817
|
else {
|
|
734
818
|
// if there is tracking 2 position with same origin_timestamp then this position is duplicate
|
|
735
|
-
const statePosition = tripPositions.positions.find((e) => e.origin_timestamp === position.origin_timestamp && e.tracking ===
|
|
819
|
+
const statePosition = tripPositions.positions.find((e) => e.origin_timestamp === position.origin_timestamp && e.tracking === const_1.PositionTrackingEnum.TRACKING)
|
|
736
820
|
? const_1.StatePositionEnum.DUPLICATE
|
|
737
821
|
: const_1.StatePositionEnum.AFTER_TRACK;
|
|
738
822
|
const lastShapesAnchorPoint = tripPositions.gtfsData.shapes_anchor_points[tripPositions.gtfsData.shapes_anchor_points.length - 1];
|
|
@@ -825,7 +909,6 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
825
909
|
.valueOf();
|
|
826
910
|
};
|
|
827
911
|
// FIND ALL SHAPE POINTS IN POLYGON CIRCLE, GET SEGMENTS WITH CONSEQUENTING POINTS
|
|
828
|
-
// TODO this should a class method
|
|
829
912
|
this.getShapePointsAroundPosition = (tripShapePoints, radius) => __awaiter(this, void 0, void 0, function* () {
|
|
830
913
|
const ptsInRadius = [];
|
|
831
914
|
let segmentIndex = 0;
|
|
@@ -983,9 +1066,9 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
983
1066
|
if (Math.abs(timeRealDiff) < Math.abs(minTimeRealDiff)) {
|
|
984
1067
|
minTimeRealDiff = timeRealDiff;
|
|
985
1068
|
// push trip into nearest at_stop shape anchor point if trip "P" event (tram) / "V" event (bus)
|
|
986
|
-
if (((gtfsRouteType ===
|
|
1069
|
+
if (((gtfsRouteType === models_2.GTFSRouteTypeEnum.TRAM &&
|
|
987
1070
|
currentPosition.properties.tcp_event === const_1.TCPEventEnum.ARRIVAL_ANNOUNCED) ||
|
|
988
|
-
(gtfsRouteType ===
|
|
1071
|
+
(gtfsRouteType === models_2.GTFSRouteTypeEnum.BUS && currentPosition.properties.tcp_event === const_1.TCPEventEnum.V)) &&
|
|
989
1072
|
thisClosestPoint.this_stop_sequence === null) {
|
|
990
1073
|
let movingShapePointIndex = thisClosestPoint.index;
|
|
991
1074
|
while (thisClosestPoint.this_stop_sequence === null && movingShapePointIndex < lastTripShapePoint.index) {
|
|
@@ -1000,7 +1083,7 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
1000
1083
|
statePosition = const_1.StatePositionEnum.ON_TRACK;
|
|
1001
1084
|
}
|
|
1002
1085
|
// if tram position has "V" avent tram is after track
|
|
1003
|
-
if (gtfsRouteType ===
|
|
1086
|
+
if (gtfsRouteType === models_2.GTFSRouteTypeEnum.TRAM && currentPosition.properties.tcp_event === const_1.TCPEventEnum.V) {
|
|
1004
1087
|
statePosition = const_1.StatePositionEnum.AFTER_TRACK;
|
|
1005
1088
|
thisClosestPoint = lastTripShapePoint;
|
|
1006
1089
|
timeDelay = null;
|
|
@@ -1062,17 +1145,17 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
1062
1145
|
* @returns {IPositionToUpdate} - Position object to update
|
|
1063
1146
|
*/
|
|
1064
1147
|
this.getEstimatedPoint = (tripGtfsData, currentPosition, context, startDayTimestamp, gtfsRouteType) => __awaiter(this, void 0, void 0, function* () {
|
|
1065
|
-
var _f, _g, _h, _j, _k
|
|
1148
|
+
var _e, _f, _g, _h, _j, _k;
|
|
1066
1149
|
// init radius around GPS position ( 200 meters radius, 16 points polygon aka circle)
|
|
1067
1150
|
const radius = turf.circle(currentPosition, 0.2, { steps: 16 });
|
|
1068
1151
|
//Initial value
|
|
1069
1152
|
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 &&
|
|
1070
|
-
((
|
|
1071
|
-
shape_dist_traveled: (
|
|
1072
|
-
last_stop_arrival_time: (
|
|
1073
|
-
last_stop_departure_time: (
|
|
1074
|
-
last_stop_sequence: (
|
|
1075
|
-
last_stop_id: (
|
|
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,
|
|
1076
1159
|
}));
|
|
1077
1160
|
// returns array of segments (row of points) of shape anchor points around gps
|
|
1078
1161
|
const ptsInRadius = yield this.getShapePointsAroundPosition(tripGtfsData.shapes_anchor_points, radius);
|
|
@@ -1103,59 +1186,13 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
1103
1186
|
if (!stopTimes || !stopTimes.stop_times || stopTimes.stop_times.length === 0) {
|
|
1104
1187
|
throw new Error(`"trip.stop_times" was not found for id ${tripId}.`);
|
|
1105
1188
|
}
|
|
1106
|
-
|
|
1107
|
-
const shapesGeometryAnchorPoints = yield this.getShapesGeometryAnchorPoints(stopTimes.shape_id, shapes.shapes);
|
|
1108
|
-
// ----------------------------------------------
|
|
1109
|
-
// TEMP constS
|
|
1110
|
-
const stopSequenceMaximum = stopTimes.stop_times.length;
|
|
1189
|
+
const shapesGeometryAnchorPoints = this.getShapesGeometryAnchorPoints(stopTimes.shape_id, shapes.shapes, stopTimes.stop_times);
|
|
1111
1190
|
// MAKING COPY
|
|
1112
1191
|
const shapePoints = [];
|
|
1113
1192
|
// const to determine shape points of stops (in meters)
|
|
1114
|
-
const distanceBefore =
|
|
1115
|
-
const distanceAfter =
|
|
1116
|
-
|
|
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
|
-
}
|
|
1193
|
+
const distanceBefore = 0.1;
|
|
1194
|
+
const distanceAfter = 0.05;
|
|
1195
|
+
for (let i = 0; i < shapesGeometryAnchorPoints.length; i++) {
|
|
1159
1196
|
let bearing = 0;
|
|
1160
1197
|
// add bearing from shape computed for previous shapePoint
|
|
1161
1198
|
if (i > 0) {
|
|
@@ -1173,13 +1210,37 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
1173
1210
|
bearing = shapePoints[i - 1].bearing;
|
|
1174
1211
|
}
|
|
1175
1212
|
}
|
|
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
|
+
}
|
|
1176
1237
|
const distanceFromLastStop = Math.round((shapesGeometryAnchorPoints[i].shape_dist_traveled -
|
|
1177
1238
|
stopTimes.stop_times[lastStopSequence - 1].shape_dist_traveled) *
|
|
1178
1239
|
1000) / 1000;
|
|
1179
1240
|
// if is trip at stop than set departure by this stop
|
|
1180
1241
|
// between stops do linear interpolation from departure from last stop and arrival of next stop
|
|
1181
|
-
const timeScheduledSeconds =
|
|
1182
|
-
? stopTimes.stop_times[lastStopSequence - 1].
|
|
1242
|
+
const timeScheduledSeconds = thisStopSequence !== null
|
|
1243
|
+
? stopTimes.stop_times[lastStopSequence - 1].arrival_time_seconds
|
|
1183
1244
|
: stopTimes.stop_times[lastStopSequence - 1].departure_time_seconds +
|
|
1184
1245
|
Math.round(((stopTimes.stop_times[nextStopSequence - 1].arrival_time_seconds -
|
|
1185
1246
|
stopTimes.stop_times[lastStopSequence - 1].departure_time_seconds) *
|
|
@@ -1188,29 +1249,22 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
1188
1249
|
stopTimes.stop_times[lastStopSequence - 1].shape_dist_traveled));
|
|
1189
1250
|
shapePoints.push({
|
|
1190
1251
|
index: i,
|
|
1191
|
-
at_stop:
|
|
1252
|
+
at_stop: thisStopSequence !== null,
|
|
1192
1253
|
bearing,
|
|
1193
1254
|
coordinates: shapesGeometryAnchorPoints[i].coordinates,
|
|
1194
1255
|
distance_from_last_stop: distanceFromLastStop,
|
|
1195
1256
|
last_stop_sequence: lastStopSequence,
|
|
1196
1257
|
next_stop_sequence: nextStopSequence,
|
|
1197
|
-
shape_dist_traveled: shapesGeometryAnchorPoints[i].shape_dist_traveled,
|
|
1198
|
-
this_stop_sequence:
|
|
1258
|
+
shape_dist_traveled: Math.round(shapesGeometryAnchorPoints[i].shape_dist_traveled * 100000) / 100000,
|
|
1259
|
+
this_stop_sequence: thisStopSequence,
|
|
1199
1260
|
time_scheduled_seconds: timeScheduledSeconds,
|
|
1200
1261
|
});
|
|
1201
|
-
|
|
1202
|
-
|
|
1262
|
+
}
|
|
1263
|
+
return {
|
|
1264
|
+
trip_id: tripId,
|
|
1265
|
+
stop_times: stopTimes.stop_times,
|
|
1266
|
+
shapes_anchor_points: shapePoints,
|
|
1203
1267
|
};
|
|
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
|
-
});
|
|
1214
1268
|
}
|
|
1215
1269
|
catch (err) {
|
|
1216
1270
|
helpers_1.log.error(err);
|
|
@@ -1222,75 +1276,156 @@ class VehiclePositionsWorker extends workers_1.BaseWorker {
|
|
|
1222
1276
|
*
|
|
1223
1277
|
* @param {string} shapeId - GTFS shape id
|
|
1224
1278
|
* @param {ITransformedTripShape[]} shapes - GTFS shape points
|
|
1279
|
+
* @param {IStopTime[]} stops
|
|
1225
1280
|
* @returns {IShapeGeometryAnchorPoint[]} - Result array of geometry points along trip track shape
|
|
1226
1281
|
*/
|
|
1227
|
-
this.getShapesGeometryAnchorPoints = (shapeId, shapes) =>
|
|
1228
|
-
var _m;
|
|
1229
|
-
const shapesAnchorPoints = [];
|
|
1282
|
+
this.getShapesGeometryAnchorPoints = (shapeId, shapes, stops) => {
|
|
1230
1283
|
try {
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
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
|
+
}
|
|
1244
1298
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
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;
|
|
1320
|
+
}
|
|
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,
|
|
1261
1347
|
});
|
|
1348
|
+
return resultArr;
|
|
1262
1349
|
}
|
|
1263
1350
|
catch (err) {
|
|
1264
1351
|
helpers_1.log.error(err);
|
|
1265
1352
|
helpers_1.log.error(shapeId);
|
|
1266
|
-
return
|
|
1353
|
+
return [];
|
|
1267
1354
|
}
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
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();
|
|
1275
1404
|
this.delayComputationTripsModel = new models_1.RedisModel(ropid_gtfs_1.RopidGTFS.delayComputationTrips.name + "Model", {
|
|
1276
1405
|
decodeDataAfterGet: JSON.parse,
|
|
1277
1406
|
encodeDataBeforeSave: JSON.stringify,
|
|
1278
1407
|
isKeyConstructedFromData: true,
|
|
1279
1408
|
prefix: ropid_gtfs_1.RopidGTFS.delayComputationTrips.mongoCollectionName,
|
|
1280
1409
|
}, new golemio_validator_1.Validator(ropid_gtfs_1.RopidGTFS.delayComputationTrips.name + "ModelValidator", ropid_gtfs_1.RopidGTFS.delayComputationTrips.outputMongooseSchemaObject));
|
|
1281
|
-
this.runTripsModel = new models_1.RedisModel(vehicle_positions_1.VehiclePositions.
|
|
1410
|
+
this.runTripsModel = new models_1.RedisModel(vehicle_positions_1.VehiclePositions.runsTrips.name + "Model", {
|
|
1282
1411
|
decodeDataAfterGet: JSON.parse,
|
|
1283
1412
|
encodeDataBeforeSave: JSON.stringify,
|
|
1284
1413
|
isKeyConstructedFromData: false,
|
|
1285
|
-
prefix: vehicle_positions_1.VehiclePositions.
|
|
1286
|
-
}, new golemio_validator_1.Validator(vehicle_positions_1.VehiclePositions.
|
|
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));
|
|
1287
1416
|
this.queuePrefix = config_1.config.RABBIT_EXCHANGE_NAME + "." + vehicle_positions_1.VehiclePositions.name.toLowerCase();
|
|
1288
1417
|
this.gtfsRtModel = new models_1.RedisModel("GTFSRealTimeModel", {
|
|
1289
1418
|
isKeyConstructedFromData: false,
|
|
1290
1419
|
prefix: "files:gtfsRt",
|
|
1291
1420
|
});
|
|
1292
|
-
this.
|
|
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));
|
|
1293
1427
|
this.modelGTFSTrips = new RopidGTFSTripsModel_1.RopidGTFSTripsModel();
|
|
1428
|
+
this.modelGTFSStopTimes = new RopidGTFSStopTimesModel_1.RopidGTFSStopTimesModel();
|
|
1294
1429
|
// Create trips upsert queue for preventing transaction deadlocks
|
|
1295
1430
|
this.upsertTripsFQ = fastq_1.default.promise(this.modelTrips.bulkUpsert, 1);
|
|
1296
1431
|
}
|