diff --git a/src/repositories/shuttle/RedisShuttleRepository.ts b/src/repositories/shuttle/RedisShuttleRepository.ts index 3cd452b..1b7ffd0 100644 --- a/src/repositories/shuttle/RedisShuttleRepository.ts +++ b/src/repositories/shuttle/RedisShuttleRepository.ts @@ -405,7 +405,10 @@ export class RedisShuttleRepository extends BaseRedisRepository implements Shutt timestamp: new Date(travelTimeTimestamp), shuttleId: shuttle.id, }; - this.emit(ShuttleRepositoryEvent.SHUTTLE_WILL_ARRIVE_AT_STOP, shuttleArrival); + this.emit(ShuttleRepositoryEvent.SHUTTLE_WILL_ARRIVE_AT_STOP, { + lastArrival: lastStop, + currentArrival: shuttleArrival, + }); await this.updateShuttleLastStopArrival(shuttleArrival); } } diff --git a/src/repositories/shuttle/ShuttleGetterRepository.ts b/src/repositories/shuttle/ShuttleGetterRepository.ts index 22118c5..7fbab0c 100644 --- a/src/repositories/shuttle/ShuttleGetterRepository.ts +++ b/src/repositories/shuttle/ShuttleGetterRepository.ts @@ -12,10 +12,15 @@ export type ShuttleRepositoryEventName = typeof ShuttleRepositoryEvent[keyof typ export type EtaRemovedEventPayload = IEta; export type EtaDataClearedEventPayload = IEta[]; +export interface WillArriveAtStopPayload { + lastArrival?: ShuttleStopArrival; + currentArrival: ShuttleStopArrival; +}; + export interface ShuttleRepositoryEventPayloads { [ShuttleRepositoryEvent.SHUTTLE_UPDATED]: IShuttle, [ShuttleRepositoryEvent.SHUTTLE_REMOVED]: IShuttle, - [ShuttleRepositoryEvent.SHUTTLE_WILL_ARRIVE_AT_STOP]: ShuttleStopArrival, + [ShuttleRepositoryEvent.SHUTTLE_WILL_ARRIVE_AT_STOP]: WillArriveAtStopPayload, } export type ShuttleRepositoryEventListener = ( diff --git a/src/repositories/shuttle/UnoptimizedInMemoryShuttleRepository.ts b/src/repositories/shuttle/UnoptimizedInMemoryShuttleRepository.ts index 068e6f7..14ba7d7 100644 --- a/src/repositories/shuttle/UnoptimizedInMemoryShuttleRepository.ts +++ b/src/repositories/shuttle/UnoptimizedInMemoryShuttleRepository.ts @@ -177,12 +177,19 @@ export class UnoptimizedInMemoryShuttleRepository const arrivedStop = await this.getArrivedStopIfExists(shuttle); if (arrivedStop != undefined) { + // stop if same stop + const lastStop = await this.getShuttleLastStopArrival(shuttle.id); + if (lastStop?.stopId === arrivedStop.id) return; + const shuttleArrival = { stopId: arrivedStop.id, timestamp: new Date(travelTimeTimestamp), shuttleId: shuttle.id, }; - this.emit(ShuttleRepositoryEvent.SHUTTLE_WILL_ARRIVE_AT_STOP, shuttleArrival); + this.emit(ShuttleRepositoryEvent.SHUTTLE_WILL_ARRIVE_AT_STOP, { + lastArrival: lastStop, + currentArrival: shuttleArrival, + }); await this.updateShuttleLastStopArrival(shuttleArrival); } } diff --git a/src/repositories/shuttle/__tests__/ShuttleRepositorySharedTests.test.ts b/src/repositories/shuttle/__tests__/ShuttleRepositorySharedTests.test.ts index e41971b..b45f2a3 100644 --- a/src/repositories/shuttle/__tests__/ShuttleRepositorySharedTests.test.ts +++ b/src/repositories/shuttle/__tests__/ShuttleRepositorySharedTests.test.ts @@ -734,9 +734,11 @@ describe.each(repositoryImplementations)('$name', (holder) => { expect(listener).toHaveBeenCalledTimes(1); const emittedPayload = listener.mock.calls[0][0] as any; - expect(emittedPayload.shuttleId).toBe(shuttle.id); - expect(emittedPayload.stopId).toBe(stop1.id); - expect(emittedPayload.timestamp.getTime()).toBe(arrivalTime.getTime()); + expect(emittedPayload.currentArrival).toEqual({ + shuttleId: shuttle.id, + stopId: stop1.id, + timestamp: arrivalTime, + }); }); test("does not emit event when shuttle is not at a stop", async () => { @@ -786,14 +788,18 @@ describe.each(repositoryImplementations)('$name', (holder) => { expect(listener).toHaveBeenCalledTimes(2); const firstPayload = listener.mock.calls[0][0] as any; - expect(firstPayload.shuttleId).toBe(shuttle.id); - expect(firstPayload.stopId).toBe(stop1.id); - expect(firstPayload.timestamp.getTime()).toBe(firstArrivalTime.getTime()); + expect(firstPayload.currentArrival).toEqual({ + shuttleId: shuttle.id, + stopId: stop1.id, + timestamp: firstArrivalTime, + }); const secondPayload = listener.mock.calls[1][0] as any; - expect(secondPayload.shuttleId).toBe(shuttle.id); - expect(secondPayload.stopId).toBe(stop2.id); - expect(secondPayload.timestamp.getTime()).toBe(secondArrivalTime.getTime()); + expect(secondPayload.currentArrival).toEqual({ + shuttleId: shuttle.id, + stopId: stop2.id, + timestamp: secondArrivalTime, + }); }); }); }); diff --git a/src/repositories/shuttle/eta/InMemorySelfUpdatingETARepository.ts b/src/repositories/shuttle/eta/InMemorySelfUpdatingETARepository.ts index bc56789..917e6bc 100644 --- a/src/repositories/shuttle/eta/InMemorySelfUpdatingETARepository.ts +++ b/src/repositories/shuttle/eta/InMemorySelfUpdatingETARepository.ts @@ -1,5 +1,5 @@ import { SelfUpdatingETARepository } from "./SelfUpdatingETARepository"; -import { ShuttleGetterRepository, ShuttleRepositoryEvent, ShuttleStopArrival, ShuttleTravelTimeDataIdentifier, ShuttleTravelTimeDateFilterArguments } from "../ShuttleGetterRepository"; +import { ShuttleGetterRepository, ShuttleRepositoryEvent, ShuttleStopArrival, ShuttleTravelTimeDataIdentifier, ShuttleTravelTimeDateFilterArguments, WillArriveAtStopPayload } from "../ShuttleGetterRepository"; import { BaseInMemoryETARepository } from "./BaseInMemoryETARepository"; import { IOrderedStop, IShuttle } from "../../../entities/ShuttleRepositoryEntities"; import { ETARepositoryEvent } from "./ETAGetterRepository"; @@ -155,26 +155,28 @@ export class InMemorySelfUpdatingETARepository extends BaseInMemoryETARepository ) } - private async handleShuttleWillArriveAtStop(shuttleArrival: ShuttleStopArrival): Promise { - const etas = await this.getEtasForShuttleId(shuttleArrival.shuttleId); + private async handleShuttleWillArriveAtStop({ + lastArrival, + currentArrival, + }: WillArriveAtStopPayload): Promise { + const etas = await this.getEtasForShuttleId(currentArrival.shuttleId); for (const eta of etas) { await this.removeEtaIfExists(eta.shuttleId, eta.stopId); } - const lastStopTimestamp = await this.shuttleRepository.getShuttleLastStopArrival(shuttleArrival.shuttleId); - if (lastStopTimestamp) { + if (lastArrival) { // disallow cases where this gets triggered multiple times - if (lastStopTimestamp.stopId === shuttleArrival.stopId) return; + if (lastArrival.stopId === currentArrival.stopId) return; - const shuttle = await this.shuttleRepository.getShuttleById(lastStopTimestamp.shuttleId); + const shuttle = await this.shuttleRepository.getShuttleById(lastArrival.shuttleId); if (!shuttle) return; const routeId = shuttle.routeId; - const fromStopId = lastStopTimestamp.stopId; - const toStopId = shuttleArrival.stopId; + const fromStopId = lastArrival.stopId; + const toStopId = currentArrival.stopId; - const travelTimeSeconds = (shuttleArrival.timestamp.getTime() - lastStopTimestamp.timestamp.getTime()) / 1000; - await this.addTravelTimeDataPoint({ routeId, fromStopId, toStopId }, travelTimeSeconds, shuttleArrival.timestamp.getTime()); + const travelTimeSeconds = (currentArrival.timestamp.getTime() - lastArrival.timestamp.getTime()) / 1000; + await this.addTravelTimeDataPoint({ routeId, fromStopId, toStopId }, travelTimeSeconds, currentArrival.timestamp.getTime()); } } diff --git a/src/repositories/shuttle/eta/RedisSelfUpdatingETARepository.ts b/src/repositories/shuttle/eta/RedisSelfUpdatingETARepository.ts index 6ce6e24..9481331 100644 --- a/src/repositories/shuttle/eta/RedisSelfUpdatingETARepository.ts +++ b/src/repositories/shuttle/eta/RedisSelfUpdatingETARepository.ts @@ -1,7 +1,7 @@ import { SelfUpdatingETARepository } from "./SelfUpdatingETARepository"; import { BaseRedisETARepository } from "./BaseRedisETARepository"; import { createClient, RedisClientType } from "redis"; -import { ShuttleGetterRepository, ShuttleRepositoryEvent, ShuttleStopArrival, ShuttleTravelTimeDataIdentifier, ShuttleTravelTimeDateFilterArguments } from "../ShuttleGetterRepository"; +import { ShuttleGetterRepository, ShuttleRepositoryEvent, ShuttleStopArrival, ShuttleTravelTimeDataIdentifier, ShuttleTravelTimeDateFilterArguments, WillArriveAtStopPayload } from "../ShuttleGetterRepository"; import { REDIS_RECONNECT_INTERVAL } from "../../../environment"; import { IEta, IOrderedStop, IShuttle } from "../../../entities/ShuttleRepositoryEntities"; import { ETARepositoryEvent } from "./ETAGetterRepository"; @@ -174,28 +174,29 @@ export class RedisSelfUpdatingETARepository extends BaseRedisETARepository imple } - private async handleShuttleWillArriveAtStop( - shuttleArrival: ShuttleStopArrival, - ) { - const etas = await this.getEtasForShuttleId(shuttleArrival.shuttleId); + private async handleShuttleWillArriveAtStop({ + lastArrival, + currentArrival, + }: WillArriveAtStopPayload) { + const etas = await this.getEtasForShuttleId(currentArrival.shuttleId); for (const eta of etas) { await this.removeEtaIfExists(eta.shuttleId, eta.stopId); } - const lastStopTimestamp = await this.shuttleRepository.getShuttleLastStopArrival(shuttleArrival.shuttleId); - if (lastStopTimestamp) { + // only update time traveled if last arrival exists + if (lastArrival) { // disallow cases where this gets triggered multiple times - if (lastStopTimestamp.stopId === shuttleArrival.stopId) return; + if (lastArrival.stopId === currentArrival.stopId) return; - const shuttle = await this.shuttleRepository.getShuttleById(lastStopTimestamp.shuttleId); + const shuttle = await this.shuttleRepository.getShuttleById(lastArrival.shuttleId); if (!shuttle) return; const routeId = shuttle.routeId; - const fromStopId = lastStopTimestamp.stopId; - const toStopId = shuttleArrival.stopId; + const fromStopId = lastArrival.stopId; + const toStopId = currentArrival.stopId; - const travelTimeSeconds = (shuttleArrival.timestamp.getTime() - lastStopTimestamp.timestamp.getTime()) / 1000; - await this.addTravelTimeDataPoint({ routeId, fromStopId, toStopId, }, travelTimeSeconds, shuttleArrival.timestamp.getTime()); + const travelTimeSeconds = (currentArrival.timestamp.getTime() - lastArrival.timestamp.getTime()) / 1000; + await this.addTravelTimeDataPoint({ routeId, fromStopId, toStopId, }, travelTimeSeconds, currentArrival.timestamp.getTime()); } }