|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 this.EXPORTED_SYMBOLS = [ |
|
8 "SyncProvider", |
|
9 ]; |
|
10 |
|
11 const {classes: Cc, interfaces: Ci, utils: Cu} = Components; |
|
12 |
|
13 Cu.import("resource://gre/modules/Metrics.jsm", this); |
|
14 Cu.import("resource://gre/modules/Promise.jsm", this); |
|
15 Cu.import("resource://gre/modules/Services.jsm", this); |
|
16 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); |
|
17 |
|
18 const DAILY_LAST_NUMERIC_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_NUMERIC}; |
|
19 const DAILY_LAST_TEXT_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_TEXT}; |
|
20 const DAILY_COUNTER_FIELD = {type: Metrics.Storage.FIELD_DAILY_COUNTER}; |
|
21 |
|
22 XPCOMUtils.defineLazyModuleGetter(this, "Weave", |
|
23 "resource://services-sync/main.js"); |
|
24 |
|
25 function SyncMeasurement1() { |
|
26 Metrics.Measurement.call(this); |
|
27 } |
|
28 |
|
29 SyncMeasurement1.prototype = Object.freeze({ |
|
30 __proto__: Metrics.Measurement.prototype, |
|
31 |
|
32 name: "sync", |
|
33 version: 1, |
|
34 |
|
35 fields: { |
|
36 enabled: DAILY_LAST_NUMERIC_FIELD, |
|
37 preferredProtocol: DAILY_LAST_TEXT_FIELD, |
|
38 activeProtocol: DAILY_LAST_TEXT_FIELD, |
|
39 syncStart: DAILY_COUNTER_FIELD, |
|
40 syncSuccess: DAILY_COUNTER_FIELD, |
|
41 syncError: DAILY_COUNTER_FIELD, |
|
42 }, |
|
43 }); |
|
44 |
|
45 function SyncDevicesMeasurement1() { |
|
46 Metrics.Measurement.call(this); |
|
47 } |
|
48 |
|
49 SyncDevicesMeasurement1.prototype = Object.freeze({ |
|
50 __proto__: Metrics.Measurement.prototype, |
|
51 |
|
52 name: "devices", |
|
53 version: 1, |
|
54 |
|
55 fields: {}, |
|
56 |
|
57 shouldIncludeField: function (name) { |
|
58 return true; |
|
59 }, |
|
60 |
|
61 fieldType: function (name) { |
|
62 return Metrics.Storage.FIELD_DAILY_COUNTER; |
|
63 }, |
|
64 }); |
|
65 |
|
66 this.SyncProvider = function () { |
|
67 Metrics.Provider.call(this); |
|
68 }; |
|
69 SyncProvider.prototype = Object.freeze({ |
|
70 __proto__: Metrics.Provider.prototype, |
|
71 |
|
72 name: "org.mozilla.sync", |
|
73 |
|
74 measurementTypes: [ |
|
75 SyncDevicesMeasurement1, |
|
76 SyncMeasurement1, |
|
77 ], |
|
78 |
|
79 _OBSERVERS: [ |
|
80 "weave:service:sync:start", |
|
81 "weave:service:sync:finish", |
|
82 "weave:service:sync:error", |
|
83 ], |
|
84 |
|
85 postInit: function () { |
|
86 for (let o of this._OBSERVERS) { |
|
87 Services.obs.addObserver(this, o, false); |
|
88 } |
|
89 |
|
90 return Promise.resolve(); |
|
91 }, |
|
92 |
|
93 onShutdown: function () { |
|
94 for (let o of this._OBSERVERS) { |
|
95 Services.obs.removeObserver(this, o); |
|
96 } |
|
97 |
|
98 return Promise.resolve(); |
|
99 }, |
|
100 |
|
101 observe: function (subject, topic, data) { |
|
102 let field; |
|
103 switch (topic) { |
|
104 case "weave:service:sync:start": |
|
105 field = "syncStart"; |
|
106 break; |
|
107 |
|
108 case "weave:service:sync:finish": |
|
109 field = "syncSuccess"; |
|
110 break; |
|
111 |
|
112 case "weave:service:sync:error": |
|
113 field = "syncError"; |
|
114 break; |
|
115 } |
|
116 |
|
117 let m = this.getMeasurement(SyncMeasurement1.prototype.name, |
|
118 SyncMeasurement1.prototype.version); |
|
119 return this.enqueueStorageOperation(function recordSyncEvent() { |
|
120 return m.incrementDailyCounter(field); |
|
121 }); |
|
122 }, |
|
123 |
|
124 collectDailyData: function () { |
|
125 return this.storage.enqueueTransaction(this._populateDailyData.bind(this)); |
|
126 }, |
|
127 |
|
128 _populateDailyData: function* () { |
|
129 let m = this.getMeasurement(SyncMeasurement1.prototype.name, |
|
130 SyncMeasurement1.prototype.version); |
|
131 |
|
132 let svc = Cc["@mozilla.org/weave/service;1"] |
|
133 .getService(Ci.nsISupports) |
|
134 .wrappedJSObject; |
|
135 |
|
136 let enabled = svc.enabled; |
|
137 yield m.setDailyLastNumeric("enabled", enabled ? 1 : 0); |
|
138 |
|
139 // preferredProtocol is constant and only changes as the client |
|
140 // evolves. |
|
141 yield m.setDailyLastText("preferredProtocol", "1.5"); |
|
142 |
|
143 let protocol = svc.fxAccountsEnabled ? "1.5" : "1.1"; |
|
144 yield m.setDailyLastText("activeProtocol", protocol); |
|
145 |
|
146 if (!enabled) { |
|
147 return; |
|
148 } |
|
149 |
|
150 // Before grabbing more information, be sure the Sync service |
|
151 // is fully initialized. This has the potential to initialize |
|
152 // Sync on the spot. This may be undesired if Sync appears to |
|
153 // be enabled but it really isn't. That responsibility should |
|
154 // be up to svc.enabled to not return false positives, however. |
|
155 yield svc.whenLoaded(); |
|
156 |
|
157 if (Weave.Status.service != Weave.STATUS_OK) { |
|
158 return; |
|
159 } |
|
160 |
|
161 // Device types are dynamic. So we need to dynamically create fields if |
|
162 // they don't exist. |
|
163 let dm = this.getMeasurement(SyncDevicesMeasurement1.prototype.name, |
|
164 SyncDevicesMeasurement1.prototype.version); |
|
165 let devices = Weave.Service.clientsEngine.deviceTypes; |
|
166 for (let [field, count] of devices) { |
|
167 let hasField = this.storage.hasFieldFromMeasurement(dm.id, field, |
|
168 this.storage.FIELD_DAILY_LAST_NUMERIC); |
|
169 let fieldID; |
|
170 if (hasField) { |
|
171 fieldID = this.storage.fieldIDFromMeasurement(dm.id, field); |
|
172 } else { |
|
173 fieldID = yield this.storage.registerField(dm.id, field, |
|
174 this.storage.FIELD_DAILY_LAST_NUMERIC); |
|
175 } |
|
176 |
|
177 yield this.storage.setDailyLastNumericFromFieldID(fieldID, count); |
|
178 } |
|
179 }, |
|
180 }); |