summaryrefslogtreecommitdiffstats
path: root/dom/network/NetworkStatsManager.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/network/NetworkStatsManager.js')
-rw-r--r--dom/network/NetworkStatsManager.js388
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]);