UNPKG

@golemio/pid

Version:
163 lines • 8.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DepartureBoardFacade = void 0; const RouteTypeEnums_1 = require("../../../../helpers/RouteTypeEnums"); const GtfsStopParser_1 = require("../../../../helpers/GtfsStopParser"); const trace_provider_1 = require("@golemio/core/dist/monitoring/opentelemetry/trace-provider"); const golemio_errors_1 = require("@golemio/core/dist/shared/golemio-errors"); const DepartureGroupRefiner_1 = require("../helpers/DepartureGroupRefiner"); const PublicDepartureTransformation_1 = require("../transformations/PublicDepartureTransformation"); class DepartureBoardFacade { constructor(departureRepository, tripRepository, stopTimeRepository, descriptorRepository, gtfsStopsRepository) { this.departureRepository = departureRepository; this.tripRepository = tripRepository; this.stopTimeRepository = stopTimeRepository; this.descriptorRepository = descriptorRepository; this.gtfsStopsRepository = gtfsStopsRepository; this.transformation = new PublicDepartureTransformation_1.PublicDepartureTransformation(); } async getAll(stopIds, limit, routeShortNames, minutesAfter, minutesBefore) { let output; const rawStopGroupsUnfiltered = this.sortStopGroupsByPriority(stopIds); const sortedStopGroups = await this.filterForExistingStopIds(rawStopGroupsUnfiltered); const promises = sortedStopGroups.map(async (stopGroup) => await this.handleStopGroupDepartures(stopGroup, limit, routeShortNames, minutesAfter, minutesBefore)); try { output = await Promise.all(promises); } catch (err) { if (err instanceof golemio_errors_1.AbstractGolemioError) { throw err; } throw new golemio_errors_1.GeneralError("Error while retrieving cached data", this.constructor.name, err, 500); } if (output.every((value) => value === null)) { return null; } else { return output.map((value) => { if (value === null) { return []; } else { return value; } }); } } async handleStopGroupDepartures(stopGroup, limit, routeShortNames, minutesAfter, minutesBefore) { let outputGroup = []; if (!stopGroup.stopIds.length) { // Wrong stop identifier, otherwise we'd have at least one valid stopId return null; } const spanDepartures = (0, trace_provider_1.createChildSpan)(`Departures.${stopGroup.priority}.getPublicDepartureCache`); const timeFrom = new Date(Date.now() - minutesBefore * 60 * 1000); const departures = await this.departureRepository.getPublicGtfsDepartureCache(stopGroup.stopIds, minutesAfter + DepartureBoardFacade.OPEN_MINUTES_IN_PAST, new Date(timeFrom.getTime() - DepartureBoardFacade.OPEN_MINUTES_IN_PAST_MS)); spanDepartures?.end(); if (departures.length === 0) { // Did not find departure in the time-window, can be a valid result for small time-window return outputGroup; } const spanPositions = (0, trace_provider_1.createChildSpan)(`Departures.${stopGroup.priority}.getAllVehiclePositions`); const nonNullTripIds = Array.from(new Set(departures.map((departure) => departure.trip_id))).filter((x) => x); const positionsByTrip = await this.tripRepository.getAllVehiclePositionsForMultipleTrips(nonNullTripIds); spanPositions?.end(); const spanTransform = (0, trace_provider_1.createChildSpan)(`Departures.${stopGroup.priority}.transformDepartures`); try { for (const departure of departures) { if (Object.keys(departure).length === 0) { // empty departure object can happen because it is cache-placeholder without real departures continue; } const positions = positionsByTrip.get(departure.trip_id) ?? []; const duplicatedDepartures = await this.duplicateDeparturesWithDifferentVehicleIds(departure, positions); outputGroup = outputGroup.concat(duplicatedDepartures); } } catch (err) { if (err instanceof golemio_errors_1.AbstractGolemioError) { throw err; } throw new golemio_errors_1.GeneralError("Error while retrieving cached data", this.constructor.name, err, 500); } finally { spanTransform?.end(); } const spanManipulate = (0, trace_provider_1.createChildSpan)(`Departures.${stopGroup.priority}.manipulateDepartures`); try { outputGroup = DepartureGroupRefiner_1.DepartureGroupRefiner.filterDeparturesByRouteShortNames(outputGroup, routeShortNames); outputGroup = DepartureGroupRefiner_1.DepartureGroupRefiner.sortDeparturesByPredictedTimestamp(outputGroup); outputGroup = DepartureGroupRefiner_1.DepartureGroupRefiner.removeDeparturesOutsideTimeRange(outputGroup, minutesBefore, minutesAfter).slice(0, limit); } catch (err) { throw new golemio_errors_1.GeneralError("Error while manipulating departures", this.constructor.name, err, 500); } finally { spanManipulate?.end(); } return outputGroup; } async duplicateDeparturesWithDifferentVehicleIds(departure, vehiclePositions) { const outputGroup = []; // If there are no RT data, we still want to display the departure // but without any RT/vehicle information if (vehiclePositions.length === 0) { outputGroup.push(this.transformation.transformElement({ departure, vehiclePosition: null, vehicleDescriptor: null, stopTime: null, })); return outputGroup; } // Otherwise, we want to duplicate the departure for each vehicleId // (multiple vehicles can be on the same trip at the same time) for (const vehiclePosition of vehiclePositions) { const vehicleDescriptor = vehiclePosition?.detailed_info.registration_number ? await this.descriptorRepository.getOneByRegNumber(departure.route_type, vehiclePosition?.detailed_info.registration_number) : null; let currentStopTime = null; // If the vehicle is a train, we need to get the current stop time // to later determine the RT CIS platform code (trains don't have platform codes in GTFS) if (vehiclePosition.route_type === RouteTypeEnums_1.GTFSRouteTypeEnum.TRAIN) { const stopTimes = await this.stopTimeRepository.getPublicStopTimeCache(vehiclePosition.vehicle_id, departure.trip_id); currentStopTime = stopTimes.find((stopTime) => stopTime.sequence === departure.stop_sequence) ?? null; } outputGroup.push(this.transformation.transformElement({ departure, vehiclePosition, vehicleDescriptor, stopTime: currentStopTime, })); } return outputGroup; } async filterForExistingStopIds(groups) { const stopNodes = new Set(); for (const group of groups) { group.stopIds.forEach((stopId) => { stopNodes.add(GtfsStopParser_1.GtfsStopParser.normalizedNodeId(stopId)); }); } const nodesToStopIds = await this.gtfsStopsRepository.getGtfsStopIdsForAswNodes(Array.from(stopNodes.values())); if (!nodesToStopIds.size) { return []; } const foundStopIds = new Set(Array.from(nodesToStopIds.values()).flat()); const filteredGroups = []; for (const group of groups) { filteredGroups.push({ priority: group.priority, stopIds: group.stopIds.filter((s) => foundStopIds.has(s)), }); } return filteredGroups; } sortStopGroupsByPriority(stopIds) { return Array.from(stopIds).sort((a, b) => a.priority - b.priority); } } exports.DepartureBoardFacade = DepartureBoardFacade; DepartureBoardFacade.OPEN_MINUTES_IN_PAST = 61; // to be able to see empty "departure" from stop without departure DepartureBoardFacade.OPEN_MINUTES_IN_PAST_MS = DepartureBoardFacade.OPEN_MINUTES_IN_PAST * 60 * 1000; //# sourceMappingURL=DepartureBoardFacade.js.map