fireproof
Version:
Promises for Firebase objects.
329 lines (234 loc) • 7.24 kB
JavaScript
/**
* Statistics about Firebase usage.
* @namespace Fireproof.stats
* @property {Object} operationLog
* @property {Number} runningOperationCount
* @property {Number} operationCount
* @property {Number} listenCount
* @static
*/
Fireproof.stats = { _eventSubscribers: {} };
/**
* Resets the count of Firebase operations back to 0.
* @method reset
* @memberof Fireproof.stats
*/
Fireproof.stats.reset = function() {
var newOperationLog = {},
newRunningOperationCount = 0;
for (var id in Fireproof.stats.operationLog) {
var operation = Fireproof.stats.operationLog[id];
if (!operation.hasOwnProperty('finish')) {
newRunningOperationCount++;
newOperationLog[id] = operation;
}
}
Fireproof.stats.operationLog = newOperationLog;
Fireproof.stats.runningOperationCount = newRunningOperationCount;
Fireproof.stats.operationCount = newRunningOperationCount;
};
Fireproof.stats.resetListeners = function() {
Fireproof.stats.listeners = {};
Fireproof.stats.listenCount = 0;
};
/**
* Records the start of a Firebase operation.
* @private
* @param {String} kind The kind of event (read, write, or update).
* @param {String} ref The Fireproof ref to which the event refers.
* @return {String} id
*/
Fireproof.stats._start = function(event, ref) {
var path = ref.ref().toString();
var id = Math.random().toString(36).slice(2);
Fireproof.stats.runningOperationCount++;
Fireproof.stats.operationLog[id] = {
id: id,
type: event,
path: path,
start: Date.now()
};
Fireproof.stats._emit('start', Fireproof.stats.operationLog[id]);
if (event === 'listen') {
Fireproof.stats.listenCount++;
}
return id;
};
/**
* Records the end of a Firebase operation.
* @private
* @param {String} id The event ID.
* @param {String} err Error, if any, to associate with the event.
*/
Fireproof.stats._finish = function(id, err) {
var logEvent = Fireproof.stats.operationLog[id];
if (!logEvent) {
throw new Error('Fireproof: reference to unknown log event ' + id);
}
if (!logEvent.finish) {
Fireproof.stats.runningOperationCount--;
Fireproof.stats.operationCount++;
logEvent.finish = Date.now();
logEvent.duration = logEvent.finish - logEvent.start;
if (err) {
logEvent.error = err;
}
}
if (logEvent.error) {
Fireproof.stats._emit('error', logEvent);
} else {
Fireproof.stats._emit('finish', logEvent);
}
};
/**
* Records the start of a Firebase listener.
* @private
* @param {Fireproof} ref
*/
Fireproof.stats._startListener = function(ref) {
var path = ref.ref().toString();
if (!Fireproof.stats.listeners[path]) {
Fireproof.stats.listeners[path] = 0;
}
Fireproof.stats.listeners[path]++;
Fireproof.stats.listenCount++;
Fireproof.stats._emit('listenStarted', path);
};
/**
* Records the end of a Firebase listener.
* @private
* @param {Fireproof} ref
* @param {String} err Error, if any, to associate with the event.
*/
Fireproof.stats._endListener = function(ref, err) {
var path = ref.ref().toString();
Fireproof.stats.listeners[path]--;
Fireproof.stats.listenCount--;
Fireproof.stats._emit('listenEnded', path, err);
};
/**
* Gets data about listeners on Firebase locations.
* @method getListeners
* @memberof Fireproof.stats
* @returns {Object} Listener counts keyed by Firebase path.
*/
Fireproof.stats.getListeners = function() {
return Fireproof.stats.listeners;
};
/**
* Gets the total number of listeners on Firebase locations.
* @method getListenerCount
* @memberof Fireproof.stats
* @returns {Number} The total number of Firebase listeners presently operating.
*/
Fireproof.stats.getListenerCount = function() {
return Fireproof.stats.listenCount;
};
/**
* Gets the per-operation, per-path counts of Firebase operations.
* @method getPathCounts
* @memberof Fireproof.stats
* @returns {Object} An object with keys like "listen", "readOnce", "write",
* and "update". Each key has an object value, of which the keys are Firebase
* paths and the values are counts.
*/
Fireproof.stats.getPathCounts = function() {
var result = {};
for (var id in Fireproof.stats.operationLog) {
var logEvent = Fireproof.stats.operationLog[id];
if (!result[logEvent.type]) {
result[logEvent.type] = {};
}
if (!result[logEvent.type][logEvent.path]) {
result[logEvent.type][logEvent.path] = 1;
} else {
result[logEvent.type][logEvent.path]++;
}
}
return result;
};
/**
* Gets the per-operation counts of Firebase operations.
* @method getCounts
* @memberof Fireproof.stats
* @returns {Object} An object with with keys like "read", "write",
* and "update". The values are the counts of operations under those headings.
*/
Fireproof.stats.getCounts = function() {
var result = {};
for (var id in Fireproof.stats.operationLog) {
var logEvent = Fireproof.stats.operationLog[id];
if (!result[logEvent.type]) {
result[logEvent.type] = 1;
} else {
result[logEvent.type]++;
}
}
return result;
};
/**
* Listens for Firebase events occurring.
* @method on
* @memberof Fireproof.stats
* @param {String} name The name of the event. One of 'start', 'finish', 'error',
* 'listenStarted', or 'listenEnded.'
* @param {Function} fn The function to call when the event happens. Takes a single
* parameter, the event object.
* @returns {Function} fn is returned for convenience, to pass to `off`.
* @throws if you don't pass in a function for fn.
*/
Fireproof.stats.on = function(name, fn) {
if (typeof name === 'function' && fn === undefined) {
fn = name;
name = null;
}
if (typeof fn !== 'function') {
throw new Error('Non-function passed to Fireproof.stats.on');
}
if (!Fireproof.stats._eventSubscribers[name]) {
Fireproof.stats._eventSubscribers[name] = [];
}
Fireproof.stats._eventSubscribers[name].push(fn);
return fn;
};
/**
* Stops sending events to a listener.
* @method off
* @memberof Fireproof.stats
* @param {String} [name] The name of the event. One of 'start', 'finish', 'error',
* 'listenStarted', or 'listenEnded.'
* @param {Function} fn The function to stop calling.
* @throws if you don't pass in a function for fn.
*/
Fireproof.stats.off = function(name, fn) {
if (typeof name === 'function' && fn === undefined) {
fn = name;
name = null;
}
if (typeof fn !== 'function') {
throw new Error('Non-function passed to Fireproof.stats.off');
}
if (name) {
var listeners = Fireproof.stats._eventSubscribers[name],
index = listeners.indexOf(fn);
if (index !== -1) {
listeners[index] = null;
}
}
};
Fireproof.stats._emit = function(name) {
var args = Array.prototype.slice.call(arguments, 1);
if (!Fireproof.stats._eventSubscribers[name]) {
Fireproof.stats._eventSubscribers[name] = [];
}
var listeners = Fireproof.stats._eventSubscribers[name];
Fireproof._nextTick(function() {
for (var i = 0; i < listeners.length; i++) {
if (listeners[i] !== null) {
listeners[i].apply(null, args);
}
}
});
};
Fireproof.stats.reset();
Fireproof.stats.resetListeners();