From 26d9cc56d30c6a0a3c75cd427f04c71a67fb592a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 28 Oct 2013 15:10:10 -0400 Subject: [PATCH] added cronjob for notifications --- app.js | 5 +- package.json | 3 +- src/notifications.js | 108 ++++++++++++++++++++++++++++++++----------- 3 files changed, 88 insertions(+), 28 deletions(-) diff --git a/app.js b/app.js index 05ba01c22f..075a029fbe 100644 --- a/app.js +++ b/app.js @@ -87,7 +87,8 @@ SocketIO = require('socket.io').listen(global.server, { log: false, transports: ['websocket', 'xhr-polling', 'jsonp-polling', 'flashsocket']}), websockets = require('./src/websockets.js'), posts = require('./src/posts.js'), - plugins = require('./src/plugins'); // Don't remove this - plugins initializes itself + plugins = require('./src/plugins'), // Don't remove this - plugins initializes itself + Notifications = require('./src/notifications'); websockets.init(SocketIO); @@ -106,6 +107,8 @@ ]); templates.ready(webserver.init); + + Notifications.init(); }); } else if (nconf.get('upgrade')) { diff --git a/package.json b/package.json index 89d3e9b69c..4890e1acd5 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,8 @@ "nodebb-plugin-mentions": "~0.1.13", "nodebb-plugin-markdown": "~0.1.7", "nodebb-theme-vanilla": "designcreateplay/nodebb-theme-vanilla", - "nodebb-theme-cerulean": "0.0.3" + "nodebb-theme-cerulean": "0.0.3", + "cron": "~1.0.1" }, "optionalDependencies": { "hiredis": "~0.1.15" diff --git a/src/notifications.js b/src/notifications.js index 2cf1aa37ab..f6d4f03e06 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -1,18 +1,29 @@ var RDB = require('./redis.js'), async = require('async'), utils = require('../public/src/utils.js'), + winston = require('winston'), + cron = require('cron').CronJob, notifications = { + init: function() { + if (process.env.NODE_ENV === 'development') { + winston.info('[notifications.init] Registering jobs.'); + } + + new cron('0 0 * * *', notifications.prune, null, true); + }, get: function(nid, uid, callback) { RDB.multi() .hmget('notifications:' + nid, 'text', 'score', 'path', 'datetime', 'uniqueId') .zrank('uid:' + uid + ':notifications:read', nid) .exists('notifications:' + nid) .exec(function(err, results) { - var notification = results[0] + var notification = results[0], readIdx = results[1]; - if (!results[2]) return callback(null); + if (!results[2]) { + return callback(null); + } callback({ nid: nid, @@ -40,7 +51,9 @@ var RDB = require('./redis.js'), datetime: Date.now(), uniqueId: uniqueId || utils.generateUUID() }, function(err, status) { - if (!err) callback(nid); + if (!err) { + callback(nid); + } }); }); }, @@ -65,12 +78,14 @@ var RDB = require('./redis.js'), notifications.get(nid, null, function(notif_data) { for (x = 0; x < numUids; x++) { - if (parseInt(uids[x]) > 0) { + if (parseInt(uids[x], 10) > 0) { (function(uid) { notifications.remove_by_uniqueId(notif_data.uniqueId, uid, function() { RDB.zadd('uid:' + uid + ':notifications:unread', notif_data.datetime, nid); global.io.sockets.in('uid_' + uid).emit('event:new_notification'); - if (callback) callback(true); + if (callback) { + callback(true); + } }); })(uids[x]); } @@ -84,13 +99,18 @@ var RDB = require('./redis.js'), if (nids && nids.length > 0) { async.each(nids, function(nid, next) { notifications.get(nid, uid, function(nid_info) { - if (nid_info.uniqueId === uniqueId) RDB.zrem('uid:' + uid + ':notifications:unread', nid); + if (nid_info.uniqueId === uniqueId) { + RDB.zrem('uid:' + uid + ':notifications:unread', nid); + } + next(); }); }, function(err) { next(); }); - } else next(); + } else { + next(); + } }); }, function(next) { @@ -98,17 +118,24 @@ var RDB = require('./redis.js'), if (nids && nids.length > 0) { async.each(nids, function(nid, next) { notifications.get(nid, uid, function(nid_info) { - if (nid_info.uniqueId === uniqueId) RDB.zrem('uid:' + uid + ':notifications:read', nid); + if (nid_info.uniqueId === uniqueId) { + RDB.zrem('uid:' + uid + ':notifications:read', nid); + } + next(); }); }, function(err) { next(); }); - } else next(); + } else { + next(); + } }); } ], function(err) { - if (!err) callback(true); + if (!err) { + callback(true); + } }); }, mark_read: function(nid, uid, callback) { @@ -116,35 +143,55 @@ var RDB = require('./redis.js'), notifications.get(nid, uid, function(notif_data) { RDB.zrem('uid:' + uid + ':notifications:unread', nid); RDB.zadd('uid:' + uid + ':notifications:read', notif_data.datetime, nid); - if (callback) callback(); + if (callback) { + callback(); + } }); } }, mark_read_multiple: function(nids, uid, callback) { - if (!Array.isArray(nids) && parseInt(nids, 10) > 0) nids = [nids]; + if (!Array.isArray(nids) && parseInt(nids, 10) > 0) { + nids = [nids]; + } async.each(nids, function(nid, next) { notifications.mark_read(nid, uid, function(err) { - if (!err) next(null); + if (!err) { + next(null); + } }); }, function(err) { - if (callback) callback(err); + if (callback) { + callback(err); + } }); }, mark_all_read: function(uid, callback) { RDB.zrange('uid:' + uid + ':notifications:unread', 0, 10, function(err, nids) { - if (err) return callback(err); + if (err) { + return callback(err); + } if (nids.length > 0) { notifications.mark_read_multiple(nids, uid, function(err) { callback(err); }); - } else callback(); + } else { + callback(); + } }); }, - prune: function(cutoff, callback) { - var today = new Date(); - if (!cutoff) cutoff = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 7); + prune: function(cutoff) { + if (process.env.NODE_ENV === 'development') { + winston.info('[notifications.prune] Removing expired notifications from the database.'); + } + + var today = new Date(), + numPruned = 0; + + if (!cutoff) { + cutoff = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 7); + } var cutoffTime = cutoff.getTime(); @@ -156,8 +203,11 @@ var RDB = require('./redis.js'), RDB.smembers('notifications', function(err, nids) { async.filter(nids, function(nid, next) { RDB.hget('notifications:' + nid, 'datetime', function(err, datetime) { - if (parseInt(datetime, 10) < cutoffTime) next(true); - else next(false); + if (parseInt(datetime, 10) < cutoffTime) { + next(true); + } else { + next(false); + } }); }, function(expiredNids) { next(null, expiredNids); @@ -179,17 +229,22 @@ var RDB = require('./redis.js'), multi.exec(function(err, results) { // If the notification is not present in any inbox, delete it altogether var expired = results.every(function(present) { - if (present === null) return true; + if (present === null) { + return true; + } }); if (expired) { notifications.destroy(nid); + numPruned++; } next(); }); }, function(err) { - + if (process.env.NODE_ENV === 'development') { + winston.info('[notifications.prune] Notification pruning completed. ' + numPruned + ' expired notification' + (numPruned !== 1 ? 's' : '') + ' removed.'); + } }); } else { if (process.env.NODE_ENV === 'development') { @@ -197,16 +252,17 @@ var RDB = require('./redis.js'), winston.error(err.stack); } } - }) + }); } - } + }; module.exports = { + init: notifications.init, get: notifications.get, create: notifications.create, push: notifications.push, mark_read: notifications.mark_read_multiple, mark_all_read: notifications.mark_all_read, prune: notifications.prune -} \ No newline at end of file +};