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: this.EXPORTED_SYMBOLS = [ michael@0: "SyncProvider", michael@0: ]; michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu} = Components; michael@0: michael@0: Cu.import("resource://gre/modules/Metrics.jsm", this); michael@0: Cu.import("resource://gre/modules/Promise.jsm", this); michael@0: Cu.import("resource://gre/modules/Services.jsm", this); michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); michael@0: michael@0: const DAILY_LAST_NUMERIC_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_NUMERIC}; michael@0: const DAILY_LAST_TEXT_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_TEXT}; michael@0: const DAILY_COUNTER_FIELD = {type: Metrics.Storage.FIELD_DAILY_COUNTER}; michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "Weave", michael@0: "resource://services-sync/main.js"); michael@0: michael@0: function SyncMeasurement1() { michael@0: Metrics.Measurement.call(this); michael@0: } michael@0: michael@0: SyncMeasurement1.prototype = Object.freeze({ michael@0: __proto__: Metrics.Measurement.prototype, michael@0: michael@0: name: "sync", michael@0: version: 1, michael@0: michael@0: fields: { michael@0: enabled: DAILY_LAST_NUMERIC_FIELD, michael@0: preferredProtocol: DAILY_LAST_TEXT_FIELD, michael@0: activeProtocol: DAILY_LAST_TEXT_FIELD, michael@0: syncStart: DAILY_COUNTER_FIELD, michael@0: syncSuccess: DAILY_COUNTER_FIELD, michael@0: syncError: DAILY_COUNTER_FIELD, michael@0: }, michael@0: }); michael@0: michael@0: function SyncDevicesMeasurement1() { michael@0: Metrics.Measurement.call(this); michael@0: } michael@0: michael@0: SyncDevicesMeasurement1.prototype = Object.freeze({ michael@0: __proto__: Metrics.Measurement.prototype, michael@0: michael@0: name: "devices", michael@0: version: 1, michael@0: michael@0: fields: {}, michael@0: michael@0: shouldIncludeField: function (name) { michael@0: return true; michael@0: }, michael@0: michael@0: fieldType: function (name) { michael@0: return Metrics.Storage.FIELD_DAILY_COUNTER; michael@0: }, michael@0: }); michael@0: michael@0: this.SyncProvider = function () { michael@0: Metrics.Provider.call(this); michael@0: }; michael@0: SyncProvider.prototype = Object.freeze({ michael@0: __proto__: Metrics.Provider.prototype, michael@0: michael@0: name: "org.mozilla.sync", michael@0: michael@0: measurementTypes: [ michael@0: SyncDevicesMeasurement1, michael@0: SyncMeasurement1, michael@0: ], michael@0: michael@0: _OBSERVERS: [ michael@0: "weave:service:sync:start", michael@0: "weave:service:sync:finish", michael@0: "weave:service:sync:error", michael@0: ], michael@0: michael@0: postInit: function () { michael@0: for (let o of this._OBSERVERS) { michael@0: Services.obs.addObserver(this, o, false); michael@0: } michael@0: michael@0: return Promise.resolve(); michael@0: }, michael@0: michael@0: onShutdown: function () { michael@0: for (let o of this._OBSERVERS) { michael@0: Services.obs.removeObserver(this, o); michael@0: } michael@0: michael@0: return Promise.resolve(); michael@0: }, michael@0: michael@0: observe: function (subject, topic, data) { michael@0: let field; michael@0: switch (topic) { michael@0: case "weave:service:sync:start": michael@0: field = "syncStart"; michael@0: break; michael@0: michael@0: case "weave:service:sync:finish": michael@0: field = "syncSuccess"; michael@0: break; michael@0: michael@0: case "weave:service:sync:error": michael@0: field = "syncError"; michael@0: break; michael@0: } michael@0: michael@0: let m = this.getMeasurement(SyncMeasurement1.prototype.name, michael@0: SyncMeasurement1.prototype.version); michael@0: return this.enqueueStorageOperation(function recordSyncEvent() { michael@0: return m.incrementDailyCounter(field); michael@0: }); michael@0: }, michael@0: michael@0: collectDailyData: function () { michael@0: return this.storage.enqueueTransaction(this._populateDailyData.bind(this)); michael@0: }, michael@0: michael@0: _populateDailyData: function* () { michael@0: let m = this.getMeasurement(SyncMeasurement1.prototype.name, michael@0: SyncMeasurement1.prototype.version); michael@0: michael@0: let svc = Cc["@mozilla.org/weave/service;1"] michael@0: .getService(Ci.nsISupports) michael@0: .wrappedJSObject; michael@0: michael@0: let enabled = svc.enabled; michael@0: yield m.setDailyLastNumeric("enabled", enabled ? 1 : 0); michael@0: michael@0: // preferredProtocol is constant and only changes as the client michael@0: // evolves. michael@0: yield m.setDailyLastText("preferredProtocol", "1.5"); michael@0: michael@0: let protocol = svc.fxAccountsEnabled ? "1.5" : "1.1"; michael@0: yield m.setDailyLastText("activeProtocol", protocol); michael@0: michael@0: if (!enabled) { michael@0: return; michael@0: } michael@0: michael@0: // Before grabbing more information, be sure the Sync service michael@0: // is fully initialized. This has the potential to initialize michael@0: // Sync on the spot. This may be undesired if Sync appears to michael@0: // be enabled but it really isn't. That responsibility should michael@0: // be up to svc.enabled to not return false positives, however. michael@0: yield svc.whenLoaded(); michael@0: michael@0: if (Weave.Status.service != Weave.STATUS_OK) { michael@0: return; michael@0: } michael@0: michael@0: // Device types are dynamic. So we need to dynamically create fields if michael@0: // they don't exist. michael@0: let dm = this.getMeasurement(SyncDevicesMeasurement1.prototype.name, michael@0: SyncDevicesMeasurement1.prototype.version); michael@0: let devices = Weave.Service.clientsEngine.deviceTypes; michael@0: for (let [field, count] of devices) { michael@0: let hasField = this.storage.hasFieldFromMeasurement(dm.id, field, michael@0: this.storage.FIELD_DAILY_LAST_NUMERIC); michael@0: let fieldID; michael@0: if (hasField) { michael@0: fieldID = this.storage.fieldIDFromMeasurement(dm.id, field); michael@0: } else { michael@0: fieldID = yield this.storage.registerField(dm.id, field, michael@0: this.storage.FIELD_DAILY_LAST_NUMERIC); michael@0: } michael@0: michael@0: yield this.storage.setDailyLastNumericFromFieldID(fieldID, count); michael@0: } michael@0: }, michael@0: });