diff --git a/src/notifications/schedulers/ETANotificationScheduler.ts b/src/notifications/schedulers/ETANotificationScheduler.ts index 480fc2b..76c6027 100644 --- a/src/notifications/schedulers/ETANotificationScheduler.ts +++ b/src/notifications/schedulers/ETANotificationScheduler.ts @@ -20,8 +20,10 @@ export interface ScheduledNotificationData { secondsThreshold?: number; } +type DeviceIdSecondsThresholdAssociation = { [key: string]: number }; + export class ETANotificationScheduler { - public readonly secondsThresholdForNotificationToFire = 180; + public readonly defaultSecondsThresholdForNotificationToFire = 180; constructor(private repository: GetterRepository, private appleNotificationSender = new AppleNotificationSender() @@ -37,9 +39,10 @@ export class ETANotificationScheduler { * An object of device ID arrays to deliver notifications to. * The key should be a combination of the shuttle ID and * stop ID, which can be generated using `TupleKey`. + * The value is a dictionary of the device ID to the stored seconds threshold. * @private */ - private deviceIdsToDeliverTo: { [key: string]: Set } = {} + private deviceIdsToDeliverTo: { [key: string]: DeviceIdSecondsThresholdAssociation } = {} private async sendEtaNotificationImmediately(notificationData: ScheduledNotificationData): Promise { const { deviceId, shuttleId, stopId } = notificationData; @@ -77,7 +80,7 @@ export class ETANotificationScheduler { } const deviceIdsToRemove = new Set(); - for (let deviceId of this.deviceIdsToDeliverTo[tuple.toString()].values()) { + for (let deviceId of Object.keys(this.deviceIdsToDeliverTo[tuple.toString()])) { const deliveredSuccessfully = await this.sendEtaNotificationImmediatelyIfSecondsRemainingBelowThreshold(deviceId, eta); if (deliveredSuccessfully) { deviceIdsToRemove.add(deviceId); @@ -85,12 +88,12 @@ export class ETANotificationScheduler { } deviceIdsToRemove.forEach((deviceId) => { - this.deviceIdsToDeliverTo[tuple.toString()].delete(deviceId); + delete this.deviceIdsToDeliverTo[tuple.toString()][deviceId] }); } private async sendEtaNotificationImmediatelyIfSecondsRemainingBelowThreshold(deviceId: string, eta: IEta) { - if (eta.secondsRemaining > this.secondsThresholdForNotificationToFire) { + if (eta.secondsRemaining > this.defaultSecondsThresholdForNotificationToFire) { return false; } @@ -106,13 +109,20 @@ export class ETANotificationScheduler { * @param deviceId The device ID to send the notification to. * @param shuttleId Shuttle ID of ETA object to check. * @param stopId Stop ID of ETA object to check. + * @param secondsThreshold Value which specifies the ETA of the shuttle for when + * the notification should fire. */ - public async scheduleNotification({ deviceId, shuttleId, stopId }: ScheduledNotificationData) { + public async scheduleNotification({ deviceId, shuttleId, stopId, secondsThreshold }: ScheduledNotificationData) { const tuple = new TupleKey(shuttleId, stopId); if (this.deviceIdsToDeliverTo[tuple.toString()] === undefined) { - this.deviceIdsToDeliverTo[tuple.toString()] = new Set(); + this.deviceIdsToDeliverTo[tuple.toString()] = {}; + } + + if (secondsThreshold !== undefined) { + this.deviceIdsToDeliverTo[tuple.toString()][deviceId] = secondsThreshold; + } else { + this.deviceIdsToDeliverTo[tuple.toString()][deviceId] = this.defaultSecondsThresholdForNotificationToFire; } - this.deviceIdsToDeliverTo[tuple.toString()].add(deviceId); this.repository.unsubscribeFromEtaUpdates(this.etaSubscriberCallback); this.repository.subscribeToEtaUpdates(this.etaSubscriberCallback); @@ -128,12 +138,12 @@ export class ETANotificationScheduler { const tupleKey = new TupleKey(shuttleId, stopId); if ( this.deviceIdsToDeliverTo[tupleKey.toString()] === undefined - || !this.deviceIdsToDeliverTo[tupleKey.toString()].has(deviceId) + || !(deviceId in this.deviceIdsToDeliverTo[tupleKey.toString()]) ) { return; } - this.deviceIdsToDeliverTo[tupleKey.toString()].delete(deviceId); + delete this.deviceIdsToDeliverTo[tupleKey.toString()][deviceId]; } /** @@ -147,7 +157,7 @@ export class ETANotificationScheduler { if (this.deviceIdsToDeliverTo[tuple.toString()] === undefined) { return false; } - return this.deviceIdsToDeliverTo[tuple.toString()].has(deviceId); + return deviceId in this.deviceIdsToDeliverTo[tuple.toString()]; } /** @@ -158,7 +168,7 @@ export class ETANotificationScheduler { const scheduledNotifications: ScheduledNotificationData[] = []; for (const key of Object.keys(this.deviceIdsToDeliverTo)) { - if (this.deviceIdsToDeliverTo[key].has(deviceId)) { + if (deviceId in this.deviceIdsToDeliverTo[key]) { const tupleKey = TupleKey.fromExistingStringKey(key); const shuttleId = tupleKey.tuple[0] const stopId = tupleKey.tuple[1];