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

Powered by Google App Engine
This is Rietveld