Skip to content

Commit

Permalink
clean code and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
kernoeb committed Sep 20, 2023
1 parent 3043135 commit 5b473ad
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 100 deletions.
103 changes: 4 additions & 99 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@ logger.info('Version : ' + packageJson.version)
logger.info('MongoDB Url : ' + (process.env.MONGODB_URL || 'localhost:27017'))
logger.info('BREE : ' + (process.env.NO_BREE ? 'disabled' : 'enabled'))

const retry = async (fn, n = 1) => {
try {
await fn()
} catch (e) {
if (n === 1) throw e
await retry(fn, n - 1)
}
}

// Connect to MongoDB first
if (process.env.NODE_ENV !== 'test') {
mongoose.connect(`mongodb://${process.env.MONGODB_URL || 'localhost:27017'}/planningsup`).then(() => {
Expand All @@ -47,102 +38,16 @@ if (process.env.NODE_ENV !== 'test') {
try {
const { Agenda } = require('@hokify/agenda')
const agenda = new Agenda({ name: 'notifications' })
const { sendNotification } = require('./util/notifications')
const { cleanName, cleanLocation, cleanDescription } = require('./util/utils')

// Remove old jobs
await mongoose.connection.db.collection('notifications').deleteMany({
nextRunAt: { $lt: new Date() }
})
await mongoose.connection.db.collection('notifications').deleteMany({ nextRunAt: { $lt: new Date() } })

await agenda.mongo(mongoose.connection.db, 'notifications')

agenda.define('send notification', async () => {
try {
const { Subscription } = require('./models/subscriptions')
const { Planning } = require('./models/planning')

const updateSubscription = async (subscription, nextNotification) => {
try {
console.log('Updating subscription', nextNotification.id)
await Subscription.updateOne(
{ endpoint: subscription.endpoint },
{ $push: { nextNotifications: nextNotification } }
)
} catch (e) {
console.error('Error while updating nextNotifications', e)
}
}

const removeOldNotifications = async (subscription) => {
const nbNotifications = subscription.nextNotifications.length
subscription.nextNotifications = subscription.nextNotifications.filter(n => n.date > new Date())
if (nbNotifications !== subscription.nextNotifications.length) {
await Subscription.updateOne({ endpoint: subscription.endpoint }, { $set: { nextNotifications: subscription.nextNotifications } })
}
}

// Get distinct of subscriptions plannings
const subscriptions = await Subscription.distinct('plannings')
logger.info('[Subscriptions] Number of active plannings', subscriptions.length)

if (subscriptions.length) {
for (const planning of subscriptions) {
const p = await Planning.findOne({ fullId: planning })
if (p.backup) {
// find dtstart nearest to now
const now = new Date()
let nextEvent = null
for (const event of p.backup) {
const dtstart = new Date(event.dtstart.value)
if (dtstart > now) {
if (!nextEvent) nextEvent = event
else if (dtstart < new Date(nextEvent.dtstart.value)) nextEvent = event
}
}

if (nextEvent) {
const now = new Date()
const dtstart = new Date(nextEvent.dtstart.value)

const diff = dtstart - now
const tenMinutes = 1000 * 60 * 10
// const thirtyMinutes = 1000 * 60 * 30
// const twelveHours = 1000 * 60 * 60 * 12

if (diff <= tenMinutes) {
// if (diff <= twelveHours) {
console.log('Event in less than 10 minutes', p.fullId)
// console.log('Event in less than 12 hours', p.fullId)
const payload = JSON.stringify({
title: `Cours dans ${Math.round(diff / 1000 / 60)} minutes`,
body: `- ${cleanName(nextEvent.summary.value)}\n- ${cleanLocation(nextEvent.location.value)}\n- ${cleanDescription(nextEvent.description.value)}`,
icon: '/favicon.ico'
})
const date = new Date(dtstart)

const id = `${p.fullId}::${date.getFullYear()}:${date.getMonth() + 1}:${date.getDate()}:${date.getHours()}:${date.getMinutes()}`

for await (const subscription of Subscription.find({ plannings: p.fullId })) {
await removeOldNotifications(subscription).catch(e => console.error('Error while removing old notifications', e))

if (subscription.nextNotifications.some(n => n.id === id)) {
console.log('Already sent notification for this event', id)
continue
}

await retry(async () => await sendNotification(subscription, payload, true), 2) // Retry 2 times
.then(() => updateSubscription(subscription, { id, date, status: 'sent' }))
.catch(() => updateSubscription(subscription, { id, date, status: 'error' }))
}
}
}
}
}
}
} catch (e) {
logger.error('Error while sending notification', e)
}
logger.info('[Subscriptions] Sending notifications...')
await require('./util/notifications').notificationsLoop()
logger.info('[Subscriptions] Notifications sent !')
})

await agenda.every('1 minute', 'send notification', {}, { skipImmediate: false })
Expand Down
99 changes: 98 additions & 1 deletion server/util/notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,24 @@ if (!process.env.VAPID_SUBJECT && process.env.NODE_ENV !== 'production') {

const webpush = require('web-push')
const { Subscription } = require('../models/subscriptions')
const { Planning } = require('../models/planning')
const { cleanName, cleanLocation, cleanDescription } = require('../util/utils')
const logger = require('../util/signale')

const publicVapidKey = process.env.PUBLIC_VAPID_KEY
const privateVapidKey = process.env.PRIVATE_VAPID_KEY

webpush.setVapidDetails(process.env.VAPID_SUBJECT, publicVapidKey, privateVapidKey)

const retry = async (fn, n = 1) => {
try {
await fn()
} catch (e) {
if (n === 1) throw e
await retry(fn, n - 1)
}
}

const sendNotification = async (subscription, payload, throwErrors = false) => {
try {
await webpush.sendNotification(subscription, payload)
Expand All @@ -27,4 +39,89 @@ const sendNotification = async (subscription, payload, throwErrors = false) => {
}
}

exports.sendNotification = sendNotification
module.exports.sendNotification = sendNotification

const updateSubscription = async (subscription, nextNotification) => {
try {
console.log('Updating subscription', nextNotification.id)
await Subscription.updateOne(
{ endpoint: subscription.endpoint },
{ $push: { nextNotifications: nextNotification } }
)
} catch (e) {
console.error('Error while updating nextNotifications', e)
}
}

const removeOldNotifications = async (subscription) => {
const nbNotifications = subscription.nextNotifications.length
subscription.nextNotifications = subscription.nextNotifications.filter(n => n.date > new Date())
if (nbNotifications !== subscription.nextNotifications.length) {
await Subscription.updateOne({ endpoint: subscription.endpoint }, { $set: { nextNotifications: subscription.nextNotifications } })
}
}

module.exports.notificationsLoop = async () => {
try {
// Get distinct of subscriptions plannings
const subscriptions = await Subscription.distinct('plannings')
logger.info('[Subscriptions] Number of active plannings', subscriptions.length)

if (subscriptions.length) {
for (const planning of subscriptions) {
const p = await Planning.findOne({ fullId: planning })
if (p.backup) {
// find dtstart nearest to now
const now = new Date()
let nextEvent = null
for (const event of p.backup) {
const dtstart = new Date(event.dtstart.value)
if (dtstart > now) {
if (!nextEvent) nextEvent = event
else if (dtstart < new Date(nextEvent.dtstart.value)) nextEvent = event
}
}

if (nextEvent) {
const now = new Date()
const dtstart = new Date(nextEvent.dtstart.value)

const diff = dtstart - now
const tenMinutes = 1000 * 60 * 10
// const thirtyMinutes = 1000 * 60 * 30
// const twelveHours = 1000 * 60 * 60 * 12

if (diff <= tenMinutes) {
// if (diff <= twelveHours) {
console.log('Event in less than 10 minutes', p.fullId)
// console.log('Event in less than 12 hours', p.fullId)
const payload = JSON.stringify({
title: `Cours dans ${Math.round(diff / 1000 / 60)} minutes`,
body: `- ${cleanName(nextEvent.summary.value)}\n- ${cleanLocation(nextEvent.location.value)}\n- ${cleanDescription(nextEvent.description.value)}`,
icon: '/favicon.ico'
})
const date = new Date(dtstart)

const id = `${p.fullId}::${date.getFullYear()}:${date.getMonth() + 1}:${date.getDate()}:${date.getHours()}:${date.getMinutes()}`

for await (const subscription of Subscription.find({ plannings: p.fullId })) {
await removeOldNotifications(subscription).catch(e => console.error('Error while removing old notifications', e))

if (subscription.nextNotifications.some(n => n.id === id)) {
console.log('Already sent notification for this event', id)
continue
}

await retry(async () => await sendNotification(subscription, payload, true), 2) // Retry 2 times
.then(() => updateSubscription(subscription, { id, date, status: 'sent' }))
.catch(() => updateSubscription(subscription, { id, date, status: 'error' }))
}
}
}
}
}
}
} catch (e) {
logger.error('Error while sending notification', e)
}
}

0 comments on commit 5b473ad

Please sign in to comment.