michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: let Cu = Components.utils; michael@0: let Ci = Components.interfaces; michael@0: let Cc = Components.classes; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: const STORAGE_MAX_EVENTS = 200; michael@0: michael@0: var _consoleStorage = new Map(); michael@0: michael@0: const CONSOLEAPISTORAGE_CID = Components.ID('{96cf7855-dfa9-4c6d-8276-f9705b4890f2}'); michael@0: michael@0: /** michael@0: * The ConsoleAPIStorage is meant to cache window.console API calls for later michael@0: * reuse by other components when needed. For example, the Web Console code can michael@0: * display the cached messages when it opens for the active tab. michael@0: * michael@0: * ConsoleAPI messages are stored as they come from the ConsoleAPI code, with michael@0: * all their properties. They are kept around until the inner window object that michael@0: * created the messages is destroyed. Messages are indexed by the inner window michael@0: * ID. michael@0: * michael@0: * Usage: michael@0: * Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm"); michael@0: * michael@0: * // Get the cached events array for the window you want (use the inner michael@0: * // window ID). michael@0: * let events = ConsoleAPIStorage.getEvents(innerWindowID); michael@0: * events.forEach(function(event) { ... }); michael@0: * michael@0: * // Clear the events for the given inner window ID. michael@0: * ConsoleAPIStorage.clearEvents(innerWindowID); michael@0: */ michael@0: function ConsoleAPIStorageService() { michael@0: this.init(); michael@0: } michael@0: michael@0: ConsoleAPIStorageService.prototype = { michael@0: classID : CONSOLEAPISTORAGE_CID, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleAPIStorage, michael@0: Ci.nsIObserver]), michael@0: classInfo: XPCOMUtils.generateCI({ michael@0: classID: CONSOLEAPISTORAGE_CID, michael@0: contractID: '@mozilla.org/consoleAPI-storage;1', michael@0: interfaces: [Ci.nsIConsoleAPIStorage, Ci.nsIObserver], michael@0: flags: Ci.nsIClassInfo.SINGLETON michael@0: }), michael@0: michael@0: observe: function CS_observe(aSubject, aTopic, aData) michael@0: { michael@0: if (aTopic == "xpcom-shutdown") { michael@0: Services.obs.removeObserver(this, "xpcom-shutdown"); michael@0: Services.obs.removeObserver(this, "inner-window-destroyed"); michael@0: Services.obs.removeObserver(this, "memory-pressure"); michael@0: } michael@0: else if (aTopic == "inner-window-destroyed") { michael@0: let innerWindowID = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data; michael@0: this.clearEvents(innerWindowID + ""); michael@0: } michael@0: else if (aTopic == "memory-pressure") { michael@0: this.clearEvents(); michael@0: } michael@0: }, michael@0: michael@0: /** @private */ michael@0: init: function CS_init() michael@0: { michael@0: Services.obs.addObserver(this, "xpcom-shutdown", false); michael@0: Services.obs.addObserver(this, "inner-window-destroyed", false); michael@0: Services.obs.addObserver(this, "memory-pressure", false); michael@0: }, michael@0: michael@0: /** michael@0: * Get the events array by inner window ID or all events from all windows. michael@0: * michael@0: * @param string [aId] michael@0: * Optional, the inner window ID for which you want to get the array of michael@0: * cached events. michael@0: * @returns array michael@0: * The array of cached events for the given window. If no |aId| is michael@0: * given this function returns all of the cached events, from any michael@0: * window. michael@0: */ michael@0: getEvents: function CS_getEvents(aId) michael@0: { michael@0: if (aId != null) { michael@0: return (_consoleStorage.get(aId) || []).slice(0); michael@0: } michael@0: michael@0: let result = []; michael@0: michael@0: for (let [id, events] of _consoleStorage) { michael@0: result.push.apply(result, events); michael@0: } michael@0: michael@0: return result.sort(function(a, b) { michael@0: return a.timeStamp - b.timeStamp; michael@0: }); michael@0: }, michael@0: michael@0: /** michael@0: * Record an event associated with the given window ID. michael@0: * michael@0: * @param string aId michael@0: * The ID of the inner window for which the event occurred or "jsm" for michael@0: * messages logged from JavaScript modules.. michael@0: * @param object aEvent michael@0: * A JavaScript object you want to store. michael@0: */ michael@0: recordEvent: function CS_recordEvent(aId, aEvent) michael@0: { michael@0: if (!_consoleStorage.has(aId)) { michael@0: _consoleStorage.set(aId, []); michael@0: } michael@0: michael@0: let storage = _consoleStorage.get(aId); michael@0: storage.push(aEvent); michael@0: michael@0: // truncate michael@0: if (storage.length > STORAGE_MAX_EVENTS) { michael@0: storage.shift(); michael@0: } michael@0: michael@0: Services.obs.notifyObservers(aEvent, "console-storage-cache-event", aId); michael@0: }, michael@0: michael@0: /** michael@0: * Clear storage data for the given window. michael@0: * michael@0: * @param string [aId] michael@0: * Optional, the inner window ID for which you want to clear the michael@0: * messages. If this is not specified all of the cached messages are michael@0: * cleared, from all window objects. michael@0: */ michael@0: clearEvents: function CS_clearEvents(aId) michael@0: { michael@0: if (aId != null) { michael@0: _consoleStorage.delete(aId); michael@0: } michael@0: else { michael@0: _consoleStorage.clear(); michael@0: Services.obs.notifyObservers(null, "console-storage-reset", null); michael@0: } michael@0: }, michael@0: }; michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ConsoleAPIStorageService]);