diff options
Diffstat (limited to 'dom/network/NetworkStatsManager.js')
-rw-r--r-- | dom/network/NetworkStatsManager.js | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/dom/network/NetworkStatsManager.js b/dom/network/NetworkStatsManager.js new file mode 100644 index 000000000..b963aba2b --- /dev/null +++ b/dom/network/NetworkStatsManager.js @@ -0,0 +1,388 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const DEBUG = false; +function debug(s) { dump("-*- NetworkStatsManager: " + s + "\n"); } + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); + +// Ensure NetworkStatsService and NetworkStatsDB are loaded in the parent process +// to receive messages from the child processes. +var appInfo = Cc["@mozilla.org/xre/app-info;1"]; +var isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime) + .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; +if (isParentProcess) { + Cu.import("resource://gre/modules/NetworkStatsService.jsm"); +} + +XPCOMUtils.defineLazyServiceGetter(this, "cpmm", + "@mozilla.org/childprocessmessagemanager;1", + "nsISyncMessageSender"); + +// NetworkStatsData +const nsIClassInfo = Ci.nsIClassInfo; +const NETWORKSTATSDATA_CID = Components.ID("{3b16fe17-5583-483a-b486-b64a3243221c}"); + +function NetworkStatsData(aWindow, aData) { + this.rxBytes = aData.rxBytes; + this.txBytes = aData.txBytes; + this.date = new aWindow.Date(aData.date.getTime()); +} + +NetworkStatsData.prototype = { + classID : NETWORKSTATSDATA_CID, + + QueryInterface : XPCOMUtils.generateQI([]) +}; + +// NetworkStatsInterface +const NETWORKSTATSINTERFACE_CONTRACTID = "@mozilla.org/networkstatsinterface;1"; +const NETWORKSTATSINTERFACE_CID = Components.ID("{f540615b-d803-43ff-8200-2a9d145a5645}"); + +function NetworkStatsInterface() { + if (DEBUG) { + debug("NetworkStatsInterface Constructor"); + } +} + +NetworkStatsInterface.prototype = { + __init: function(aNetwork) { + this.type = aNetwork.type; + this.id = aNetwork.id; + }, + + classID : NETWORKSTATSINTERFACE_CID, + + contractID: NETWORKSTATSINTERFACE_CONTRACTID, + QueryInterface : XPCOMUtils.generateQI([]) +} + +// NetworkStats +const NETWORKSTATS_CID = Components.ID("{28904f59-8497-4ac0-904f-2af14b7fd3de}"); + +function NetworkStats(aWindow, aStats) { + if (DEBUG) { + debug("NetworkStats Constructor"); + } + this.appManifestURL = aStats.appManifestURL || null; + this.browsingTrafficOnly = aStats.browsingTrafficOnly || false; + this.serviceType = aStats.serviceType || null; + this.network = new aWindow.MozNetworkStatsInterface(aStats.network); + this.start = aStats.start ? new aWindow.Date(aStats.start.getTime()) : null; + this.end = aStats.end ? new aWindow.Date(aStats.end.getTime()) : null; + + let samples = this.data = new aWindow.Array(); + for (let i = 0; i < aStats.data.length; i++) { + samples.push(aWindow.MozNetworkStatsData._create( + aWindow, new NetworkStatsData(aWindow, aStats.data[i]))); + } +} + +NetworkStats.prototype = { + classID : NETWORKSTATS_CID, + + QueryInterface : XPCOMUtils.generateQI() +} + +// NetworkStatsAlarm +const NETWORKSTATSALARM_CID = Components.ID("{a93ea13e-409c-4189-9b1e-95fff220be55}"); + +function NetworkStatsAlarm(aWindow, aAlarm) { + this.alarmId = aAlarm.id; + this.network = new aWindow.MozNetworkStatsInterface(aAlarm.network); + this.threshold = aAlarm.threshold; + this.data = aAlarm.data; +} + +NetworkStatsAlarm.prototype = { + classID : NETWORKSTATSALARM_CID, + + QueryInterface : XPCOMUtils.generateQI([]) +}; + +// NetworkStatsManager + +const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1"; +const NETWORKSTATSMANAGER_CID = Components.ID("{ceb874cd-cc1a-4e65-b404-cc2d3e42425f}"); + +function NetworkStatsManager() { + if (DEBUG) { + debug("Constructor"); + } +} + +NetworkStatsManager.prototype = { + __proto__: DOMRequestIpcHelper.prototype, + + getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) { + if (aStart > aEnd) { + throw Components.results.NS_ERROR_INVALID_ARG; + } + + // appManifestURL is used to query network statistics by app; + // serviceType is used to query network statistics by system service. + // It is illegal to specify both of them at the same time. + if (aOptions.appManifestURL && aOptions.serviceType) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + } + // browsingTrafficOnly is meaningful only when querying by app. + if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + } + + let appManifestURL = aOptions.appManifestURL; + let serviceType = aOptions.serviceType; + let browsingTrafficOnly = aOptions.browsingTrafficOnly; + + // TODO Bug 929410 Date object cannot correctly pass through cpmm/ppmm IPC + // This is just a work-around by passing timestamp numbers. + aStart = aStart.getTime(); + aEnd = aEnd.getTime(); + + let request = this.createRequest(); + cpmm.sendAsyncMessage("NetworkStats:Get", + { network: aNetwork.toJSON(), + start: aStart, + end: aEnd, + appManifestURL: appManifestURL, + browsingTrafficOnly: browsingTrafficOnly, + serviceType: serviceType, + id: this.getRequestId(request) }); + return request; + }, + + clearStats: function clearStats(aNetwork) { + let request = this.createRequest(); + cpmm.sendAsyncMessage("NetworkStats:Clear", + { network: aNetwork.toJSON(), + id: this.getRequestId(request) }); + return request; + }, + + clearAllStats: function clearAllStats() { + let request = this.createRequest(); + cpmm.sendAsyncMessage("NetworkStats:ClearAll", + {id: this.getRequestId(request)}); + return request; + }, + + addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) { + let request = this.createRequest(); + cpmm.sendAsyncMessage("NetworkStats:SetAlarm", + {id: this.getRequestId(request), + data: {network: aNetwork.toJSON(), + threshold: aThreshold, + startTime: aOptions.startTime, + data: aOptions.data, + manifestURL: this.manifestURL, + pageURL: this.pageURL}}); + return request; + }, + + getAllAlarms: function getAllAlarms(aNetwork) { + let network = null; + if (aNetwork) { + network = aNetwork.toJSON(); + } + + let request = this.createRequest(); + cpmm.sendAsyncMessage("NetworkStats:GetAlarms", + {id: this.getRequestId(request), + data: {network: network, + manifestURL: this.manifestURL}}); + return request; + }, + + removeAlarms: function removeAlarms(aAlarmId) { + if (aAlarmId == 0) { + aAlarmId = -1; + } + + let request = this.createRequest(); + cpmm.sendAsyncMessage("NetworkStats:RemoveAlarms", + {id: this.getRequestId(request), + data: {alarmId: aAlarmId, + manifestURL: this.manifestURL}}); + + return request; + }, + + getAvailableNetworks: function getAvailableNetworks() { + let request = this.createRequest(); + cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks", + { id: this.getRequestId(request) }); + return request; + }, + + getAvailableServiceTypes: function getAvailableServiceTypes() { + let request = this.createRequest(); + cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes", + { id: this.getRequestId(request) }); + return request; + }, + + get sampleRate() { + return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0]; + }, + + get maxStorageAge() { + return cpmm.sendSyncMessage("NetworkStats:MaxStorageAge")[0]; + }, + + receiveMessage: function(aMessage) { + if (DEBUG) { + debug("NetworkStatsmanager::receiveMessage: " + aMessage.name); + } + + let msg = aMessage.json; + let req = this.takeRequest(msg.id); + if (!req) { + if (DEBUG) { + debug("No request stored with id " + msg.id); + } + return; + } + + switch (aMessage.name) { + case "NetworkStats:Get:Return": + if (msg.error) { + Services.DOMRequest.fireError(req, msg.error); + return; + } + + let result = this._window.MozNetworkStats._create( + this._window, new NetworkStats(this._window, msg.result)); + if (DEBUG) { + debug("result: " + JSON.stringify(result)); + } + Services.DOMRequest.fireSuccess(req, result); + break; + + case "NetworkStats:GetAvailableNetworks:Return": + if (msg.error) { + Services.DOMRequest.fireError(req, msg.error); + return; + } + + let networks = new this._window.Array(); + for (let i = 0; i < msg.result.length; i++) { + let network = new this._window.MozNetworkStatsInterface(msg.result[i]); + networks.push(network); + } + + Services.DOMRequest.fireSuccess(req, networks); + break; + + case "NetworkStats:GetAvailableServiceTypes:Return": + if (msg.error) { + Services.DOMRequest.fireError(req, msg.error); + return; + } + + let serviceTypes = new this._window.Array(); + for (let i = 0; i < msg.result.length; i++) { + serviceTypes.push(msg.result[i]); + } + + Services.DOMRequest.fireSuccess(req, serviceTypes); + break; + + case "NetworkStats:Clear:Return": + case "NetworkStats:ClearAll:Return": + if (msg.error) { + Services.DOMRequest.fireError(req, msg.error); + return; + } + + Services.DOMRequest.fireSuccess(req, true); + break; + + case "NetworkStats:SetAlarm:Return": + case "NetworkStats:RemoveAlarms:Return": + if (msg.error) { + Services.DOMRequest.fireError(req, msg.error); + return; + } + + Services.DOMRequest.fireSuccess(req, msg.result); + break; + + case "NetworkStats:GetAlarms:Return": + if (msg.error) { + Services.DOMRequest.fireError(req, msg.error); + return; + } + + let alarms = new this._window.Array(); + for (let i = 0; i < msg.result.length; i++) { + // The WebIDL type of data is any, so we should manually clone it + // into the content window. + if ("data" in msg.result[i]) { + msg.result[i].data = Cu.cloneInto(msg.result[i].data, this._window); + } + let alarm = new NetworkStatsAlarm(this._window, msg.result[i]); + alarms.push(this._window.MozNetworkStatsAlarm._create(this._window, alarm)); + } + + Services.DOMRequest.fireSuccess(req, alarms); + break; + + default: + if (DEBUG) { + debug("Wrong message: " + aMessage.name); + } + } + }, + + init: function(aWindow) { + let principal = aWindow.document.nodePrincipal; + + this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return", + "NetworkStats:GetAvailableNetworks:Return", + "NetworkStats:GetAvailableServiceTypes:Return", + "NetworkStats:Clear:Return", + "NetworkStats:ClearAll:Return", + "NetworkStats:SetAlarm:Return", + "NetworkStats:GetAlarms:Return", + "NetworkStats:RemoveAlarms:Return"]); + + // Init app properties. + let appsService = Cc["@mozilla.org/AppsService;1"] + .getService(Ci.nsIAppsService); + + this.manifestURL = appsService.getManifestURLByLocalId(principal.appId); + + let isApp = !!this.manifestURL.length; + if (isApp) { + this.pageURL = principal.URI.spec; + } + + this.window = aWindow; + }, + + // Called from DOMRequestIpcHelper + uninit: function uninit() { + if (DEBUG) { + debug("uninit call"); + } + }, + + classID : NETWORKSTATSMANAGER_CID, + contractID : NETWORKSTATSMANAGER_CONTRACTID, + QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer, + Ci.nsISupportsWeakReference, + Ci.nsIObserver]), +} + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm, + NetworkStatsData, + NetworkStatsInterface, + NetworkStats, + NetworkStatsManager]); |