eventlog: async'ify
This commit is contained in:
+78
-54
@@ -2,11 +2,11 @@
|
||||
|
||||
exports = module.exports = {
|
||||
add,
|
||||
upsert,
|
||||
upsertLoginEvent,
|
||||
get,
|
||||
getAllPaged,
|
||||
getByCreationTime,
|
||||
cleanup,
|
||||
_clear: clear,
|
||||
|
||||
// keep in sync with webadmin index.js filter
|
||||
ACTION_ACTIVATE: 'cloudron.activate',
|
||||
@@ -77,94 +77,118 @@ exports = module.exports = {
|
||||
};
|
||||
|
||||
const assert = require('assert'),
|
||||
database = require('./database.js'),
|
||||
debug = require('debug')('box:eventlog'),
|
||||
eventlogdb = require('./eventlogdb.js'),
|
||||
mysql = require('mysql'),
|
||||
notifications = require('./notifications.js'),
|
||||
safe = require('safetydance'),
|
||||
util = require('util'),
|
||||
uuid = require('uuid');
|
||||
|
||||
const NOOP_CALLBACK = function (error) { if (error) debug(error); };
|
||||
const EVENTLOG_FIELDS = [ 'id', 'action', 'source', 'data', 'creationTime' ].join(',');
|
||||
|
||||
function add(action, source, data, callback) {
|
||||
function postProcess(record) {
|
||||
// usually we have sourceJson and dataJson, however since this used to be the JSON data type, we don't
|
||||
record.source = safe.JSON.parse(record.source);
|
||||
record.data = safe.JSON.parse(record.data);
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
// never throws, only logs because previously code did not take a callback
|
||||
async function add(action, source, data) {
|
||||
assert.strictEqual(typeof action, 'string');
|
||||
assert.strictEqual(typeof source, 'object');
|
||||
assert.strictEqual(typeof data, 'object');
|
||||
assert(!callback || typeof callback === 'function');
|
||||
|
||||
callback = callback || NOOP_CALLBACK;
|
||||
|
||||
eventlogdb.add(uuid.v4(), action, source, data, async function (error, id) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null, { id: id });
|
||||
|
||||
await safe(notifications.onEvent(id, action, source, data));
|
||||
});
|
||||
const id = uuid.v4();
|
||||
try {
|
||||
await database.query('INSERT INTO eventlog (id, action, source, data) VALUES (?, ?, ?, ?)', [ id, action, JSON.stringify(source), JSON.stringify(data) ]);
|
||||
await notifications.onEvent(id, action, source, data);
|
||||
return id;
|
||||
} catch (error) {
|
||||
debug('add: error adding event', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function upsert(action, source, data, callback) {
|
||||
// never throws, only logs because previously code did not take a callback
|
||||
async function upsertLoginEvent(action, source, data) {
|
||||
assert.strictEqual(typeof action, 'string');
|
||||
assert.strictEqual(typeof source, 'object');
|
||||
assert.strictEqual(typeof data, 'object');
|
||||
assert(!callback || typeof callback === 'function');
|
||||
|
||||
callback = callback || NOOP_CALLBACK;
|
||||
// can't do a real sql upsert, for frequent eventlog entries we only have to do 2 queries once a day
|
||||
const queries = [{
|
||||
query: 'UPDATE eventlog SET creationTime=NOW(), data=? WHERE action = ? AND source LIKE ? AND DATE(creationTime)=CURDATE()',
|
||||
args: [ JSON.stringify(data), action, JSON.stringify(source) ]
|
||||
}, {
|
||||
query: 'SELECT ' + EVENTLOG_FIELDS + ' FROM eventlog WHERE action = ? AND source LIKE ? AND DATE(creationTime)=CURDATE()',
|
||||
args: [ action, JSON.stringify(source) ]
|
||||
}];
|
||||
|
||||
eventlogdb.upsert(uuid.v4(), action, source, data, async function (error, id) {
|
||||
if (error) return callback(error);
|
||||
try {
|
||||
const result = await database.transaction(queries);
|
||||
if (result[0].affectedRows >= 1) return result[1][0].id;
|
||||
|
||||
callback(null, { id: id });
|
||||
|
||||
await safe(notifications.onEvent(id, action, source, data));
|
||||
});
|
||||
// no existing eventlog found, create one
|
||||
return await add(action, source, data);
|
||||
} catch (error) {
|
||||
debug('add: error adding event', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function get(id, callback) {
|
||||
async function get(id) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
eventlogdb.get(id, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
const result = await database.query('SELECT ' + EVENTLOG_FIELDS + ' FROM eventlog WHERE id = ?', [ id ]);
|
||||
if (result.length === 0) return null;
|
||||
|
||||
callback(null, result);
|
||||
});
|
||||
return postProcess(result[0]);
|
||||
}
|
||||
|
||||
function getAllPaged(actions, search, page, perPage, callback) {
|
||||
async function getAllPaged(actions, search, page, perPage) {
|
||||
assert(Array.isArray(actions));
|
||||
assert(typeof search === 'string' || search === null);
|
||||
assert.strictEqual(typeof page, 'number');
|
||||
assert.strictEqual(typeof perPage, 'number');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
eventlogdb.getAllPaged(actions, search, page, perPage, function (error, events) {
|
||||
if (error) return callback(error);
|
||||
let data = [];
|
||||
let query = `SELECT ${EVENTLOG_FIELDS} FROM eventlog`;
|
||||
|
||||
callback(null, events);
|
||||
if (actions.length || search) query += ' WHERE';
|
||||
if (search) query += ' (source LIKE ' + mysql.escape('%' + search + '%') + ' OR data LIKE ' + mysql.escape('%' + search + '%') + ')';
|
||||
|
||||
if (actions.length && search) query += ' AND ( ';
|
||||
actions.forEach(function (action, i) {
|
||||
query += ' (action LIKE ' + mysql.escape(`%${action}%`) + ') ';
|
||||
if (i < actions.length-1) query += ' OR ';
|
||||
});
|
||||
if (actions.length && search) query += ' ) ';
|
||||
|
||||
query += ' ORDER BY creationTime DESC LIMIT ?,?';
|
||||
|
||||
data.push((page-1)*perPage);
|
||||
data.push(perPage);
|
||||
|
||||
const results = await database.query(query, data);
|
||||
results.forEach(postProcess);
|
||||
return results;
|
||||
}
|
||||
|
||||
function getByCreationTime(creationTime, callback) {
|
||||
assert(util.types.isDate(creationTime));
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
async function cleanup(options) {
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
eventlogdb.getByCreationTime(creationTime, function (error, events) {
|
||||
if (error) return callback(error);
|
||||
const creationTime = options.creationTime || new Date(Date.now() - 60 * 60 * 24 * 10 * 1000); // 10 days ago
|
||||
|
||||
callback(null, events);
|
||||
});
|
||||
const results = await database.query('SELECT * FROM eventlog WHERE creationTime <= ?', [ creationTime ]);
|
||||
|
||||
for (const result of results) {
|
||||
await database.query('DELETE FROM notifications WHERE eventId=?', [ result.id ]); // remove notifications that reference the events as well
|
||||
await database.query('DELETE FROM eventlog WHERE id=?', [ result.id ]);
|
||||
}
|
||||
}
|
||||
|
||||
function cleanup(callback) {
|
||||
callback = callback || NOOP_CALLBACK;
|
||||
|
||||
var d = new Date();
|
||||
d.setDate(d.getDate() - 10); // 10 days ago
|
||||
|
||||
eventlogdb.delByCreationTime(d, function (error) {
|
||||
if (error) return callback(error);
|
||||
|
||||
callback(null);
|
||||
});
|
||||
async function clear() {
|
||||
await database.query('DELETE FROM eventlog');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user