Add history collection

This commit is contained in:
John Furrow
2016-01-30 12:45:46 -08:00
parent ea95765ed4
commit b17b8d317d
7 changed files with 242 additions and 17 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
node_modules
npm-debug.log
server/db/users.js
server/db/history

View File

@@ -28,6 +28,7 @@
"keymirror": "^0.1.1",
"lodash": "^3.10.1",
"morgan": "~1.5.1",
"nedb": "^1.7.2",
"object-assign": "^2.0.0",
"passport": "^0.3.2",
"passport-http": "^0.3.0",

141
server/models/HistoryEra.js Normal file
View File

@@ -0,0 +1,141 @@
'use strict';
let Datastore = require('nedb');
let stringUtil = require('./util/stringUtil');
const FILE_PATH = './server/db/history/';
const MAX_CLEANUP_INTERVAL = 1000 * 60 * 60; // 1 hour
const MAX_NEXT_ERA_UPDATE_INTERVAL = 1000 * 60 * 60 * 12; // 12 hours
const REQUIRED_FIELDS = ['interval', 'maxTime', 'name'];
class HistoryEra {
constructor(opts) {
opts = opts || {};
this.ready = false;
if (!this.hasRequiredFields(opts)) {
return;
}
this.data = [];
this.opts = opts;
this.startedAt = Date.now();
this.db = this.loadDatabase(this.opts.name);
this.removeOutdatedData(this.db);
let cleanupInterval = this.opts.maxTime;
let nextEraUpdateInterval = this.opts.nextEraUpdateInterval;
if (cleanupInterval === 0 || cleanupInterval > MAX_CLEANUP_INTERVAL) {
cleanupInterval = MAX_CLEANUP_INTERVAL;
}
if (nextEraUpdateInterval && nextEraUpdateInterval > MAX_NEXT_ERA_UPDATE_INTERVAL) {
nextEraUpdateInterval = MAX_NEXT_ERA_UPDATE_INTERVAL;
}
this.startAutoCleanup(cleanupInterval, this.db);
if (nextEraUpdateInterval) {
this.startNextEraUpdate(nextEraUpdateInterval, this.db);
}
}
addData(data) {
if (!this.ready) {
console.warn('database is not ready');
return;
}
console.log(`insert data in ${this.opts.name}`);
this.db.insert({
ts: Date.now(),
up: data.upload,
dn: data.download
});
}
cleanup(db) {
this.removeOutdatedData(db);
db.persistence.compactDatafile();
}
hasRequiredFields(opts) {
let requirementsMet = true;
REQUIRED_FIELDS.forEach(function (field) {
if (opts[field] == null) {
console.warn(`historyEra requires ${field}`);
requirementsMet = false;
}
});
return requirementsMet;
}
loadDatabase(dbName) {
let db = new Datastore({
autoload: true,
filename: `${FILE_PATH}${dbName}.db`
});
this.ready = true;
return db;
}
removeOutdatedData(db) {
if (this.opts.maxTime > 0) {
let minTimestamp = Date.now() - this.opts.maxTime;
db.remove({ts: {$lt: minTimestamp}}, {multi: true}, (err, numRemoved) => {
console.log(`removed ${numRemoved} entries from ${this.opts.name}`)
});
}
}
startAutoCleanup(interval, db) {
this.autoCleanupInterval = setInterval(
this.cleanup.bind(this, db), interval
);
}
startNextEraUpdate(interval, currentDB, nextDB) {
this.nextEraUpdateInterval = setInterval(
this.updateNextEra.bind(this, currentDB, nextDB), interval
);
}
stopAutoCleanup() {
clearInterval(this.autoCleanupInterval);
this.autoCleanupInterval = null;
}
stopNextEraUpdate(interval, db) {
clearInterval(this.nextEraUpdateInterval);
this.nextEraUpdateInterval = null;
}
updateNextEra(currentDB, nextDB) {
let minTimestamp = Date.now() - this.opts.nextEraUpdateInterval;
currentDB.find({ts: {$gte: minTimestamp}}, (err, docs) => {
let downTotal = 0;
let upTotal = 0;
docs.forEach(function (doc) {
downTotal += parseInt(doc.dn);
upTotal += parseInt(doc.up);
});
this.opts.nextEra.addData({
download: (downTotal / docs.length).toFixed(1),
upload: (upTotal / docs.length).toFixed(1)
});
});
}
}
module.exports = HistoryEra;

View File

@@ -241,25 +241,22 @@ var client = {
},
getTransferStats: function(callback) {
try {
var request = clientUtil.createMulticallRequest(
clientUtil.defaults.clientPropertyMethods
);
var request = clientUtil.createMulticallRequest(
clientUtil.defaults.clientPropertyMethods
);
request = [request];
request = [request];
rTorrent.get('system.multicall', request)
.then(function(data) {
callback(null, clientUtil.mapClientProps(
clientUtil.defaults.clientProperties,
data
));
}, function(error) {
callback(error, null);
});
} catch(err) {
console.log(err);
}
rTorrent.get('system.multicall', request)
.then(function(data) {
var parsedData = clientUtil.mapClientProps(
clientUtil.defaults.clientProperties,
data
);
callback(null, parsedData);
}, function(error) {
callback(error, null);
});
}
};

View File

@@ -0,0 +1,74 @@
'use strict';
var Datastore = require('nedb');
var client = require('./client');
var HistoryEra = require('./HistoryEra');
let pollInterval = null;
let yearSnapshot = new HistoryEra({
interval: 1000 * 60 * 60 * 24 * 7, // 7 days
name: 'yearSnapshot',
maxTime: 0 // 365 days
});
let monthSnapshot = new HistoryEra({
interval: 1000 * 60 * 60 * 12, // 12 hours
maxTime: 1000 * 60 * 60 * 24 * 365, // 365 days
name: 'monthSnapshot',
nextEraUpdateInterval: 1000 * 60 * 60 * 24 * 7, // 7 days
nextEra: yearSnapshot
});
let weekSnapshot = new HistoryEra({
interval: 1000 * 60 * 60 * 4, // 4 hours
maxTime: 1000 * 60 * 60 * 24 * 7 * 24, // 24 weeks
name: 'weekSnapshot',
nextEraUpdateInterval: 1000 * 60 * 60 * 12, // 12 hours
nextEra: monthSnapshot
});
let daySnapshot = new HistoryEra({
interval: 1000 * 60 * 60, // 60 minutes
maxTime: 1000 * 60 * 60 * 24 * 30, // 30 days
name: 'daySnapshot',
nextEraUpdateInterval: 1000 * 60 * 60 * 4, // 4 hours
nextEra: weekSnapshot
});
let hourSnapshot = new HistoryEra({
interval: 1000 * 60 * 15, // 15 minutes
maxTime: 1000 * 60 * 60 * 24, // 24 hours
name: 'hourSnapshot',
nextEraUpdateInterval: 1000 * 60 * 60, // 60 minutes
nextEra: daySnapshot
});
let thirtyMinSnapshot = new HistoryEra({
interval: 1000 * 20, // 20 seconds
maxTime: 1000 * 60 * 30, // 30 minutes
name: 'thirtyMinSnapshot',
nextEraUpdateInterval: 1000 * 60 * 15, // 15 minutes
nextEra: hourSnapshot
});
let fiveMinSnapshot = new HistoryEra({
interval: 1000 * 5, // 5 seconds
maxTime: 1000 * 60 * 5, // 5 minutes
name: 'fiveMinSnapshot',
nextEraUpdateInterval: 1000 * 20, // 20 seconds
nextEra: thirtyMinSnapshot
});
pollInterval = setInterval(function() {
client.getTransferStats(function (err, data) {
if (err) {
return;
}
fiveMinSnapshot.addData({
upload: data.uploadRate,
download: data.downloadRate
});
});
}, 1000 * 5);

View File

@@ -0,0 +1,9 @@
'use strict';
let stringUtil = {
capitalize: function (string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
}
module.exports = stringUtil;

View File

@@ -5,6 +5,8 @@ var Strategy = require('passport-http').BasicStrategy;
var users = require('../db/users');
var collectHistory = require('../models/collectHistory');
passport.use(new Strategy(
function(username, password, callback) {
users.findByUsername(username, function(err, user) {