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

Side by Side Diff: lib/filterStorage.js

Issue 29375915: Issue 4878 - Start using ESLint for adblockpluscore (Closed)
Patch Set: Created Feb. 20, 2017, 10:02 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 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/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 /* globals FileUtils, Services */
19
20 "use strict";
21
18 /** 22 /**
19 * @fileOverview FilterStorage class responsible for managing user's subscriptio ns and filters. 23 * @fileOverview FilterStorage class responsible for managing user's
24 * subscriptions and filters.
20 */ 25 */
21 26
22 Cu.import("resource://gre/modules/Services.jsm"); 27 Cu.import("resource://gre/modules/Services.jsm");
23 Cu.import("resource://gre/modules/FileUtils.jsm"); 28 Cu.import("resource://gre/modules/FileUtils.jsm");
24 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 29 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
25 30
26 let {IO} = require("io"); 31 let {IO} = require("io");
27 let {Prefs} = require("prefs"); 32 let {Prefs} = require("prefs");
28 let {Filter, ActiveFilter} = require("filterClasses"); 33 let {Filter, ActiveFilter} = require("filterClasses");
29 let {Subscription, SpecialSubscription, ExternalSubscription} = require("subscri ptionClasses"); 34 let {Subscription, SpecialSubscription,
35 ExternalSubscription} = require("subscriptionClasses");
30 let {FilterNotifier} = require("filterNotifier"); 36 let {FilterNotifier} = require("filterNotifier");
31 let {Utils} = require("utils"); 37 let {Utils} = require("utils");
32 38
33 /** 39 /**
34 * Version number of the filter storage file format. 40 * Version number of the filter storage file format.
35 * @type Integer 41 * @type {Integer}
36 */ 42 */
37 let formatVersion = 4; 43 let formatVersion = 4;
38 44
39 /** 45 /**
40 * This class reads user's filters from disk, manages them in memory and writes them back. 46 * This class reads user's filters from disk, manages them in memory
47 * and writes them back.
41 * @class 48 * @class
42 */ 49 */
43 let FilterStorage = exports.FilterStorage = 50 let FilterStorage = exports.FilterStorage =
44 { 51 {
45 /** 52 /**
46 * Version number of the patterns.ini format used. 53 * Version number of the patterns.ini format used.
47 * @type Integer 54 * @type {Integer}
48 */ 55 */
49 get formatVersion() 56 get formatVersion()
50 { 57 {
51 return formatVersion; 58 return formatVersion;
52 }, 59 },
53 60
54 /** 61 /**
55 * File that the filter list has been loaded from and should be saved to 62 * File that the filter list has been loaded from and should be saved to
56 * @type nsIFile 63 * @type {nsIFile}
57 */ 64 */
58 get sourceFile() 65 get sourceFile()
59 { 66 {
60 let file = null; 67 let file = null;
61 if (Prefs.patternsfile) 68 if (Prefs.patternsfile)
62 { 69 {
63 // Override in place, use it instead of placing the file in the regular da ta dir 70 // Override in place, use it instead of placing the file in the
71 // regular data dir
64 file = IO.resolveFilePath(Prefs.patternsfile); 72 file = IO.resolveFilePath(Prefs.patternsfile);
65 } 73 }
66 if (!file) 74 if (!file)
67 { 75 {
68 // Place the file in the data dir 76 // Place the file in the data dir
69 file = IO.resolveFilePath(Prefs.data_directory); 77 file = IO.resolveFilePath(Prefs.data_directory);
70 if (file) 78 if (file)
71 file.append("patterns.ini"); 79 file.append("patterns.ini");
72 } 80 }
73 if (!file) 81 if (!file)
74 { 82 {
75 // Data directory pref misconfigured? Try the default value 83 // Data directory pref misconfigured? Try the default value
76 try 84 try
77 { 85 {
78 file = IO.resolveFilePath(Services.prefs.getDefaultBranch("extensions.ad blockplus.").getCharPref("data_directory")); 86 file = IO.resolveFilePath(
87 Services.prefs.getDefaultBranch("extensions.adblockplus."
88 ).getCharPref("data_directory"));
79 if (file) 89 if (file)
80 file.append("patterns.ini"); 90 file.append("patterns.ini");
81 } catch(e) {} 91 }
92 catch (e) {}
82 } 93 }
83 94
84 if (!file) 95 if (!file)
85 Cu.reportError("Adblock Plus: Failed to resolve filter file location from extensions.adblockplus.patternsfile preference"); 96 {
97 Cu.reportError("Adblock Plus: Failed to resolve filter file location " +
98 "from extensions.adblockplus.patternsfile preference");
99 }
86 100
87 // Property is configurable because of the test suite. 101 // Property is configurable because of the test suite.
88 Object.defineProperty(this, "sourceFile", {value: file, configurable: true}) ; 102 Object.defineProperty(this, "sourceFile",
103 {value: file, configurable: true});
89 return file; 104 return file;
90 }, 105 },
91 106
92 /** 107 /**
93 * Will be set to true if no patterns.ini file exists. 108 * Will be set to true if no patterns.ini file exists.
94 * @type Boolean 109 * @type {Boolean}
95 */ 110 */
96 firstRun: false, 111 firstRun: false,
97 112
98 /** 113 /**
99 * Map of properties listed in the filter storage file before the sections 114 * Map of properties listed in the filter storage file before the sections
100 * start. Right now this should be only the format version. 115 * start. Right now this should be only the format version.
101 */ 116 */
102 fileProperties: Object.create(null), 117 fileProperties: Object.create(null),
103 118
104 /** 119 /**
105 * List of filter subscriptions containing all filters 120 * List of filter subscriptions containing all filters
106 * @type Subscription[] 121 * @type {Subscription[]}
107 */ 122 */
108 subscriptions: [], 123 subscriptions: [],
109 124
110 /** 125 /**
111 * Map of subscriptions already on the list, by their URL/identifier 126 * Map of subscriptions already on the list, by their URL/identifier
112 * @type Object 127 * @type {Object}
113 */ 128 */
114 knownSubscriptions: Object.create(null), 129 knownSubscriptions: Object.create(null),
115 130
116 /** 131 /**
117 * Finds the filter group that a filter should be added to by default. Will 132 * Finds the filter group that a filter should be added to by default. Will
118 * return null if this group doesn't exist yet. 133 * return null if this group doesn't exist yet.
134 * @param {Filter} filter
135 * @return {SpecialSubscription|null}
119 */ 136 */
120 getGroupForFilter: function(/**Filter*/ filter) /**SpecialSubscription*/ 137 getGroupForFilter(filter)
121 { 138 {
122 let generalSubscription = null; 139 let generalSubscription = null;
123 for (let subscription of FilterStorage.subscriptions) 140 for (let subscription of FilterStorage.subscriptions)
124 { 141 {
125 if (subscription instanceof SpecialSubscription && !subscription.disabled) 142 if (subscription instanceof SpecialSubscription && !subscription.disabled)
126 { 143 {
127 // Always prefer specialized subscriptions 144 // Always prefer specialized subscriptions
128 if (subscription.isDefaultFor(filter)) 145 if (subscription.isDefaultFor(filter))
129 return subscription; 146 return subscription;
130 147
131 // If this is a general subscription - store it as fallback 148 // If this is a general subscription - store it as fallback
132 if (!generalSubscription && (!subscription.defaults || !subscription.def aults.length)) 149 if (!generalSubscription &&
150 (!subscription.defaults || !subscription.defaults.length))
133 generalSubscription = subscription; 151 generalSubscription = subscription;
134 } 152 }
135 } 153 }
136 return generalSubscription; 154 return generalSubscription;
137 }, 155 },
138 156
139 /** 157 /**
140 * Adds a filter subscription to the list 158 * Adds a filter subscription to the list
141 * @param {Subscription} subscription filter subscription to be added 159 * @param {Subscription} subscription filter subscription to be added
142 * @param {Boolean} silent if true, no listeners will be triggered (to be use d when filter list is reloaded) 160 * @param {Boolean} silent if true, no listeners will be triggered
161 * (to be used when filter list is reloaded)
143 */ 162 */
144 addSubscription: function(subscription, silent) 163 addSubscription(subscription, silent)
145 { 164 {
146 if (subscription.url in FilterStorage.knownSubscriptions) 165 if (subscription.url in FilterStorage.knownSubscriptions)
147 return; 166 return;
148 167
149 FilterStorage.subscriptions.push(subscription); 168 FilterStorage.subscriptions.push(subscription);
150 FilterStorage.knownSubscriptions[subscription.url] = subscription; 169 FilterStorage.knownSubscriptions[subscription.url] = subscription;
151 addSubscriptionFilters(subscription); 170 addSubscriptionFilters(subscription);
152 171
153 if (!silent) 172 if (!silent)
154 FilterNotifier.triggerListeners("subscription.added", subscription); 173 FilterNotifier.triggerListeners("subscription.added", subscription);
155 }, 174 },
156 175
157 /** 176 /**
158 * Removes a filter subscription from the list 177 * Removes a filter subscription from the list
159 * @param {Subscription} subscription filter subscription to be removed 178 * @param {Subscription} subscription filter subscription to be removed
160 * @param {Boolean} silent if true, no listeners will be triggered (to be use d when filter list is reloaded) 179 * @param {Boolean} silent if true, no listeners will be triggered
180 * (to be used when filter list is reloaded)
161 */ 181 */
162 removeSubscription: function(subscription, silent) 182 removeSubscription(subscription, silent)
163 { 183 {
164 for (let i = 0; i < FilterStorage.subscriptions.length; i++) 184 for (let i = 0; i < FilterStorage.subscriptions.length; i++)
165 { 185 {
166 if (FilterStorage.subscriptions[i].url == subscription.url) 186 if (FilterStorage.subscriptions[i].url == subscription.url)
167 { 187 {
168 removeSubscriptionFilters(subscription); 188 removeSubscriptionFilters(subscription);
169 189
170 FilterStorage.subscriptions.splice(i--, 1); 190 FilterStorage.subscriptions.splice(i--, 1);
171 delete FilterStorage.knownSubscriptions[subscription.url]; 191 delete FilterStorage.knownSubscriptions[subscription.url];
172 if (!silent) 192 if (!silent)
173 FilterNotifier.triggerListeners("subscription.removed", subscription); 193 FilterNotifier.triggerListeners("subscription.removed", subscription);
174 return; 194 return;
175 } 195 }
176 } 196 }
177 }, 197 },
178 198
179 /** 199 /**
180 * Moves a subscription in the list to a new position. 200 * Moves a subscription in the list to a new position.
181 * @param {Subscription} subscription filter subscription to be moved 201 * @param {Subscription} subscription filter subscription to be moved
182 * @param {Subscription} [insertBefore] filter subscription to insert before 202 * @param {Subscription} [insertBefore] filter subscription to insert before
183 * (if omitted the subscription will be put at the end of the list) 203 * (if omitted the subscription will be put at the end of the list)
184 */ 204 */
185 moveSubscription: function(subscription, insertBefore) 205 moveSubscription(subscription, insertBefore)
186 { 206 {
187 let currentPos = FilterStorage.subscriptions.indexOf(subscription); 207 let currentPos = FilterStorage.subscriptions.indexOf(subscription);
188 if (currentPos < 0) 208 if (currentPos < 0)
189 return; 209 return;
190 210
191 let newPos = insertBefore ? FilterStorage.subscriptions.indexOf(insertBefore ) : -1; 211 let newPos = -1;
212 if (insertBefore)
213 newPos = FilterStorage.subscriptions.indexOf(insertBefore);
214
192 if (newPos < 0) 215 if (newPos < 0)
193 newPos = FilterStorage.subscriptions.length; 216 newPos = FilterStorage.subscriptions.length;
194 217
195 if (currentPos < newPos) 218 if (currentPos < newPos)
196 newPos--; 219 newPos--;
197 if (currentPos == newPos) 220 if (currentPos == newPos)
198 return; 221 return;
199 222
200 FilterStorage.subscriptions.splice(currentPos, 1); 223 FilterStorage.subscriptions.splice(currentPos, 1);
201 FilterStorage.subscriptions.splice(newPos, 0, subscription); 224 FilterStorage.subscriptions.splice(newPos, 0, subscription);
202 FilterNotifier.triggerListeners("subscription.moved", subscription); 225 FilterNotifier.triggerListeners("subscription.moved", subscription);
203 }, 226 },
204 227
205 /** 228 /**
206 * Replaces the list of filters in a subscription by a new list 229 * Replaces the list of filters in a subscription by a new list
207 * @param {Subscription} subscription filter subscription to be updated 230 * @param {Subscription} subscription filter subscription to be updated
208 * @param {Filter[]} filters new filter list 231 * @param {Filter[]} filters new filter list
209 */ 232 */
210 updateSubscriptionFilters: function(subscription, filters) 233 updateSubscriptionFilters(subscription, filters)
211 { 234 {
212 removeSubscriptionFilters(subscription); 235 removeSubscriptionFilters(subscription);
213 subscription.oldFilters = subscription.filters; 236 subscription.oldFilters = subscription.filters;
214 subscription.filters = filters; 237 subscription.filters = filters;
215 addSubscriptionFilters(subscription); 238 addSubscriptionFilters(subscription);
216 FilterNotifier.triggerListeners("subscription.updated", subscription); 239 FilterNotifier.triggerListeners("subscription.updated", subscription);
217 delete subscription.oldFilters; 240 delete subscription.oldFilters;
218 }, 241 },
219 242
220 /** 243 /**
221 * Adds a user-defined filter to the list 244 * Adds a user-defined filter to the list
222 * @param {Filter} filter 245 * @param {Filter} filter
223 * @param {SpecialSubscription} [subscription] particular group that the filte r should be added to 246 * @param {SpecialSubscription} [subscription] particular group that the
224 * @param {Integer} [position] position within the subscription at which the f ilter should be added 247 * filter should be added to
225 * @param {Boolean} silent if true, no listeners will be triggered (to be use d when filter list is reloaded) 248 * @param {Integer} [position] position within the subscription at which
249 * the filter should be added
250 * @param {Boolean} silent if true, no listeners will be triggered (to
251 * be used when filter list is reloaded)
226 */ 252 */
227 addFilter: function(filter, subscription, position, silent) 253 addFilter(filter, subscription, position, silent)
228 { 254 {
229 if (!subscription) 255 if (!subscription)
230 { 256 {
231 if (filter.subscriptions.some(s => s instanceof SpecialSubscription && !s. disabled)) 257 if (filter.subscriptions.some(s => s instanceof SpecialSubscription &&
258 !s.disabled))
232 return; // No need to add 259 return; // No need to add
233 subscription = FilterStorage.getGroupForFilter(filter); 260 subscription = FilterStorage.getGroupForFilter(filter);
234 } 261 }
235 if (!subscription) 262 if (!subscription)
236 { 263 {
237 // No group for this filter exists, create one 264 // No group for this filter exists, create one
238 subscription = SpecialSubscription.createForFilter(filter); 265 subscription = SpecialSubscription.createForFilter(filter);
239 this.addSubscription(subscription); 266 this.addSubscription(subscription);
240 return; 267 return;
241 } 268 }
242 269
243 if (typeof position == "undefined") 270 if (typeof position == "undefined")
244 position = subscription.filters.length; 271 position = subscription.filters.length;
245 272
246 if (filter.subscriptions.indexOf(subscription) < 0) 273 if (filter.subscriptions.indexOf(subscription) < 0)
247 filter.subscriptions.push(subscription); 274 filter.subscriptions.push(subscription);
248 subscription.filters.splice(position, 0, filter); 275 subscription.filters.splice(position, 0, filter);
249 if (!silent) 276 if (!silent)
250 FilterNotifier.triggerListeners("filter.added", filter, subscription, posi tion); 277 {
278 FilterNotifier.triggerListeners("filter.added", filter, subscription,
279 position);
280 }
251 }, 281 },
252 282
253 /** 283 /**
254 * Removes a user-defined filter from the list 284 * Removes a user-defined filter from the list
255 * @param {Filter} filter 285 * @param {Filter} filter
256 * @param {SpecialSubscription} [subscription] a particular filter group that 286 * @param {SpecialSubscription} [subscription] a particular filter group that
257 * the filter should be removed from (if ommited will be removed from all subscriptions) 287 * the filter should be removed from (if ommited will be removed from all
288 * subscriptions)
258 * @param {Integer} [position] position inside the filter group at which the 289 * @param {Integer} [position] position inside the filter group at which the
259 * filter should be removed (if ommited all instances will be removed) 290 * filter should be removed (if ommited all instances will be removed)
260 */ 291 */
261 removeFilter: function(filter, subscription, position) 292 removeFilter(filter, subscription, position)
262 { 293 {
263 let subscriptions = (subscription ? [subscription] : filter.subscriptions.sl ice()); 294 let subscriptions = (
295 subscription ? [subscription] : filter.subscriptions.slice()
296 );
264 for (let i = 0; i < subscriptions.length; i++) 297 for (let i = 0; i < subscriptions.length; i++)
265 { 298 {
266 let subscription = subscriptions[i]; 299 let currentSubscription = subscriptions[i];
267 if (subscription instanceof SpecialSubscription) 300 if (currentSubscription instanceof SpecialSubscription)
268 { 301 {
269 let positions = []; 302 let positions = [];
270 if (typeof position == "undefined") 303 if (typeof position == "undefined")
271 { 304 {
272 let index = -1; 305 let index = -1;
273 do 306 do
274 { 307 {
275 index = subscription.filters.indexOf(filter, index + 1); 308 index = currentSubscription.filters.indexOf(filter, index + 1);
276 if (index >= 0) 309 if (index >= 0)
277 positions.push(index); 310 positions.push(index);
278 } while (index >= 0); 311 } while (index >= 0);
279 } 312 }
280 else 313 else
281 positions.push(position); 314 positions.push(position);
282 315
283 for (let j = positions.length - 1; j >= 0; j--) 316 for (let j = positions.length - 1; j >= 0; j--)
284 { 317 {
285 let position = positions[j]; 318 let currentPosition = positions[j];
286 if (subscription.filters[position] == filter) 319 if (currentSubscription.filters[currentPosition] == filter)
287 { 320 {
288 subscription.filters.splice(position, 1); 321 currentSubscription.filters.splice(currentPosition, 1);
289 if (subscription.filters.indexOf(filter) < 0) 322 if (currentSubscription.filters.indexOf(filter) < 0)
290 { 323 {
291 let index = filter.subscriptions.indexOf(subscription); 324 let index = filter.subscriptions.indexOf(currentSubscription);
292 if (index >= 0) 325 if (index >= 0)
293 filter.subscriptions.splice(index, 1); 326 filter.subscriptions.splice(index, 1);
294 } 327 }
295 FilterNotifier.triggerListeners("filter.removed", filter, subscripti on, position); 328 FilterNotifier.triggerListeners(
329 "filter.removed", filter, currentSubscription, currentPosition
330 );
296 } 331 }
297 } 332 }
298 } 333 }
299 } 334 }
300 }, 335 },
301 336
302 /** 337 /**
303 * Moves a user-defined filter to a new position 338 * Moves a user-defined filter to a new position
304 * @param {Filter} filter 339 * @param {Filter} filter
305 * @param {SpecialSubscription} subscription filter group where the filter is located 340 * @param {SpecialSubscription} subscription filter group where the filter is
341 * located
306 * @param {Integer} oldPosition current position of the filter 342 * @param {Integer} oldPosition current position of the filter
307 * @param {Integer} newPosition new position of the filter 343 * @param {Integer} newPosition new position of the filter
308 */ 344 */
309 moveFilter: function(filter, subscription, oldPosition, newPosition) 345 moveFilter(filter, subscription, oldPosition, newPosition)
310 { 346 {
311 if (!(subscription instanceof SpecialSubscription) || subscription.filters[o ldPosition] != filter) 347 if (!(subscription instanceof SpecialSubscription) ||
348 subscription.filters[oldPosition] != filter)
312 return; 349 return;
313 350
314 newPosition = Math.min(Math.max(newPosition, 0), subscription.filters.length - 1); 351 newPosition = Math.min(Math.max(newPosition, 0),
352 subscription.filters.length - 1);
315 if (oldPosition == newPosition) 353 if (oldPosition == newPosition)
316 return; 354 return;
317 355
318 subscription.filters.splice(oldPosition, 1); 356 subscription.filters.splice(oldPosition, 1);
319 subscription.filters.splice(newPosition, 0, filter); 357 subscription.filters.splice(newPosition, 0, filter);
320 FilterNotifier.triggerListeners("filter.moved", filter, subscription, oldPos ition, newPosition); 358 FilterNotifier.triggerListeners("filter.moved", filter, subscription,
359 oldPosition, newPosition);
321 }, 360 },
322 361
323 /** 362 /**
324 * Increases the hit count for a filter by one 363 * Increases the hit count for a filter by one
325 * @param {Filter} filter 364 * @param {Filter} filter
326 */ 365 */
327 increaseHitCount: function(filter) 366 increaseHitCount(filter)
328 { 367 {
329 if (!Prefs.savestats || !(filter instanceof ActiveFilter)) 368 if (!Prefs.savestats || !(filter instanceof ActiveFilter))
330 return; 369 return;
331 370
332 filter.hitCount++; 371 filter.hitCount++;
333 filter.lastHit = Date.now(); 372 filter.lastHit = Date.now();
334 }, 373 },
335 374
336 /** 375 /**
337 * Resets hit count for some filters 376 * Resets hit count for some filters
338 * @param {Filter[]} filters filters to be reset, if null all filters will be reset 377 * @param {Filter[]} filters filters to be reset, if null all filters will
378 * be reset
339 */ 379 */
340 resetHitCounts: function(filters) 380 resetHitCounts(filters)
341 { 381 {
342 if (!filters) 382 if (!filters)
343 { 383 {
344 filters = []; 384 filters = [];
345 for (let text in Filter.knownFilters) 385 for (let text in Filter.knownFilters)
346 filters.push(Filter.knownFilters[text]); 386 filters.push(Filter.knownFilters[text]);
347 } 387 }
348 for (let filter of filters) 388 for (let filter of filters)
349 { 389 {
350 filter.hitCount = 0; 390 filter.hitCount = 0;
351 filter.lastHit = 0; 391 filter.lastHit = 0;
352 } 392 }
353 }, 393 },
354 394
355 _loading: false, 395 _loading: false,
356 396
357 /** 397 /**
358 * Loads all subscriptions from the disk 398 * Loads all subscriptions from the disk
359 * @param {nsIFile} [sourceFile] File to read from 399 * @param {nsIFile} [sourceFile] File to read from
360 */ 400 */
361 loadFromDisk: function(sourceFile) 401 loadFromDisk(sourceFile)
362 { 402 {
363 if (this._loading) 403 if (this._loading)
364 return; 404 return;
365 405
366 this._loading = true; 406 this._loading = true;
367 407
368 let readFile = function(sourceFile, backupIndex) 408 let readFile = function(currentSourceFile, backupIndex)
369 { 409 {
370 let parser = new INIParser(); 410 let parser = new INIParser();
371 IO.readFromFile(sourceFile, parser, function(e) 411 IO.readFromFile(currentSourceFile, parser, readFromFileException =>
372 { 412 {
373 if (!e && parser.subscriptions.length == 0) 413 if (!readFromFileException && parser.subscriptions.length == 0)
374 { 414 {
375 // No filter subscriptions in the file, this isn't right. 415 // No filter subscriptions in the file, this isn't right.
376 e = new Error("No data in the file"); 416 readFromFileException = new Error("No data in the file");
377 } 417 }
378 418
379 if (e) 419 if (readFromFileException)
380 Cu.reportError(e); 420 Cu.reportError(readFromFileException);
381 421
382 if (e && !explicitFile) 422 if (readFromFileException && !explicitFile)
383 { 423 {
384 // Attempt to load a backup 424 // Attempt to load a backup
385 sourceFile = this.sourceFile; 425 currentSourceFile = this.sourcefile;
386 if (sourceFile) 426 if (currentSourceFile)
387 { 427 {
388 let [, part1, part2] = /^(.*)(\.\w+)$/.exec(sourceFile.leafName) || [null, sourceFile.leafName, ""]; 428 let [, part1, part2] = /^(.*)(\.\w+)$/.exec(
429 currentSourceFile.leafName
430 ) || [null, currentSourceFile.leafName, ""];
389 431
390 sourceFile = sourceFile.clone(); 432 currentSourceFile = currentSourceFile.clone();
391 sourceFile.leafName = part1 + "-backup" + (++backupIndex) + part2; 433 currentSourceFile.leafName = (
434 part1 + "-backup" + (++backupIndex) + part2
435 );
392 436
393 IO.statFile(sourceFile, function(e, statData) 437 IO.statFile(currentSourceFile, (statFileException, statData) =>
394 { 438 {
395 if (!e && statData.exists) 439 if (!statFileException && statData.exists)
396 readFile(sourceFile, backupIndex); 440 readFile(currentSourceFile, backupIndex);
397 else 441 else
398 doneReading(parser); 442 doneReading(parser);
399 }); 443 });
400 return; 444 return;
401 } 445 }
402 } 446 }
403 doneReading(parser); 447 doneReading(parser);
404 }.bind(this)); 448 });
405 }.bind(this); 449 }.bind(this);
406 450
407 var doneReading = function(parser) 451 let doneReading = function(parser)
408 { 452 {
409 // Old special groups might have been converted, remove them if they are e mpty 453 // Old special groups might have been converted, remove them if
454 // they are empty
410 let specialMap = {"~il~": true, "~wl~": true, "~fl~": true, "~eh~": true}; 455 let specialMap = {"~il~": true, "~wl~": true, "~fl~": true, "~eh~": true};
411 let knownSubscriptions = Object.create(null); 456 let knownSubscriptions = Object.create(null);
412 for (let i = 0; i < parser.subscriptions.length; i++) 457 for (let i = 0; i < parser.subscriptions.length; i++)
413 { 458 {
414 let subscription = parser.subscriptions[i]; 459 let subscription = parser.subscriptions[i];
415 if (subscription instanceof SpecialSubscription && subscription.filters. length == 0 && subscription.url in specialMap) 460 if (subscription instanceof SpecialSubscription &&
461 subscription.filters.length == 0 && subscription.url in specialMap)
416 parser.subscriptions.splice(i--, 1); 462 parser.subscriptions.splice(i--, 1);
417 else 463 else
418 knownSubscriptions[subscription.url] = subscription; 464 knownSubscriptions[subscription.url] = subscription;
419 } 465 }
420 466
421 this.fileProperties = parser.fileProperties; 467 this.fileProperties = parser.fileProperties;
422 this.subscriptions = parser.subscriptions; 468 this.subscriptions = parser.subscriptions;
423 this.knownSubscriptions = knownSubscriptions; 469 this.knownSubscriptions = knownSubscriptions;
424 Filter.knownFilters = parser.knownFilters; 470 Filter.knownFilters = parser.knownFilters;
425 Subscription.knownSubscriptions = parser.knownSubscriptions; 471 Subscription.knownSubscriptions = parser.knownSubscriptions;
426 472
427 if (parser.userFilters) 473 if (parser.userFilters)
428 { 474 {
429 for (let i = 0; i < parser.userFilters.length; i++) 475 for (let i = 0; i < parser.userFilters.length; i++)
430 { 476 {
431 let filter = Filter.fromText(parser.userFilters[i]); 477 let filter = Filter.fromText(parser.userFilters[i]);
432 this.addFilter(filter, null, undefined, true); 478 this.addFilter(filter, null, undefined, true);
433 } 479 }
434 } 480 }
435 481
436 this._loading = false; 482 this._loading = false;
437 FilterNotifier.triggerListeners("load"); 483 FilterNotifier.triggerListeners("load");
438 484
439 if (sourceFile != this.sourceFile) 485 if (sourceFile != this.sourceFile)
440 this.saveToDisk(); 486 this.saveToDisk();
441
442 }.bind(this); 487 }.bind(this);
443 488
444 let explicitFile; 489 let explicitFile;
445 if (sourceFile) 490 if (sourceFile)
446 { 491 {
447 explicitFile = true; 492 explicitFile = true;
448 readFile(sourceFile, 0); 493 readFile(sourceFile, 0);
449 } 494 }
450 else 495 else
451 { 496 {
452 explicitFile = false; 497 explicitFile = false;
453 sourceFile = FilterStorage.sourceFile; 498 ({sourceFile} = FilterStorage);
454 499
455 let callback = function(e, statData) 500 let callback = function(e, statData)
456 { 501 {
457 if (e || !statData.exists) 502 if (e || !statData.exists)
458 { 503 {
459 this.firstRun = true; 504 this.firstRun = true;
460 this._loading = false; 505 this._loading = false;
461 FilterNotifier.triggerListeners("load"); 506 FilterNotifier.triggerListeners("load");
462 } 507 }
463 else 508 else
464 readFile(sourceFile, 0); 509 readFile(sourceFile, 0);
465 }.bind(this); 510 }.bind(this);
466 511
467 if (sourceFile) 512 if (sourceFile)
468 IO.statFile(sourceFile, callback); 513 IO.statFile(sourceFile, callback);
469 else 514 else
470 callback(true); 515 callback(true);
471 } 516 }
472 }, 517 },
473 518
474 _generateFilterData: function*(subscriptions) 519 *_generateFilterData(subscriptions)
475 { 520 {
476 yield "# Adblock Plus preferences"; 521 yield "# Adblock Plus preferences";
477 yield "version=" + formatVersion; 522 yield "version=" + formatVersion;
478 523
479 let saved = Object.create(null); 524 let saved = Object.create(null);
480 let buf = []; 525 let buf = [];
481 526
482 // Save filter data 527 // Save filter data
483 for (let i = 0; i < subscriptions.length; i++) 528 for (let i = 0; i < subscriptions.length; i++)
484 { 529 {
(...skipping 15 matching lines...) Expand all
500 // Save subscriptions 545 // Save subscriptions
501 for (let i = 0; i < subscriptions.length; i++) 546 for (let i = 0; i < subscriptions.length; i++)
502 { 547 {
503 let subscription = subscriptions[i]; 548 let subscription = subscriptions[i];
504 549
505 yield ""; 550 yield "";
506 551
507 subscription.serialize(buf); 552 subscription.serialize(buf);
508 if (subscription.filters.length) 553 if (subscription.filters.length)
509 { 554 {
510 buf.push("", "[Subscription filters]") 555 buf.push("", "[Subscription filters]");
511 subscription.serializeFilters(buf); 556 subscription.serializeFilters(buf);
512 } 557 }
513 for (let k = 0; k < buf.length; k++) 558 for (let k = 0; k < buf.length; k++)
514 yield buf[k]; 559 yield buf[k];
515 buf.splice(0); 560 buf.splice(0);
516 } 561 }
517 }, 562 },
518 563
519 /** 564 /**
520 * Will be set to true if saveToDisk() is running (reentrance protection). 565 * Will be set to true if saveToDisk() is running (reentrance protection).
521 * @type Boolean 566 * @type {Boolean}
522 */ 567 */
523 _saving: false, 568 _saving: false,
524 569
525 /** 570 /**
526 * Will be set to true if a saveToDisk() call arrives while saveToDisk() is 571 * Will be set to true if a saveToDisk() call arrives while saveToDisk() is
527 * already running (delayed execution). 572 * already running (delayed execution).
528 * @type Boolean 573 * @type {Boolean}
529 */ 574 */
530 _needsSave: false, 575 _needsSave: false,
531 576
532 /** 577 /**
533 * Saves all subscriptions back to disk 578 * Saves all subscriptions back to disk
534 * @param {nsIFile} [targetFile] File to be written 579 * @param {nsIFile} [targetFile] File to be written
535 */ 580 */
536 saveToDisk: function(targetFile) 581 saveToDisk(targetFile)
537 { 582 {
538 let explicitFile = true; 583 let explicitFile = true;
539 if (!targetFile) 584 if (!targetFile)
540 { 585 {
541 targetFile = FilterStorage.sourceFile; 586 targetFile = FilterStorage.sourceFile;
542 explicitFile = false; 587 explicitFile = false;
543 } 588 }
544 if (!targetFile) 589 if (!targetFile)
545 return; 590 return;
546 591
547 if (!explicitFile && this._saving) 592 if (!explicitFile && this._saving)
548 { 593 {
549 this._needsSave = true; 594 this._needsSave = true;
550 return; 595 return;
551 } 596 }
552 597
553 // Make sure the file's parent directory exists 598 // Make sure the file's parent directory exists
554 try { 599 try
555 targetFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECT ORY); 600 {
556 } catch (e) {} 601 targetFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE,
602 FileUtils.PERMS_DIRECTORY);
603 }
604 catch (e) {}
557 605
558 let writeFilters = function() 606 let writeFilters = function()
559 { 607 {
560 IO.writeToFile(targetFile, this._generateFilterData(subscriptions), functi on(e) 608 IO.writeToFile(targetFile, this._generateFilterData(subscriptions), e =>
561 { 609 {
562 if (!explicitFile) 610 if (!explicitFile)
563 this._saving = false; 611 this._saving = false;
564 612
565 if (e) 613 if (e)
566 Cu.reportError(e); 614 Cu.reportError(e);
567 615
568 if (!explicitFile && this._needsSave) 616 if (!explicitFile && this._needsSave)
569 { 617 {
570 this._needsSave = false; 618 this._needsSave = false;
571 this.saveToDisk(); 619 this.saveToDisk();
572 } 620 }
573 else 621 else
574 FilterNotifier.triggerListeners("save"); 622 FilterNotifier.triggerListeners("save");
575 }.bind(this)); 623 });
576 }.bind(this); 624 }.bind(this);
577 625
578 let checkBackupRequired = function(callbackNotRequired, callbackRequired) 626 let checkBackupRequired = function(callbackNotRequired, callbackRequired)
579 { 627 {
580 if (explicitFile || Prefs.patternsbackups <= 0) 628 if (explicitFile || Prefs.patternsbackups <= 0)
581 callbackNotRequired(); 629 callbackNotRequired();
582 else 630 else
583 { 631 {
584 IO.statFile(targetFile, function(e, statData) 632 IO.statFile(targetFile, (statFileException, statData) =>
585 { 633 {
586 if (e || !statData.exists) 634 if (statFileException || !statData.exists)
587 callbackNotRequired(); 635 callbackNotRequired();
588 else 636 else
589 { 637 {
590 let [, part1, part2] = /^(.*)(\.\w+)$/.exec(targetFile.leafName) || [null, targetFile.leafName, ""]; 638 let [, part1, part2] = /^(.*)(\.\w+)$/.exec(targetFile.leafName) ||
639 [null, targetFile.leafName, ""];
591 let newestBackup = targetFile.clone(); 640 let newestBackup = targetFile.clone();
592 newestBackup.leafName = part1 + "-backup1" + part2; 641 newestBackup.leafName = part1 + "-backup1" + part2;
593 IO.statFile(newestBackup, function(e, statData) 642 IO.statFile(
594 { 643 newestBackup,
595 if (!e && (!statData.exists || (Date.now() - statData.lastModified ) / 3600000 >= Prefs.patternsbackupinterval)) 644 (statBackupFileException, statBackupData) =>
596 callbackRequired(part1, part2) 645 {
597 else 646 if (!statBackupFileException && (!statBackupData.exists ||
598 callbackNotRequired(); 647 (Date.now() - statBackupData.lastModified) /
599 }); 648 3600000 >= Prefs.patternsbackupinterval))
649 callbackRequired(part1, part2);
650 else
651 callbackNotRequired();
652 }
653 );
600 } 654 }
601 }); 655 });
602 } 656 }
603 }.bind(this); 657 };
604 658
605 let removeLastBackup = function(part1, part2) 659 let removeLastBackup = function(part1, part2)
606 { 660 {
607 let file = targetFile.clone(); 661 let file = targetFile.clone();
608 file.leafName = part1 + "-backup" + Prefs.patternsbackups + part2; 662 file.leafName = part1 + "-backup" + Prefs.patternsbackups + part2;
609 IO.removeFile(file, (e) => renameBackup(part1, part2, Prefs.patternsbackup s - 1)); 663 IO.removeFile(
610 }.bind(this); 664 file, e => renameBackup(part1, part2, Prefs.patternsbackups - 1)
665 );
666 };
611 667
612 let renameBackup = function(part1, part2, index) 668 let renameBackup = function(part1, part2, index)
613 { 669 {
614 if (index > 0) 670 if (index > 0)
615 { 671 {
616 let fromFile = targetFile.clone(); 672 let fromFile = targetFile.clone();
617 fromFile.leafName = part1 + "-backup" + index + part2; 673 fromFile.leafName = part1 + "-backup" + index + part2;
618 674
619 let toName = part1 + "-backup" + (index + 1) + part2; 675 let toName = part1 + "-backup" + (index + 1) + part2;
620 676
621 IO.renameFile(fromFile, toName, (e) => renameBackup(part1, part2, index - 1)); 677 IO.renameFile(fromFile, toName, e => renameBackup(part1, part2,
678 index - 1));
622 } 679 }
623 else 680 else
624 { 681 {
625 let toFile = targetFile.clone(); 682 let toFile = targetFile.clone();
626 toFile.leafName = part1 + "-backup" + (index + 1) + part2; 683 toFile.leafName = part1 + "-backup" + (index + 1) + part2;
627 684
628 IO.copyFile(targetFile, toFile, writeFilters); 685 IO.copyFile(targetFile, toFile, writeFilters);
629 } 686 }
630 }.bind(this); 687 };
631 688
632 // Do not persist external subscriptions 689 // Do not persist external subscriptions
633 let subscriptions = this.subscriptions.filter((s) => !(s instanceof External Subscription)); 690 let subscriptions = this.subscriptions.filter(
691 s => !(s instanceof ExternalSubscription)
692 );
634 if (!explicitFile) 693 if (!explicitFile)
635 this._saving = true; 694 this._saving = true;
636 695
637 checkBackupRequired(writeFilters, removeLastBackup); 696 checkBackupRequired(writeFilters, removeLastBackup);
638 }, 697 },
639 698
640 /** 699 /**
641 * Returns the list of existing backup files. 700 * Returns the list of existing backup files.
701 * @return {nsIFile[]}
642 */ 702 */
643 getBackupFiles: function() /**nsIFile[]*/ 703 getBackupFiles()
644 { 704 {
705 /* eslint-disable no-warning-comments */
Sebastian Noack 2017/02/20 13:14:51 Please just file an issue for this change and remo
kzar 2017/02/21 06:13:59 Done. https://issues.adblockplus.org/ticket/4919
645 // TODO: This method should be asynchronous 706 // TODO: This method should be asynchronous
707 /* eslint-enable no-warning-comments */
646 let result = []; 708 let result = [];
647 709
648 let [, part1, part2] = /^(.*)(\.\w+)$/.exec(FilterStorage.sourceFile.leafNam e) || [null, FilterStorage.sourceFile.leafName, ""]; 710 let [, part1, part2] = /^(.*)(\.\w+)$/.exec(
711 FilterStorage.sourceFile.leafName
712 ) || [null, FilterStorage.sourceFile.leafName, ""];
649 for (let i = 1; ; i++) 713 for (let i = 1; ; i++)
650 { 714 {
651 let file = FilterStorage.sourceFile.clone(); 715 let file = FilterStorage.sourceFile.clone();
652 file.leafName = part1 + "-backup" + i + part2; 716 file.leafName = part1 + "-backup" + i + part2;
653 if (file.exists()) 717 if (file.exists())
654 result.push(file); 718 result.push(file);
655 else 719 else
656 break; 720 break;
657 } 721 }
658 return result; 722 return result;
659 } 723 }
660 }; 724 };
661 725
662 /** 726 /**
663 * Joins subscription's filters to the subscription without any notifications. 727 * Joins subscription's filters to the subscription without any notifications.
664 * @param {Subscription} subscription filter subscription that should be connect ed to its filters 728 * @param {Subscription} subscription filter subscription that should be
729 * connected to its filters
665 */ 730 */
666 function addSubscriptionFilters(subscription) 731 function addSubscriptionFilters(subscription)
667 { 732 {
668 if (!(subscription.url in FilterStorage.knownSubscriptions)) 733 if (!(subscription.url in FilterStorage.knownSubscriptions))
669 return; 734 return;
670 735
671 for (let filter of subscription.filters) 736 for (let filter of subscription.filters)
672 filter.subscriptions.push(subscription); 737 filter.subscriptions.push(subscription);
673 } 738 }
674 739
675 /** 740 /**
676 * Removes subscription's filters from the subscription without any notification s. 741 * Removes subscription's filters from the subscription without any
742 * notifications.
677 * @param {Subscription} subscription filter subscription to be removed 743 * @param {Subscription} subscription filter subscription to be removed
678 */ 744 */
679 function removeSubscriptionFilters(subscription) 745 function removeSubscriptionFilters(subscription)
680 { 746 {
681 if (!(subscription.url in FilterStorage.knownSubscriptions)) 747 if (!(subscription.url in FilterStorage.knownSubscriptions))
682 return; 748 return;
683 749
684 for (let filter of subscription.filters) 750 for (let filter of subscription.filters)
685 { 751 {
686 let i = filter.subscriptions.indexOf(subscription); 752 let i = filter.subscriptions.indexOf(subscription);
(...skipping 11 matching lines...) Expand all
698 this.fileProperties = this.curObj = {}; 764 this.fileProperties = this.curObj = {};
699 this.subscriptions = []; 765 this.subscriptions = [];
700 this.knownFilters = Object.create(null); 766 this.knownFilters = Object.create(null);
701 this.knownSubscriptions = Object.create(null); 767 this.knownSubscriptions = Object.create(null);
702 } 768 }
703 INIParser.prototype = 769 INIParser.prototype =
704 { 770 {
705 linesProcessed: 0, 771 linesProcessed: 0,
706 subscriptions: null, 772 subscriptions: null,
707 knownFilters: null, 773 knownFilters: null,
708 knownSubscriptions : null, 774 knownSubscriptions: null,
709 wantObj: true, 775 wantObj: true,
710 fileProperties: null, 776 fileProperties: null,
711 curObj: null, 777 curObj: null,
712 curSection: null, 778 curSection: null,
713 userFilters: null, 779 userFilters: null,
714 780
715 process: function(val) 781 process(val)
716 { 782 {
717 let origKnownFilters = Filter.knownFilters; 783 let origKnownFilters = Filter.knownFilters;
718 Filter.knownFilters = this.knownFilters; 784 Filter.knownFilters = this.knownFilters;
719 let origKnownSubscriptions = Subscription.knownSubscriptions; 785 let origKnownSubscriptions = Subscription.knownSubscriptions;
720 Subscription.knownSubscriptions = this.knownSubscriptions; 786 Subscription.knownSubscriptions = this.knownSubscriptions;
721 let match; 787 let match;
722 try 788 try
723 { 789 {
724 if (this.wantObj === true && (match = /^(\w+)=(.*)$/.exec(val))) 790 if (this.wantObj === true && (match = /^(\w+)=(.*)$/.exec(val)))
725 this.curObj[match[1]] = match[2]; 791 this.curObj[match[1]] = match[2];
726 else if (val === null || (match = /^\s*\[(.+)\]\s*$/.exec(val))) 792 else if (val === null || (match = /^\s*\[(.+)\]\s*$/.exec(val)))
727 { 793 {
728 if (this.curObj) 794 if (this.curObj)
729 { 795 {
730 // Process current object before going to next section 796 // Process current object before going to next section
731 switch (this.curSection) 797 switch (this.curSection)
732 { 798 {
733 case "filter": 799 case "filter":
734 case "pattern": 800 case "pattern":
735 if ("text" in this.curObj) 801 if ("text" in this.curObj)
736 Filter.fromObject(this.curObj); 802 Filter.fromObject(this.curObj);
737 break; 803 break;
738 case "subscription": 804 case "subscription": {
739 let subscription = Subscription.fromObject(this.curObj); 805 let subscription = Subscription.fromObject(this.curObj);
740 if (subscription) 806 if (subscription)
741 this.subscriptions.push(subscription); 807 this.subscriptions.push(subscription);
742 break; 808 break;
809 }
743 case "subscription filters": 810 case "subscription filters":
744 case "subscription patterns": 811 case "subscription patterns":
745 if (this.subscriptions.length) 812 if (this.subscriptions.length)
746 { 813 {
747 let subscription = this.subscriptions[this.subscriptions.length - 1]; 814 let subscription = this.subscriptions[
815 this.subscriptions.length - 1
816 ];
748 for (let text of this.curObj) 817 for (let text of this.curObj)
749 { 818 {
750 let filter = Filter.fromText(text); 819 let filter = Filter.fromText(text);
751 subscription.filters.push(filter); 820 subscription.filters.push(filter);
752 filter.subscriptions.push(subscription); 821 filter.subscriptions.push(subscription);
753 } 822 }
754 } 823 }
755 break; 824 break;
756 case "user patterns": 825 case "user patterns":
757 this.userFilters = this.curObj; 826 this.userFilters = this.curObj;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 Subscription.knownSubscriptions = origKnownSubscriptions; 860 Subscription.knownSubscriptions = origKnownSubscriptions;
792 } 861 }
793 862
794 // Allow events to be processed every now and then. 863 // Allow events to be processed every now and then.
795 // Note: IO.readFromFile() will deal with the potential reentrance here. 864 // Note: IO.readFromFile() will deal with the potential reentrance here.
796 this.linesProcessed++; 865 this.linesProcessed++;
797 if (this.linesProcessed % 1000 == 0) 866 if (this.linesProcessed % 1000 == 0)
798 return Utils.yield(); 867 return Utils.yield();
799 } 868 }
800 }; 869 };
OLDNEW
« lib/filterNotifier.js ('K') | « lib/filterNotifier.js ('k') | lib/matcher.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld