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 Feb. 28, 2015, 3:01 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 * The Service URL that should handle the data
42 * @type String
43 */
44 _serviceURL: "",
45
46 /**
47 * Time since last push
48 * @type Number
49 */
50 _lastPush: 0,
51
52 /**
53 * Indicates the timeframe between pushes
54 * @type Number
55 */
56 _pushInterval: MILLIS_IN_DAY * 7,
57
58 /**
59 * Indicates whether the data are being loaded from storage
60 * @type Boolean
61 */
62 _loading: false,
63
64 /**
65 * Indicates whether the data are being saved to storage
66 * @type Boolean
67 */
68 _saving: false,
69
70 /**
71 * Indicates whether the data are being sent to the server
72 * @type Boolean
73 */
74 _sending: false,
75
76 /**
77 * Increases the filter hit count
78 * @param {Filter} filter
79 * @param {Window} window Window that the match originated in (required to ge t host)
80 */
81 increaseFilterHits: function(filter, wnd)
82 {
83 let subscriptionTitles = [];
84 for (let i = 0; i < filter.subscriptions.length; i++)
85 {
86 if (filter.subscriptions[i] instanceof DownloadableSubscription)
87 subscriptionTitles.push(filter.subscriptions[i]._title)
Thomas Greiner 2015/03/06 11:29:19 See https://issues.adblockplus.org/ticket/394#comm
saroyanm 2015/03/06 16:54:04 Ohh, so stupid from my side :/ Done.
88 }
89
90 if (subscriptionTitles.length == 0)
91 return;
Thomas Greiner 2015/03/06 11:29:19 Rather than constructing an array on each function
saroyanm 2015/03/06 16:54:04 Done.
92
93 if (!(filter.text in this.filters))
94 this.filters[filter.text] = Object.create(null);
95
96 let statFilter = this.filters[filter.text];
97 let filterType = filter.thirdParty ? "thirdParty" : "firstParty";
98
99 if (!(filterType in statFilter))
100 statFilter[filterType] = Object.create(null);
101
102 if (!("subscriptions" in statFilter))
103 statFilter.subscriptions = [];
104
105 for (let i = 0; i < subscriptionTitles.length; i++)
106 {
107 if (statFilter.subscriptions.indexOf(subscriptionTitles[i]) == -1)
108 statFilter.subscriptions.push(subscriptionTitles[i]);
109 }
110
111 let wndLocation = Utils.getOriginWindow(wnd).location.href;
112 let host = Utils.unwrapURL(wndLocation).host;
113
114 if (!(host in statFilter[filterType]))
115 statFilter[filterType][host] = {hits: 1, latest: filter.lastHit};
116 else
117 {
118 statFilter[filterType][host].hits++;
119 statFilter[filterType][host].latest = filter.lastHit;
120 }
121 },
122
123 resetFilterHits: function()
124 {
125 this.filters = Object.create(null);
126 this.saveFilterHitsToDatabase();
127 },
128
129 sendFilterHitsToServer: function()
130 {
131 let request = new XMLHttpRequest();
132 request.open("POST", this._serviceURL);
133 request.setRequestHeader("Content-Type", "application/json");
134 request.addEventListener("load", function(event)
135 {
136 FilterHits._sending = false;
137 if (request.status == 200)
138 {
139 FilterHits._lastPush = new Date().getTime();
140 FilterHits.resetFilterHits();
141 }
142 else
143 Cu.reportError("Could not send filter hit statistics to Adblock Plus ser ver.");
144 }, false);
145
146 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info");
147 let data = {
148 version: 1,
149 timeSincePush: this._lastPush,
150 addonName: addonName,
151 addonVersion: addonVersion,
152 application: application,
153 applicationVersion: applicationVersion,
154 platform: platform,
155 platformVersion: platformVersion,
156 filters: this.filters
157 };
158
159 this._sending = true;
160 request.send(JSON.stringify(data));
161 },
162
163 getStorageFile: function()
164 {
165 return FileUtils.getFile("ProfD", ["adblockplus.sqlite"]);
166 },
167
168 checkCreateTable: function(connection)
169 {
170 if (!connection.tableExists("filterhits"))
171 connection.executeSimpleSQL("CREATE TABLE filterhits (id INTEGER PRIMARY K EY, filters TEXT, date INTEGER)");
172 },
173
174 /**
175 * Load Filter hits from database
176 */
177 loadFilterHitsFromDatabase: function()
178 {
179 let storageFile = this.getStorageFile();
180 if (!storageFile)
181 return;
182
183 let connection = Services.storage.openDatabase(storageFile);
184 this.checkCreateTable(connection);
185
186 let statement = connection.createStatement("SELECT * FROM filterhits");
187 if (!this._loading)
188 {
189 this._loading = true;
190 statement.executeAsync(
191 {
192 handleResult: function(results)
193 {
194 let row = results.getNextRow();
195 if (row)
196 {
197 let filters = row.getResultByName("filters");
198 let lastDate = row.getResultByName("date");
199 FilterHits.filters = JSON.parse(filters);
200 FilterHits._lastPush = lastDate;
201 }
202 },
203
204 handleError: function(error)
205 {
206 Cu.reportError(error.message);
207 },
208
209 handleCompletion: function(reason)
210 {
211 if (reason != Ci.mozIStorageStatementCallback.REASON_FINISHED)
212 Cu.reportError("Loading of filter hits canceled or aborted.");
213 FilterHits._loading = false;
214 }
215 });
216 }
217
218 connection.asyncClose();
219 },
220
221 /**
222 * Save Filter hits to database
223 */
224 saveFilterHitsToDatabase: function()
225 {
226 let now = new Date().getTime();
227 if (!this._lastPush)
228 this._lastPush = now;
229
230 if (!this._sending && now - this._lastPush > this._pushInterval)
231 {
232 this.sendFilterHitsToServer();
233 return;
234 }
235
236 let storageFile = this.getStorageFile();
237 if (!storageFile)
238 return;
239
240 let connection = Services.storage.openDatabase(storageFile);
241 this.checkCreateTable(connection);
242
243 let statement = connection.createStatement("INSERT OR REPLACE INTO filterhit s (id, filters, date) VALUES(0, :filters, :date)");
244 statement.params.filters = JSON.stringify(this.filters);
245 statement.params.date = this._lastPush;
246 if (!this._saving)
247 {
248 this._saving = true;
249 statement.executeAsync(
250 {
251 handleError: function(aError)
252 {
253 Cu.reportError(aError.message);
254 },
255
256 handleCompletion: function(aReason)
257 {
258 if (aReason != Components.interfaces.mozIStorageStatementCallback.REAS ON_FINISHED)
259 Cu.reportError("Writing of filter hits canceled or aborted.");
260 FilterHits._saving = false;
261 }
262 });
263 }
264
265 connection.asyncClose();
266 }
267 };
268
269 FilterNotifier.addListener(function(action)
270 {
271 if (action == "load" && Prefs.sendstats)
272 FilterHits.loadFilterHitsFromDatabase();
273 });
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