130 lines
3.1 KiB
JavaScript
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; |