NotificationLatch/src/notification/repository.js

130 lines
3.1 KiB
JavaScript

const fs = require('fs').promises;
const crypto = require('crypto');
class NotificationRepository
{
constructor(logger, dateTimeProvider, asyncFs, config)
{
this.logger = logger;
this.dateTimeProvider = dateTimeProvider;
this.asyncFs = asyncFs;
this.filename = config.dataFilename;
this.salt = config.salt;
this.notifications = null;
}
async init()
{
if (this.notifications !== null)
throw new Error('Repository is already initialized');
this.notifications = {};
if (!(await this.asyncFs.exists(this.filename)))
return;
const contents = await fs.readFile(this.filename, 'utf8');
this.notifications = JSON.parse(contents.toString());
}
// Returns the notification token if it should be sent out or null if the notification is latched
async storeNotification(id, title)
{
this._checkInitialized();
const now = this.dateTimeProvider.unixTimestamp();
const token = this._getNotificationToken(id);
if (!this.notifications.hasOwnProperty(token))
{
this.logger.info(`New notification with id '${id}' and token '${token}', send permitted`);
this.notifications[token] = {
id: id,
title: title,
latched: true,
latchTime: now,
resetTime: null,
reminders: true,
remindTime: null
};
await this._flush();
return token;
}
const notification = this.notifications[token];
if (notification.latched)
{
this.logger.info(`Notification with id ${id} and token '${token}' is already latched, send blocked`);
return null;
}
this.logger.info(`Latching notification with id ${id} and token '${token}', send permitted`);
notification.latched = true;
notification.latchTime = now;
await this._flush();
return token;
}
async resetNotification(token)
{
this._checkInitialized();
const now = this.dateTimeProvider.unixTimestamp();
if (!this.notifications.hasOwnProperty(token))
{
this.logger.info(`Notification token '${token}' does not exist, reset unneccesary`);
return;
}
const notification = this.notifications[token];
if (!notification.latched)
{
this.logger.info(`Notification with id '${notification.id}' and token '${token}' is not latched, reset unneccesary`);
return;
}
this.logger.info(`Resetting notification with id '${notification.id}' and token '${token}'`);
notification.latched = false;
notification.resetTime = now;
notification.reminders = true;
notification.remindTime = null;
await this._flush();
}
_getNotificationToken(id)
{
const hasher = crypto.createHmac("sha256", this.salt);
return hasher.update(id).digest("hex");
}
async _flush()
{
const contents = JSON.stringify(this.notifications, null, 2);
await fs.writeFile(this.filename, contents, 'utf8');
}
_checkInitialized()
{
if (this.notifications === null)
throw new Error('Repository not initialized, call init() first');
}
}
module.exports = NotificationRepository;