Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/filterHits.js

Issue 6337686776315904: Issue 394 - hit statistics tool data collection (Closed)
Patch Set: Created April 7, 2015, 3:15 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « defaults/prefs.js ('k') | lib/filterListener.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 let {Services} = Cu.import("resource://gre/modules/Services.jsm", null);
19 let {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", null);
20
21 let {Prefs} = require("prefs");
22 let {Utils} = require("utils");
23 let {MILLIS_IN_DAY} = require("downloader");
24 let {FilterNotifier} = require("filterNotifier");
25 let {DownloadableSubscription} = require("subscriptionClasses");
26
27 /**
28 * This class reads filter hits statistics from SQLite database,
29 * manages them in memory and writes them back.
30 * @class
31 */
32 let FilterHits = exports.FilterHits =
33 {
34 /**
35 * Data that shoud be sent to the server
36 * @type Object
37 */
38 filters: Object.create(null),
39
40 /**
41 * Time since last push
42 * @type Number
43 */
kzar 2015/04/14 16:33:30 I guess we don't need to document these private va
saroyanm 2015/04/16 10:42:59 Please have a look on current discussion: http://c
kzar 2015/04/16 12:46:26 I disagree on this one, I've been told not to over
saroyanm 2015/04/16 14:08:45 I guess sometimes would be nice to have link to th
44 _lastPush: 0,
45
46 /**
47 * Indicates the timeframe between pushes
48 * @type Number
49 */
50 _pushInterval: MILLIS_IN_DAY * 7,
51
52 /**
53 * Indicates whether the data is being loaded from storage
54 * @type Boolean
55 */
56 _loading: false,
57
58 /**
59 * Indicates whether the data is being saved to storage
60 * @type Boolean
61 */
62 _saving: false,
63
64 /**
65 * Indicates whether the data is being sent to the server
66 * @type Boolean
67 */
68 _sending: false,
69
70 /**
71 * Increases the filter hit count
kzar 2015/04/14 16:33:30 Perhaps "Increases the hit count for the given fil
saroyanm 2015/04/16 10:42:59 No actually the filter in the parameter is the fil
kzar 2015/04/16 12:46:26 I think you've slightly missed my point here. We a
72 * @param {Filter} filter
73 * @param {Window} window Window that the match originated in (required to ge t host)
74 */
75 increaseFilterHits: function(filter, wnd)
kzar 2015/04/14 16:33:30 Maybe we should just make host the parameter here,
saroyanm 2015/04/16 10:42:59 Done.
76 {
77 let subscriptions = filter.subscriptions;
78 let inDownloadableSubscription = false;
79 for (let i = 0; i < subscriptions.length; i++)
80 {
81 if (subscriptions[i] instanceof DownloadableSubscription)
82 {
83 inDownloadableSubscription = true;
84 break;
85 }
86 }
87
88 if (!inDownloadableSubscription)
89 return;
90
91 if (!(filter.text in this.filters))
92 this.filters[filter.text] = Object.create(null);
93
94 let statFilter = this.filters[filter.text];
95 let filterType = filter.thirdParty ? "thirdParty" : "firstParty";
96
97 if (!(filterType in statFilter))
98 statFilter[filterType] = Object.create(null);
99
100 if (!("subscriptions" in statFilter))
101 statFilter.subscriptions = [];
102
103 for (let i = 0; i < subscriptions.length; i++)
104 {
105 if (subscriptions[i] instanceof DownloadableSubscription
106 && statFilter.subscriptions.indexOf(subscriptions[i].url) == -1)
107 statFilter.subscriptions.push(subscriptions[i].url);
108 }
109
110 let wndLocation = Utils.getOriginWindow(wnd).location.href;
111 let host = Utils.unwrapURL(wndLocation).host;
112
113 if (!(host in statFilter[filterType]))
114 statFilter[filterType][host] = {hits: 1, latest: filter.lastHit};
kzar 2015/04/14 16:33:30 I think we're supposed to use braces consistently
saroyanm 2015/04/16 10:42:59 I'm not sure if be honest, I can see your point, b
kzar 2015/04/16 12:46:26 I've definitely been told that the braces should b
saroyanm 2015/04/16 14:08:45 Would be nice to have some reference for future, f
115 else
116 {
117 statFilter[filterType][host].hits++;
118 statFilter[filterType][host].latest = filter.lastHit;
119 }
120 },
121
122 resetFilterHits: function()
123 {
124 this.filters = Object.create(null);
125 this.saveFilterHitsToDatabase();
126 },
127
128 sendFilterHitsToServer: function()
129 {
130 if (!Prefs.sendstats)
131 return;
132
133 let request = new XMLHttpRequest();
134 request.open("POST", Prefs.sendstats_url);
135 request.setRequestHeader("Content-Type", "application/json");
136 request.addEventListener("load", function(event)
137 {
138 FilterHits._sending = false;
139 if (request.status >= 200 && request.status < 300)
140 {
141 FilterHits._lastPush = new Date().getTime();
142 FilterHits.resetFilterHits();
143 }
144 else
kzar 2015/04/14 16:33:30 Again here with the if...else brace consistency. P
saroyanm 2015/04/16 10:42:59 Same as my reply above.
145 Cu.reportError("Could not send filter hit statistics to Adblock Plus ser ver.");
kzar 2015/04/14 16:33:30 If sending fails and it's the server's fault / a c
saroyanm 2015/04/16 10:42:59 Yes, but it depends on filterStorage action. Her
146 }, false);
147
148 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info");
kzar 2015/04/14 16:33:30 Possible to add a newline in this list? It seems l
saroyanm 2015/04/16 10:42:59 Couldn't find any documentation that explicitly sa
kzar 2015/04/16 12:46:26 It is possible, I was just being polite. (British
saroyanm 2015/04/16 14:08:45 Ha ha :) That's funny :D
149 let data = {
150 version: 1,
151 timeSincePush: this._lastPush,
152 addonName: addonName,
153 addonVersion: addonVersion,
154 application: application,
155 applicationVersion: applicationVersion,
156 platform: platform,
157 platformVersion: platformVersion,
158 filters: this.filters
159 };
160
161 this._sending = true;
162 request.send(JSON.stringify(data));
163 },
164
165 getStorageFile: function()
166 {
167 return FileUtils.getFile("ProfD", ["adblockplus.sqlite"]);
168 },
169
170 checkCreateTable: function(connection)
171 {
172 if (!connection.tableExists("filterhits"))
173 connection.executeSimpleSQL("CREATE TABLE filterhits (id INTEGER PRIMARY K EY, filters TEXT, date INTEGER)");
174 },
175
176 /**
177 * Load Filter hits from database
178 */
179 loadFilterHitsFromDatabase: function()
180 {
181 let storageFile = this.getStorageFile();
182 if (!storageFile)
183 return;
184
185 let connection = Services.storage.openDatabase(storageFile);
186 this.checkCreateTable(connection);
187
188 let statement = connection.createStatement("SELECT * FROM filterhits");
189 if (!this._loading)
190 {
191 this._loading = true;
192 statement.executeAsync(
193 {
194 handleResult: function(results)
195 {
196 let row = results.getNextRow();
197 if (row)
198 {
199 let filters = row.getResultByName("filters");
200 let lastDate = row.getResultByName("date");
201 FilterHits.filters = JSON.parse(filters);
kzar 2015/04/14 16:33:30 We are serialising some of the data into JSON and
saroyanm 2015/04/16 10:42:59 The idea was to use Storage API which is actually
kzar 2015/04/16 12:46:26 Well it just seems like a hack to mix them both to
202 FilterHits._lastPush = lastDate;
203 }
204 },
205
206 handleError: function(error)
207 {
208 Cu.reportError(error.message);
209 },
210
211 handleCompletion: function(reason)
212 {
213 if (reason != Ci.mozIStorageStatementCallback.REASON_FINISHED)
214 Cu.reportError("Loading of filter hits canceled or aborted.");
215 FilterHits._loading = false;
216 }
217 });
218 }
219
220 connection.asyncClose();
221 },
222
223 /**
224 * Save Filter hits to database
225 */
226 saveFilterHitsToDatabase: function()
227 {
228 let now = new Date().getTime();
229 if (!this._lastPush)
230 this._lastPush = now;
231
232 if (!this._sending && now - this._lastPush > this._pushInterval)
kzar 2015/04/14 16:33:30 I think that perhaps the logic here for sending th
saroyanm 2015/04/16 10:42:59 Yes you are right this should go elsewhere, but b
kzar 2015/04/16 12:46:26 The geometrical mean calculation on the server tak
233 {
234 this.sendFilterHitsToServer();
kzar 2015/04/14 16:33:30 If we are going to perform the web request here sh
saroyanm 2015/04/16 10:42:59 Yes it doesn't because after the successful postin
kzar 2015/04/16 12:46:26 I guess we can ignore this one for now as it will
saroyanm 2015/04/16 14:08:45 Yes agree.
235 return;
236 }
237
238 let storageFile = this.getStorageFile();
239 if (!storageFile)
240 return;
241
242 let connection = Services.storage.openDatabase(storageFile);
243 this.checkCreateTable(connection);
244
245 let statement = connection.createStatement("INSERT OR REPLACE INTO filterhit s (id, filters, date) VALUES(0, :filters, :date)");
246 statement.params.filters = JSON.stringify(this.filters);
247 statement.params.date = this._lastPush;
248 if (!this._saving)
249 {
250 this._saving = true;
251 statement.executeAsync(
252 {
253 handleError: function(aError)
254 {
255 Cu.reportError(aError.message);
256 },
257
258 handleCompletion: function(aReason)
259 {
260 if (aReason != Components.interfaces.mozIStorageStatementCallback.REAS ON_FINISHED)
261 Cu.reportError("Writing of filter hits canceled or aborted.");
262 FilterHits._saving = false;
263 }
264 });
265 }
266
267 connection.asyncClose();
268 }
269 };
270
271 FilterNotifier.addListener(function(action)
272 {
273 if (action == "load" && Prefs.sendstats)
274 FilterHits.loadFilterHitsFromDatabase();
275 });
OLDNEW
« no previous file with comments | « defaults/prefs.js ('k') | lib/filterListener.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld