UNPKG

@golemio/pid

Version:
232 lines • 10.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PublicVehiclePositionsRepository = void 0; const IoRedisConnector_1 = require("@golemio/core/dist/helpers/data-access/redis/IoRedisConnector"); const CoreToken_1 = require("@golemio/core/dist/helpers/ioc/CoreToken"); const ioc_1 = require("@golemio/core/dist/output-gateway/ioc"); const golemio_errors_1 = require("@golemio/core/dist/shared/golemio-errors"); const tsyringe_1 = require("@golemio/core/dist/shared/tsyringe"); let PublicVehiclePositionsRepository = exports.PublicVehiclePositionsRepository = class PublicVehiclePositionsRepository { constructor(redisConnector, log) { this.redisConnector = redisConnector; this.log = log; this.setName = undefined; // loaded via pub sub } setCurrentSetName(name) { this.setName = name; } async getAllVehicleIds(boundingBox) { if (!this.setName) { this.log.debug("Empty setName for public vehicle positions api."); return []; } if (!this.redisConnector.isConnected()) { await this.redisConnector.connect(); } const connection = this.redisConnector.getConnection(); let vehicleIds = []; try { vehicleIds = (await connection.geosearch(this.setName, "FROMLONLAT", boundingBox.centerPoint.longitude, boundingBox.centerPoint.latitude, "BYBOX", boundingBox.width, boundingBox.height, "m", "ASC")); } catch (error) { throw new golemio_errors_1.GeneralError("Cannot get vehicle ids from cache", this.constructor.name, error); } return vehicleIds; } async getAllVehiclePositions(vehicleIds, tripIds) { if (!this.setName) { this.log.debug("Empty setName for public vehicle positions api."); return []; } const connection = this.redisConnector.getConnection(); let vehiclePositions = []; try { const keys = []; if (tripIds) { for (const tripId of tripIds) { keys.push(...vehicleIds.map((vehicleId) => `${this.setName}:future-vehicle-${vehicleId}-${tripId}`)); } } else { keys.push(...vehicleIds.map((vehicleId) => `${this.setName}:vehicle-${vehicleId}`)); } vehiclePositions = await connection.mget(keys); } catch (error) { throw new golemio_errors_1.GeneralError("Cannot get vehicle positions from cache", this.constructor.name, error); } const parsedVehiclePositions = []; for (const vehiclePosition of vehiclePositions) { if (vehiclePosition === null) { continue; } try { parsedVehiclePositions.push(JSON.parse(vehiclePosition)); } catch (error) { throw new golemio_errors_1.GeneralError("Cannot parse vehicle position", this.constructor.name, error); } } return parsedVehiclePositions; } async getAllVehiclePositionsForMultipleTrips(tripIds) { const positionsByTrip = new Map(); if (!this.setName || tripIds.length === 0) { this.log.debug("Empty setName for public vehicle positions api or empty trip ids."); return positionsByTrip; } if (!this.redisConnector.isConnected()) { await this.redisConnector.connect(); } const [vehicleIdsCurrent, vehicleIdsFuture] = await Promise.all([ this.getVehicleIdsForMultiple(tripIds, "trip"), this.getVehicleIdsForMultiple(tripIds, "future-trip"), ]); const vehicleIds = Array.from(new Set([...vehicleIdsCurrent, ...vehicleIdsFuture])); if (vehicleIds.length > 0) { const allPositions = await this.getAllVehiclePositions(vehicleIds); for (const position of allPositions) { if (!positionsByTrip.has(position.gtfs_trip_id)) { positionsByTrip.set(position.gtfs_trip_id, []); } positionsByTrip.get(position.gtfs_trip_id).push(position); } const futurePositions = await this.getAllVehiclePositions(vehicleIds, tripIds); for (const position of futurePositions) { if (!positionsByTrip.has(position.gtfs_trip_id)) { positionsByTrip.set(position.gtfs_trip_id, []); } positionsByTrip.get(position.gtfs_trip_id).push(position); } } const canceledTrips = await this.getCanceledTrips(tripIds); for (const canceledTrip of canceledTrips) { positionsByTrip.set(canceledTrip.gtfs_trip_id, [canceledTrip]); } return positionsByTrip; } async getTripsWithUntrackedVehicles(tripIds) { const untrackedTrips = new Set(); if (!this.setName || tripIds.length === 0) { this.log.debug("Empty setName for public vehicle positions api or empty trip ids."); return untrackedTrips; } if (!this.redisConnector.isConnected()) { await this.redisConnector.connect(); } const vehicleIds = await this.getVehicleIdsForMultiple(tripIds, "trip"); try { // TODO optimization point here - use JSON.GET once it's available in the redis/valkey server const allPositions = await this.getAllVehiclePositions(vehicleIds); for (let i = 0; i < allPositions.length; i++) { if (allPositions[i].delay === null) { untrackedTrips.add(allPositions[i].gtfs_trip_id); } } } catch (error) { throw new golemio_errors_1.GeneralError("Cannot get vehicle positions from cache", this.constructor.name, error); } return untrackedTrips; } // Current trips are saved in the cache with key made from vehicleId only. For future trips tripId has to be also provided. async getDetailedVehiclePosition(vehicleId, tripId) { if (!this.setName) { this.log.debug("Empty setName for public vehicle positions api."); return null; } if (!this.redisConnector.isConnected()) { await this.redisConnector.connect(); } const connection = this.redisConnector.getConnection(); let vehiclePosition = null; try { const key = tripId ? `${this.setName}:future-trip-${vehicleId}-${tripId}` : `${this.setName}:vehicle-${vehicleId}`; vehiclePosition = await connection.get(key); } catch (error) { this.log.error(error, "Cannot get vehicle position from cache"); throw new golemio_errors_1.GeneralError("Cannot get vehicle position from cache", this.constructor.name, error); } if (vehiclePosition === null) { this.log.info(`${this.constructor.name}: Cannot find vehicle_id ${vehicleId}`); return null; } try { return JSON.parse(vehiclePosition); } catch (error) { this.log.error(error, `Cannot parse ${vehicleId}`); throw new golemio_errors_1.GeneralError(`Cannot parse ${vehicleId}`, this.constructor.name, error); } } async getVehicleIdsForMultiple(tripIds, keyPrefix) { const vehicleIdsByTrip = new Map(); const connection = this.redisConnector.getConnection(); const pipeline = connection.pipeline(); for (const tripId of tripIds) { pipeline.lrange(`${this.setName}:${keyPrefix}-${tripId}`, 0, -1); } try { const trips = await pipeline.exec(); for (const [error, vehicleIds] of trips) { if (error) { throw new golemio_errors_1.GeneralError(`Cannot get vehicle ids for ${keyPrefix} from cache`, this.constructor.name, error); } vehicleIdsByTrip.set(tripIds[vehicleIdsByTrip.size], vehicleIds); } } catch (error) { if (error instanceof golemio_errors_1.GeneralError) { throw error; } throw new golemio_errors_1.GeneralError(`Cannot get vehicle ids for ${keyPrefix} from cache`, this.constructor.name, error); } return Array.from(vehicleIdsByTrip.values()).flat(); } async getCanceledTrips(tripIds) { const connection = this.redisConnector.getConnection(); const parsedCanceledTrips = []; if (tripIds.length === 0) { return []; } const keys = []; for (const tripId of tripIds) { keys.push(`${this.setName}:canceled-trips-${tripId}`); } const canceledTrips = await connection.mget(keys); for (const canceledTrip of canceledTrips) { if (canceledTrip === null) { continue; } else { try { parsedCanceledTrips.push(JSON.parse(canceledTrip)); } catch (error) { throw new golemio_errors_1.GeneralError("Cannot parse canceled trip", this.constructor.name, error); } } } return parsedCanceledTrips; } }; exports.PublicVehiclePositionsRepository = PublicVehiclePositionsRepository = __decorate([ (0, tsyringe_1.injectable)(), __param(0, (0, tsyringe_1.inject)(ioc_1.ContainerToken.RedisConnector)), __param(1, (0, tsyringe_1.inject)(CoreToken_1.CoreToken.Logger)), __metadata("design:paramtypes", [IoRedisConnector_1.IoRedisConnector, Object]) ], PublicVehiclePositionsRepository); //# sourceMappingURL=PublicVehiclePositionsRepository.js.map