diff --git a/src/notifications/senders/AppleNotificationSender.ts b/src/notifications/senders/AppleNotificationSender.ts index c4a551d..002da8f 100644 --- a/src/notifications/senders/AppleNotificationSender.ts +++ b/src/notifications/senders/AppleNotificationSender.ts @@ -1,4 +1,5 @@ import jwt from "jsonwebtoken"; +import http2 from "http2"; interface APNsUrl { fullUrl: string; @@ -6,6 +7,11 @@ interface APNsUrl { host: string; } +interface NotificationAlertArguments { + title: string; + body: string; +} + class AppleNotificationSender { private apnsToken: string | undefined = undefined; private _lastRefreshedTimeMs: number | undefined = undefined; @@ -45,8 +51,56 @@ class AppleNotificationSender { this._lastRefreshedTimeMs = nowMs; } - public sendNotificationImmediately(notification: any) { - // TODO Send the notification + /** + * Send a notification immediately. + * @param deviceId + * @param notificationAlertArguments + * + * @return Boolean promise indicating whether the + * notification was sent successfully. + */ + public async sendNotificationImmediately(deviceId: string, notificationAlertArguments: NotificationAlertArguments) { + const bundleId = process.env.APNS_BUNDLE_ID; + if (typeof bundleId !== "string") { + throw new Error("APNS_BUNDLE_ID environment variable is not set correctly"); + } + + const { path, host } = AppleNotificationSender.getAPNsFullUrlToUse(deviceId); + + const headers = { + ':method': 'POST', + ':path': path, + 'authorization': `bearer ${this.apnsToken}`, + "apns-push-type": "alert", + "apns-expiration": "0", + "apns-priority": "10", + "apns-topic": bundleId, + }; + try { + const client = http2.connect(host); + const req = client.request(headers); + req.setEncoding('utf8'); + + await new Promise((resolve, reject) => { + req.on('response', (headers, flags) => { + if (headers[":status"] !== 200) { + reject(`APNs request failed with status ${headers[":status"]}`); + } + resolve(); + }); + + req.write(JSON.stringify({ + aps: { + alert: notificationAlertArguments, + } + })); + req.end(); + }); + return true; + } catch(e) { + console.error(e); + return false; + } } public static getAPNsFullUrlToUse(deviceId: string): APNsUrl {