import { ETANotificationScheduler } from "../notifications/schedulers/ETANotificationScheduler"; import { TimedApiBasedRepositoryLoader } from "../loaders/TimedApiBasedRepositoryLoader"; import { UnoptimizedInMemoryShuttleRepository } from "../repositories/UnoptimizedInMemoryShuttleRepository"; import { RedisNotificationRepository } from "../repositories/RedisNotificationRepository"; import { NotificationRepository } from "../repositories/NotificationRepository"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; import { InMemoryNotificationRepository } from "../repositories/InMemoryNotificationRepository"; import { AppleNotificationSender } from "../notifications/senders/AppleNotificationSender"; import { ApiBasedShuttleRepositoryLoader } from "../loaders/shuttle/ApiBasedShuttleRepositoryLoader"; import { ParkingGetterSetterRepository } from "../repositories/ParkingGetterSetterRepository"; import { InMemoryParkingRepository } from "../repositories/InMemoryParkingRepository"; import { buildParkingRepositoryLoaderIfExists, ParkingRepositoryLoaderBuilderArguments } from "../loaders/parking/buildParkingRepositoryLoaderIfExists"; export interface InterchangeSystemBuilderArguments { name: string; /** * ID to identify the system internally and in the API. */ id: string; /** * ID for fetching shuttle data from the Passio GO! system. */ passioSystemId: string; /** * ID for the parking repository ID in the codebase. */ parkingSystemId?: string; } export class InterchangeSystem { private constructor( public name: string, public id: string, public shuttleTimedDataLoader: TimedApiBasedRepositoryLoader, public shuttleRepository: ShuttleGetterSetterRepository, public notificationScheduler: ETANotificationScheduler, public notificationRepository: NotificationRepository, public parkingTimedDataLoader: TimedApiBasedRepositoryLoader | null, public parkingRepository: ParkingGetterSetterRepository | null, ) { } /** * Construct an instance of the class where all composited * classes are correctly linked, meant for use in development and production. * @param args */ static async build( args: InterchangeSystemBuilderArguments, ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); const shuttleDataLoader = new ApiBasedShuttleRepositoryLoader( args.passioSystemId, args.id, shuttleRepository ); const timedShuttleDataLoader = new TimedApiBasedRepositoryLoader( shuttleDataLoader, ); await timedShuttleDataLoader.start(); const notificationRepository = new RedisNotificationRepository(); await notificationRepository.connect(); const notificationScheduler = new ETANotificationScheduler( shuttleRepository, notificationRepository, new AppleNotificationSender(), args.id, ); notificationScheduler.startListeningForUpdates(); let { parkingRepository, timedParkingLoader } = this.buildParkingLoaderAndRepository(args.parkingSystemId); timedParkingLoader?.start(); return new InterchangeSystem( args.name, args.id, timedShuttleDataLoader, shuttleRepository, notificationScheduler, notificationRepository, timedParkingLoader, parkingRepository, ); } /** * Construct an instance of the class where all composited * classes are correctly linked, meant for unit tests, and server/app * integration tests. * @param args */ static buildForTesting( args: InterchangeSystemBuilderArguments, ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); const shuttleDataLoader = new ApiBasedShuttleRepositoryLoader( args.passioSystemId, args.id, shuttleRepository ); // Note that this loader should not be started, // so the test data doesn't get overwritten const timedShuttleLoader = new TimedApiBasedRepositoryLoader( shuttleDataLoader, ); const notificationRepository = new InMemoryNotificationRepository(); const notificationScheduler = new ETANotificationScheduler( shuttleRepository, notificationRepository, new AppleNotificationSender(false), args.id, ); notificationScheduler.startListeningForUpdates(); let { parkingRepository, timedParkingLoader } = this.buildParkingLoaderAndRepository(args.parkingSystemId); // Timed parking loader is not started return new InterchangeSystem( args.name, args.id, timedShuttleLoader, shuttleRepository, notificationScheduler, notificationRepository, timedParkingLoader, parkingRepository, ); } private static buildParkingLoaderAndRepository(id?: string) { if (id === undefined) { return { parkingRepository: null, timedParkingLoader: null }; } let parkingRepository: ParkingGetterSetterRepository | null = new InMemoryParkingRepository(); const loaderBuilderArguments: ParkingRepositoryLoaderBuilderArguments = { id, repository: parkingRepository, }; let parkingLoader = buildParkingRepositoryLoaderIfExists( loaderBuilderArguments, ); let timedParkingLoader = null; if (parkingLoader == null) { parkingRepository = null; } else { timedParkingLoader = new TimedApiBasedRepositoryLoader(parkingLoader); } return { parkingRepository, timedParkingLoader }; } }