NotificationLatch/src/notification/facade.js

156 lines
4.1 KiB
JavaScript

class NotificationFacade
{
static create = container => new this(container.Logger, container.DateTimeProvider, container.TransportProvider,
container.SubjectParser, container.NotificationRepository, container.Config);
constructor(logger, dateTimeProvider, transportProvider, subjectParser, notificationRepository, config)
{
this.logger = logger;
this.dateTimeProvider = dateTimeProvider;
this.transportProvider = transportProvider;
this.subjectParser = subjectParser;
this.notificationRepository = notificationRepository;
this.contacts = config.contacts.filter(contact =>
{
if (transportProvider.byType(contact.type) === null)
{
logger.error(`Unknown transport type '${contact.type}' for contact '${contact.description}', skipping contact`)
return false;
}
return true;
});
this.publicUrl = config.publicUrl;
this.reminders = config.reminders;
}
async postNotification(subject, message, priority)
{
var parsedSubject = this.subjectParser.parse(subject);
const token = await this.notificationRepository.storeNotification(parsedSubject.id, parsedSubject.title);
if (token === null)
return;
this._sendNotification({
id: parsedSubject.id,
token: token,
title: parsedSubject.title,
message: message,
priority: Number(priority) || 0,
sound: parsedSubject.sound,
timestamp: this.dateTimeProvider.unixTimestamp(),
url: new URL('/#/n/' + token, this.publicUrl).href
});
}
async resetNotification(token)
{
await this.notificationRepository.resetNotification(token);
}
getLatchedNotifications(token)
{
const notifications = this.notificationRepository.getLatchedNotifications(token);
return notifications !== null
? {
reminders: {
enabled: this.reminders.enabled,
interval: this.reminders.interval
},
notifications: notifications
}
: null;
}
async setReminders(token, enabled)
{
await this.notificationRepository.setReminders(token, enabled);
}
async sendReminders(interval, title, message, sound)
{
await this.notificationRepository.processReminderNotifications(interval, this._sendReminder.bind(this, title, message, sound));
}
_sendNotification(notification)
{
this.contacts.forEach(contact =>
{
const transport = this.transportProvider.byType(contact.type);
this._retryableSend(transport, contact, notification);
});
}
_sendReminder(title, message, sound, token, notification)
{
const reminderNotification = {
id: notification.id,
token: token,
title: title,
message: message.replace('{title}', notification.title),
priority: 0,
timestamp: this.dateTimeProvider.unixTimestamp(),
url: new URL('/#/n/' + token, this.publicUrl).href
};
if (sound)
reminderNotification.sound = sound;
this._sendNotification(reminderNotification);
}
_delay(ms)
{
return new Promise(resolve => setTimeout(resolve, ms));
}
async _retryableSend(transport, contact, notification)
{
let attempt = 1;
const retryInterval = contact.retryIntervalSeconds || 0;
const maxAttempts = contact.maxAttempts || 1;
while (true)
{
try
{
this.logger.info(`Sending notification '${notification.id}' with token '${notification.token}' to '${contact.description}' (attempt ${attempt})`);
await transport.send(this.logger, contact, notification);
this.logger.info(`Notification '${notification.id}' succesfully sent to '${contact.description}'`);
return;
}
catch (err)
{
if (attempt >= maxAttempts)
{
this.logger.info(`Error while sending notification '${notification.id}' to '${contact.description}', max attempts reached: ${err}`);
return;
}
this.logger.info(`Error while sending notification '${notification.id}' to '${contact.description}', retrying in ${retryInterval} seconds: ${err}`);
await this._delay(retryInterval * 1000);
attempt++;
}
}
}
}
module.exports = NotificationFacade;