mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-17 16:00:32 +00:00
98 lines
3.9 KiB
TypeScript
98 lines
3.9 KiB
TypeScript
import { ShuttleGetterRepository } from "../../repositories/ShuttleGetterRepository";
|
|
import { IEta } from "../../entities/ShuttleRepositoryEntities";
|
|
import { AppleNotificationSender, NotificationAlertArguments } from "../senders/AppleNotificationSender";
|
|
import {
|
|
NotificationRepository,
|
|
ScheduledNotification
|
|
} from "../../repositories/NotificationRepository";
|
|
import { InMemoryNotificationRepository } from "../../repositories/InMemoryNotificationRepository";
|
|
|
|
export class ETANotificationScheduler {
|
|
public static readonly defaultSecondsThresholdForNotificationToFire = 180;
|
|
|
|
constructor(
|
|
private shuttleRepository: ShuttleGetterRepository,
|
|
private notificationRepository: NotificationRepository = new InMemoryNotificationRepository(),
|
|
private appleNotificationSender = new AppleNotificationSender(),
|
|
private interchangeSystemId: string,
|
|
) {
|
|
this.etaSubscriberCallback = this.etaSubscriberCallback.bind(this);
|
|
this.sendEtaNotificationImmediately = this.sendEtaNotificationImmediately.bind(this);
|
|
this.sendEtaNotificationImmediatelyIfSecondsRemainingBelowThreshold = this.sendEtaNotificationImmediatelyIfSecondsRemainingBelowThreshold.bind(this);
|
|
}
|
|
|
|
private async sendEtaNotificationImmediately(notificationData: ScheduledNotification): Promise<boolean> {
|
|
const { deviceId, shuttleId, stopId } = notificationData;
|
|
|
|
const shuttle = await this.shuttleRepository.getShuttleById(shuttleId);
|
|
const stop = await this.shuttleRepository.getStopById(stopId);
|
|
const eta = await this.shuttleRepository.getEtaForShuttleAndStopId(shuttleId, stopId);
|
|
if (!shuttle) {
|
|
console.warn(`Notification ${notificationData} fell through; no associated shuttle`);
|
|
return false;
|
|
}
|
|
if (!stop) {
|
|
console.warn(`Notification ${notificationData} fell through; no associated stop`);
|
|
return false;
|
|
}
|
|
|
|
// Notification may not be sent if ETA is unavailable at the moment;
|
|
// this is fine because it will be sent again when ETA becomes available
|
|
if (!eta) {
|
|
console.warn(`Notification ${notificationData} fell through; no associated ETA`);
|
|
return false;
|
|
}
|
|
|
|
const notificationAlertArguments: NotificationAlertArguments = {
|
|
title: "Shuttle is arriving",
|
|
body: `Shuttle is approaching ${stop.name} in ${Math.ceil(eta.secondsRemaining / 60)} minutes.`,
|
|
customKeys: {
|
|
shuttleId,
|
|
stopId,
|
|
systemId: this.interchangeSystemId,
|
|
},
|
|
}
|
|
return this.appleNotificationSender.sendNotificationImmediately(deviceId, notificationAlertArguments);
|
|
}
|
|
|
|
private async etaSubscriberCallback(eta: IEta) {
|
|
const deviceIdsToRemove = new Set<string>();
|
|
const notifications = await this.notificationRepository.getAllNotificationsForShuttleAndStopId(
|
|
eta.shuttleId,
|
|
eta.stopId
|
|
)
|
|
|
|
for (let notification of notifications) {
|
|
const deliveredSuccessfully = await this.sendEtaNotificationImmediatelyIfSecondsRemainingBelowThreshold(notification, eta.secondsRemaining);
|
|
if (deliveredSuccessfully) {
|
|
deviceIdsToRemove.add(notification.deviceId);
|
|
}
|
|
}
|
|
|
|
deviceIdsToRemove.forEach((deviceId) => {
|
|
this.notificationRepository.deleteNotificationIfExists({
|
|
shuttleId: eta.shuttleId,
|
|
stopId: eta.stopId,
|
|
deviceId,
|
|
})
|
|
});
|
|
}
|
|
|
|
private async sendEtaNotificationImmediatelyIfSecondsRemainingBelowThreshold(notificationObject: ScheduledNotification, etaSecondsRemaining: number) {
|
|
if (etaSecondsRemaining > notificationObject.secondsThreshold) {
|
|
return false;
|
|
}
|
|
|
|
return await this.sendEtaNotificationImmediately(notificationObject);
|
|
}
|
|
|
|
// The following is a workaround for the constructor being called twice
|
|
public startListeningForUpdates() {
|
|
this.shuttleRepository.subscribeToEtaUpdates(this.etaSubscriberCallback);
|
|
}
|
|
|
|
public stopListeningForUpdates() {
|
|
this.shuttleRepository.subscribeToEtaUpdates(this.etaSubscriberCallback);
|
|
}
|
|
}
|