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

Side by Side Diff: lib/filterStorage.js

Issue 29912619: Issue 6891, 6741 - Rename FilterStorage to filterStorage (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Minor update Created Oct. 16, 2018, 10:02 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 | « lib/filterListener.js ('k') | lib/synchronizer.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-present eyeo GmbH 3 * Copyright (C) 2006-present 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"; 18 "use strict";
19 19
20 /** 20 /**
21 * @fileOverview FilterStorage class responsible for managing user's 21 * @fileOverview <code>filterStorage</code> object responsible for managing the
22 * subscriptions and filters. 22 * user's subscriptions and filters.
23 */ 23 */
24 24
25 const {IO} = require("io"); 25 const {IO} = require("io");
26 const {Prefs} = require("prefs"); 26 const {Prefs} = require("prefs");
27 const {Filter, ActiveFilter} = require("./filterClasses"); 27 const {Filter, ActiveFilter} = require("./filterClasses");
28 const {Subscription, SpecialSubscription, 28 const {Subscription, SpecialSubscription,
29 ExternalSubscription} = require("./subscriptionClasses"); 29 ExternalSubscription} = require("./subscriptionClasses");
30 const {filterNotifier} = require("./filterNotifier"); 30 const {filterNotifier} = require("./filterNotifier");
31 const {INIParser} = require("./iniParser"); 31 const {INIParser} = require("./iniParser");
32 32
33 /** 33 /**
34 * Version number of the filter storage file format. 34 * Version number of the filter storage file format.
35 * @type {number} 35 * @type {number}
36 */ 36 */
37 let formatVersion = 5; 37 const FORMAT_VERSION = 5;
38 38
39 /** 39 /**
40 * This class reads user's filters from disk, manages them in memory 40 * {@link filterStorage} implementation.
41 * and writes them back. 41 */
42 * @class 42 class FilterStorage
43 */
44 let FilterStorage = exports.FilterStorage =
45 { 43 {
46 /** 44 /**
47 * Will be set to true after the initial loadFromDisk() call completes. 45 * @hideconstructor
48 * @type {boolean} 46 */
49 */ 47 constructor()
50 initialized: false, 48 {
51 49 /**
52 /** 50 * Will be set to true after the initial {@link FilterStorage#loadFromDisk}
53 * Version number of the patterns.ini format used. 51 * call completes.
52 * @type {boolean}
53 */
54 this.initialized = false;
55
56 /**
57 * Will be set to <code>true</code> if no <code>patterns.ini</code> file
58 * exists.
59 * @type {boolean}
60 */
61 this.firstRun = false;
62
63 /**
64 * Map of properties listed in the filter storage file before the sections
65 * start. Right now this should be only the format version.
66 * @type {object}
67 */
68 this.fileProperties = Object.create(null);
69
70 /**
71 * Map of subscriptions already on the list, by their URL/identifier.
72 * @type {Map.<string,Subscription>}
73 */
74 this.knownSubscriptions = new Map();
75
76 /**
77 * Will be set to true if {@link FilterStorage#saveToDisk} is running
78 * (reentrance protection).
79 * @type {boolean}
80 * @private
81 */
82 this._saving = false;
83
84 /**
85 * Will be set to true if a {@link FilterStorage#saveToDisk} call arrives
86 * while {@link FilterStorage#saveToDisk} is already running (delayed
87 * execution).
88 * @type {boolean}
89 * @private
90 */
91 this._needsSave = false;
92 }
93
94 /**
95 * The version number of the <code>patterns.ini</code> format used.
54 * @type {number} 96 * @type {number}
55 */ 97 */
56 get formatVersion() 98 get formatVersion()
57 { 99 {
58 return formatVersion; 100 return FORMAT_VERSION;
59 }, 101 }
60 102
61 /** 103 /**
62 * File containing the filter list 104 * The file containing the subscriptions.
63 * @type {string} 105 * @type {string}
64 */ 106 */
65 get sourceFile() 107 get sourceFile()
66 { 108 {
67 return "patterns.ini"; 109 return "patterns.ini";
68 }, 110 }
69 111
70 /** 112 /**
71 * Will be set to true if no patterns.ini file exists. 113 * Yields all subscriptions in the storage.
72 * @type {boolean}
73 */
74 firstRun: false,
75
76 /**
77 * Map of properties listed in the filter storage file before the sections
78 * start. Right now this should be only the format version.
79 */
80 fileProperties: Object.create(null),
81
82 /**
83 * Yields subscriptions containing all filters
84 * @yields {Subscription} 114 * @yields {Subscription}
85 */ 115 */
86 *subscriptions() 116 *subscriptions()
87 { 117 {
88 yield* this.knownSubscriptions.values(); 118 yield* this.knownSubscriptions.values();
89 }, 119 }
90 120
91 /** 121 /**
92 * Number of known subscriptions. 122 * The number of subscriptions in the storage.
93 * @type {number} 123 * @type {number}
94 */ 124 */
95 get subscriptionCount() 125 get subscriptionCount()
96 { 126 {
97 return this.knownSubscriptions.size; 127 return this.knownSubscriptions.size;
98 }, 128 }
99
100 /**
101 * Map of subscriptions already on the list, by their URL/identifier
102 * @type {Map.<string,Subscription>}
103 */
104 knownSubscriptions: new Map(),
105 129
106 /** 130 /**
107 * Finds the filter group that a filter should be added to by default. Will 131 * Finds the filter group that a filter should be added to by default. Will
108 * return null if this group doesn't exist yet. 132 * return <code>null</code> if this group doesn't exist yet.
109 * @param {Filter} filter 133 * @param {Filter} filter
110 * @return {?SpecialSubscription} 134 * @returns {?SpecialSubscription}
111 */ 135 */
112 getGroupForFilter(filter) 136 getGroupForFilter(filter)
113 { 137 {
114 let generalSubscription = null; 138 let generalSubscription = null;
115 for (let subscription of FilterStorage.knownSubscriptions.values()) 139 for (let subscription of this.knownSubscriptions.values())
116 { 140 {
117 if (subscription instanceof SpecialSubscription && !subscription.disabled) 141 if (subscription instanceof SpecialSubscription && !subscription.disabled)
118 { 142 {
119 // Always prefer specialized subscriptions 143 // Always prefer specialized subscriptions
120 if (subscription.isDefaultFor(filter)) 144 if (subscription.isDefaultFor(filter))
121 return subscription; 145 return subscription;
122 146
123 // If this is a general subscription - store it as fallback 147 // If this is a general subscription - store it as fallback
124 if (!generalSubscription && 148 if (!generalSubscription &&
125 (!subscription.defaults || !subscription.defaults.length)) 149 (!subscription.defaults || !subscription.defaults.length))
126 { 150 {
127 generalSubscription = subscription; 151 generalSubscription = subscription;
128 } 152 }
129 } 153 }
130 } 154 }
131 return generalSubscription; 155 return generalSubscription;
132 }, 156 }
133 157
134 /** 158 /**
135 * Adds a filter subscription to the list 159 * Adds a subscription to the storage.
136 * @param {Subscription} subscription filter subscription to be added 160 * @param {Subscription} subscription The subscription to be added.
137 */ 161 */
138 addSubscription(subscription) 162 addSubscription(subscription)
139 { 163 {
140 if (FilterStorage.knownSubscriptions.has(subscription.url)) 164 if (this.knownSubscriptions.has(subscription.url))
141 return; 165 return;
142 166
143 FilterStorage.knownSubscriptions.set(subscription.url, subscription); 167 this.knownSubscriptions.set(subscription.url, subscription);
144 addSubscriptionFilters(subscription); 168 connectSubscriptionFilters(subscription);
145 169
146 filterNotifier.emit("subscription.added", subscription); 170 filterNotifier.emit("subscription.added", subscription);
147 }, 171 }
148 172
149 /** 173 /**
150 * Removes a filter subscription from the list 174 * Removes a subscription from the storage.
151 * @param {Subscription} subscription filter subscription to be removed 175 * @param {Subscription} subscription The subscription to be removed.
152 */ 176 */
153 removeSubscription(subscription) 177 removeSubscription(subscription)
154 { 178 {
155 if (!FilterStorage.knownSubscriptions.has(subscription.url)) 179 if (!this.knownSubscriptions.has(subscription.url))
156 return; 180 return;
157 181
158 removeSubscriptionFilters(subscription); 182 disconnectSubscriptionFilters(subscription);
159 183
160 FilterStorage.knownSubscriptions.delete(subscription.url); 184 this.knownSubscriptions.delete(subscription.url);
161 185
162 // This should be the last remaining reference to the Subscription 186 // This should be the last remaining reference to the Subscription
163 // object. 187 // object.
164 Subscription.knownSubscriptions.delete(subscription.url); 188 Subscription.knownSubscriptions.delete(subscription.url);
165 189
166 filterNotifier.emit("subscription.removed", subscription); 190 filterNotifier.emit("subscription.removed", subscription);
167 }, 191 }
168 192
169 /** 193 /**
170 * Replaces the list of filters in a subscription by a new list 194 * Replaces the list of filters in a subscription with a new list.
171 * @param {Subscription} subscription filter subscription to be updated 195 * @param {Subscription} subscription The subscription to be updated.
172 * @param {Filter[]} filters new filter list 196 * @param {Array.<Filter>} filters The new list of filters.
173 */ 197 */
174 updateSubscriptionFilters(subscription, filters) 198 updateSubscriptionFilters(subscription, filters)
175 { 199 {
176 removeSubscriptionFilters(subscription); 200 disconnectSubscriptionFilters(subscription);
177 let oldFilters = subscription.filters; 201 let oldFilters = subscription.filters;
178 subscription.filters = filters; 202 subscription.filters = filters;
179 addSubscriptionFilters(subscription); 203 connectSubscriptionFilters(subscription);
180 filterNotifier.emit("subscription.updated", subscription, oldFilters); 204 filterNotifier.emit("subscription.updated", subscription, oldFilters);
181 }, 205 }
182 206
183 /** 207 /**
184 * Adds a user-defined filter to the list 208 * Adds a user-defined filter to the storage.
185 * @param {Filter} filter 209 * @param {Filter} filter
186 * @param {SpecialSubscription} [subscription] 210 * @param {?SpecialSubscription} [subscription] The subscription that the
187 * particular group that the filter should be added to 211 * filter should be added to.
188 * @param {number} [position] 212 * @param {number} [position] The position within the subscription at which
189 * position within the subscription at which the filter should be added 213 * the filter should be added. If not specified, the filter is added at the
214 * end of the subscription.
190 */ 215 */
191 addFilter(filter, subscription, position) 216 addFilter(filter, subscription, position)
192 { 217 {
193 if (!subscription) 218 if (!subscription)
194 { 219 {
195 for (let currentSubscription of filter.subscriptions()) 220 for (let currentSubscription of filter.subscriptions())
196 { 221 {
197 if (currentSubscription instanceof SpecialSubscription && 222 if (currentSubscription instanceof SpecialSubscription &&
198 !currentSubscription.disabled) 223 !currentSubscription.disabled)
199 { 224 {
200 return; // No need to add 225 return; // No need to add
201 } 226 }
202 } 227 }
203 subscription = FilterStorage.getGroupForFilter(filter); 228 subscription = this.getGroupForFilter(filter);
204 } 229 }
205 if (!subscription) 230 if (!subscription)
206 { 231 {
207 // No group for this filter exists, create one 232 // No group for this filter exists, create one
208 subscription = SpecialSubscription.createForFilter(filter); 233 subscription = SpecialSubscription.createForFilter(filter);
209 this.addSubscription(subscription); 234 this.addSubscription(subscription);
210 return; 235 return;
211 } 236 }
212 237
213 if (typeof position == "undefined") 238 if (typeof position == "undefined")
214 position = subscription.filters.length; 239 position = subscription.filters.length;
215 240
216 filter.addSubscription(subscription); 241 filter.addSubscription(subscription);
217 subscription.filters.splice(position, 0, filter); 242 subscription.filters.splice(position, 0, filter);
218 filterNotifier.emit("filter.added", filter, subscription, position); 243 filterNotifier.emit("filter.added", filter, subscription, position);
219 }, 244 }
220 245
221 /** 246 /**
222 * Removes a user-defined filter from the list 247 * Removes a user-defined filter from the storage.
223 * @param {Filter} filter 248 * @param {Filter} filter
224 * @param {SpecialSubscription} [subscription] a particular filter group that 249 * @param {?SpecialSubscription} [subscription] The subscription that the
225 * the filter should be removed from (if ommited will be removed from all 250 * filter should be removed from. If not specified, the filter will be
226 * subscriptions) 251 * removed from all subscriptions.
227 * @param {number} [position] position inside the filter group at which the 252 * @param {number} [position] The position within the subscription at which
228 * filter should be removed (if ommited all instances will be removed) 253 * the filter should be removed. If not specified, all instances of the
254 * filter will be removed.
229 */ 255 */
230 removeFilter(filter, subscription, position) 256 removeFilter(filter, subscription, position)
231 { 257 {
232 let subscriptions = ( 258 let subscriptions = (
233 subscription ? [subscription] : filter.subscriptions() 259 subscription ? [subscription] : filter.subscriptions()
234 ); 260 );
235 for (let currentSubscription of subscriptions) 261 for (let currentSubscription of subscriptions)
236 { 262 {
237 if (currentSubscription instanceof SpecialSubscription) 263 if (currentSubscription instanceof SpecialSubscription)
238 { 264 {
(...skipping 18 matching lines...) Expand all
257 { 283 {
258 currentSubscription.filters.splice(currentPosition, 1); 284 currentSubscription.filters.splice(currentPosition, 1);
259 if (currentSubscription.filters.indexOf(filter) < 0) 285 if (currentSubscription.filters.indexOf(filter) < 0)
260 filter.removeSubscription(currentSubscription); 286 filter.removeSubscription(currentSubscription);
261 filterNotifier.emit("filter.removed", filter, currentSubscription, 287 filterNotifier.emit("filter.removed", filter, currentSubscription,
262 currentPosition); 288 currentPosition);
263 } 289 }
264 } 290 }
265 } 291 }
266 } 292 }
267 }, 293 }
268 294
269 /** 295 /**
270 * Moves a user-defined filter to a new position 296 * Moves a user-defined filter to a new position.
271 * @param {Filter} filter 297 * @param {Filter} filter
272 * @param {SpecialSubscription} subscription filter group where the filter is 298 * @param {SpecialSubscription} subscription The subscription where the
273 * located 299 * filter is located.
274 * @param {number} oldPosition current position of the filter 300 * @param {number} oldPosition The current position of the filter.
275 * @param {number} newPosition new position of the filter 301 * @param {number} newPosition The new position of the filter.
276 */ 302 */
277 moveFilter(filter, subscription, oldPosition, newPosition) 303 moveFilter(filter, subscription, oldPosition, newPosition)
278 { 304 {
279 if (!(subscription instanceof SpecialSubscription) || 305 if (!(subscription instanceof SpecialSubscription) ||
280 subscription.filters[oldPosition] != filter) 306 subscription.filters[oldPosition] != filter)
281 { 307 {
282 return; 308 return;
283 } 309 }
284 310
285 newPosition = Math.min(Math.max(newPosition, 0), 311 newPosition = Math.min(Math.max(newPosition, 0),
286 subscription.filters.length - 1); 312 subscription.filters.length - 1);
287 if (oldPosition == newPosition) 313 if (oldPosition == newPosition)
288 return; 314 return;
289 315
290 subscription.filters.splice(oldPosition, 1); 316 subscription.filters.splice(oldPosition, 1);
291 subscription.filters.splice(newPosition, 0, filter); 317 subscription.filters.splice(newPosition, 0, filter);
292 filterNotifier.emit("filter.moved", filter, subscription, oldPosition, 318 filterNotifier.emit("filter.moved", filter, subscription, oldPosition,
293 newPosition); 319 newPosition);
294 }, 320 }
295 321
296 /** 322 /**
297 * Increases the hit count for a filter by one 323 * Increases the hit count for a filter by one.
298 * @param {Filter} filter 324 * @param {Filter} filter
299 */ 325 */
300 increaseHitCount(filter) 326 increaseHitCount(filter)
301 { 327 {
302 if (!Prefs.savestats || !(filter instanceof ActiveFilter)) 328 if (!Prefs.savestats || !(filter instanceof ActiveFilter))
303 return; 329 return;
304 330
305 filter.hitCount++; 331 filter.hitCount++;
306 filter.lastHit = Date.now(); 332 filter.lastHit = Date.now();
307 }, 333 }
308 334
309 /** 335 /**
310 * Resets hit count for some filters 336 * Resets hit count for some filters.
311 * @param {Filter[]} filters filters to be reset, if null all filters will 337 * @param {?Array.<Filter>} [filters] The filters to be reset. If not
312 * be reset 338 * specified, all filters will be reset.
313 */ 339 */
314 resetHitCounts(filters) 340 resetHitCounts(filters)
315 { 341 {
316 if (!filters) 342 if (!filters)
317 filters = Filter.knownFilters.values(); 343 filters = Filter.knownFilters.values();
318 for (let filter of filters) 344 for (let filter of filters)
319 { 345 {
320 filter.hitCount = 0; 346 filter.hitCount = 0;
321 filter.lastHit = 0; 347 filter.lastHit = 0;
322 } 348 }
323 }, 349 }
324 350
325 /** 351 /**
326 * @callback TextSink 352 * @callback TextSink
327 * @param {string?} line 353 * @param {string?} line
328 */ 354 */
329 355
330 /** 356 /**
331 * Allows importing previously serialized filter data. 357 * Allows importing previously serialized filter data.
332 * @param {boolean} silent 358 * @param {boolean} silent If <code>true</code>, no "load" notification will
333 * If true, no "load" notification will be sent out. 359 * be sent out.
334 * @return {TextSink} 360 * @returns {TextSink} The function to be called for each line of data.
335 * Function to be called for each line of data. Calling it with null as 361 * Calling it with <code>null</code> as the argument finalizes the import
336 * parameter finalizes the import and replaces existing data. No changes 362 * and replaces existing data. No changes will be applied before
337 * will be applied before finalization, so import can be "aborted" by 363 * finalization, so import can be "aborted" by forgetting this callback.
338 * forgetting this callback.
339 */ 364 */
340 importData(silent) 365 importData(silent)
341 { 366 {
342 let parser = new INIParser(); 367 let parser = new INIParser();
343 return line => 368 return line =>
344 { 369 {
345 parser.process(line); 370 parser.process(line);
346 if (line === null) 371 if (line === null)
347 { 372 {
348 let knownSubscriptions = new Map(); 373 let knownSubscriptions = new Map();
349 for (let subscription of parser.subscriptions) 374 for (let subscription of parser.subscriptions)
350 knownSubscriptions.set(subscription.url, subscription); 375 knownSubscriptions.set(subscription.url, subscription);
351 376
352 this.fileProperties = parser.fileProperties; 377 this.fileProperties = parser.fileProperties;
353 this.knownSubscriptions = knownSubscriptions; 378 this.knownSubscriptions = knownSubscriptions;
354 Filter.knownFilters = parser.knownFilters; 379 Filter.knownFilters = parser.knownFilters;
355 Subscription.knownSubscriptions = parser.knownSubscriptions; 380 Subscription.knownSubscriptions = parser.knownSubscriptions;
356 381
357 if (!silent) 382 if (!silent)
358 filterNotifier.emit("load"); 383 filterNotifier.emit("load");
359 } 384 }
360 }; 385 };
361 }, 386 }
362 387
363 /** 388 /**
364 * Loads all subscriptions from the disk. 389 * Loads all subscriptions from disk.
365 * @return {Promise} promise resolved or rejected when loading is complete 390 * @returns {Promise} A promise resolved or rejected when loading is complete.
366 */ 391 */
367 loadFromDisk() 392 loadFromDisk()
368 { 393 {
369 let tryBackup = backupIndex => 394 let tryBackup = backupIndex =>
370 { 395 {
371 return this.restoreBackup(backupIndex, true).then(() => 396 return this.restoreBackup(backupIndex, true).then(() =>
372 { 397 {
373 if (this.knownSubscriptions.size == 0) 398 if (this.knownSubscriptions.size == 0)
374 return tryBackup(backupIndex + 1); 399 return tryBackup(backupIndex + 1);
375 }).catch(error => 400 }).catch(error =>
(...skipping 22 matching lines...) Expand all
398 }); 423 });
399 }).catch(error => 424 }).catch(error =>
400 { 425 {
401 Cu.reportError(error); 426 Cu.reportError(error);
402 return tryBackup(1); 427 return tryBackup(1);
403 }).then(() => 428 }).then(() =>
404 { 429 {
405 this.initialized = true; 430 this.initialized = true;
406 filterNotifier.emit("load"); 431 filterNotifier.emit("load");
407 }); 432 });
408 }, 433 }
409 434
410 /** 435 /**
411 * Constructs the file name for a patterns.ini backup. 436 * Constructs the file name for a <code>patterns.ini</code> backup.
412 * @param {number} backupIndex 437 * @param {number} backupIndex Number of the backup file (1 being the most
413 * number of the backup file (1 being the most recent) 438 * recent).
414 * @return {string} backup file name 439 * @returns {string} Backup file name.
415 */ 440 */
416 getBackupName(backupIndex) 441 getBackupName(backupIndex)
417 { 442 {
418 let [name, extension] = this.sourceFile.split(".", 2); 443 let [name, extension] = this.sourceFile.split(".", 2);
419 return (name + "-backup" + backupIndex + "." + extension); 444 return (name + "-backup" + backupIndex + "." + extension);
420 }, 445 }
421 446
422 /** 447 /**
423 * Restores an automatically created backup. 448 * Restores an automatically created backup.
424 * @param {number} backupIndex 449 * @param {number} backupIndex Number of the backup to restore (1 being the
425 * number of the backup to restore (1 being the most recent) 450 * most recent).
426 * @param {boolean} silent 451 * @param {boolean} silent If <code>true</code>, no "load" notification will
427 * If true, no "load" notification will be sent out. 452 * be sent out.
428 * @return {Promise} promise resolved or rejected when restoring is complete 453 * @returns {Promise} A promise resolved or rejected when restoration is
454 * complete.
429 */ 455 */
430 restoreBackup(backupIndex, silent) 456 restoreBackup(backupIndex, silent)
431 { 457 {
432 let backupFile = this.getBackupName(backupIndex); 458 let backupFile = this.getBackupName(backupIndex);
433 let parser = this.importData(silent); 459 let parser = this.importData(silent);
434 return IO.readFromFile(backupFile, parser).then(() => 460 return IO.readFromFile(backupFile, parser).then(() =>
435 { 461 {
436 parser(null); 462 parser(null);
437 return this.saveToDisk(); 463 return this.saveToDisk();
438 }); 464 });
439 }, 465 }
440 466
441 /** 467 /**
442 * Generator serializing filter data and yielding it line by line. 468 * Generator serializing filter data and yielding it line by line.
469 * @yields {string}
443 */ 470 */
444 *exportData() 471 *exportData()
445 { 472 {
446 // Do not persist external subscriptions 473 // Do not persist external subscriptions
447 let subscriptions = []; 474 let subscriptions = [];
448 for (let subscription of this.subscriptions()) 475 for (let subscription of this.subscriptions())
449 { 476 {
450 if (!(subscription instanceof ExternalSubscription) && 477 if (!(subscription instanceof ExternalSubscription) &&
451 !(subscription instanceof SpecialSubscription && 478 !(subscription instanceof SpecialSubscription &&
452 subscription.filters.length == 0)) 479 subscription.filters.length == 0))
453 { 480 {
454 subscriptions.push(subscription); 481 subscriptions.push(subscription);
455 } 482 }
456 } 483 }
457 484
458 yield "# Adblock Plus preferences"; 485 yield "# Adblock Plus preferences";
459 yield "version=" + formatVersion; 486 yield "version=" + this.formatVersion;
460 487
461 let saved = new Set(); 488 let saved = new Set();
462 let buf = []; 489 let buf = [];
463 490
464 // Save subscriptions 491 // Save subscriptions
465 for (let subscription of subscriptions) 492 for (let subscription of subscriptions)
466 { 493 {
467 yield ""; 494 yield "";
468 495
469 subscription.serialize(buf); 496 subscription.serialize(buf);
(...skipping 15 matching lines...) Expand all
485 if (!saved.has(filter.text)) 512 if (!saved.has(filter.text))
486 { 513 {
487 filter.serialize(buf); 514 filter.serialize(buf);
488 saved.add(filter.text); 515 saved.add(filter.text);
489 for (let line of buf) 516 for (let line of buf)
490 yield line; 517 yield line;
491 buf.splice(0); 518 buf.splice(0);
492 } 519 }
493 } 520 }
494 } 521 }
495 }, 522 }
496 523
497 /** 524 /**
498 * Will be set to true if saveToDisk() is running (reentrance protection). 525 * Saves all subscriptions back to disk.
499 * @type {boolean} 526 * @returns {Promise} A promise resolved or rejected when saving is complete.
500 */
501 _saving: false,
502
503 /**
504 * Will be set to true if a saveToDisk() call arrives while saveToDisk() is
505 * already running (delayed execution).
506 * @type {boolean}
507 */
508 _needsSave: false,
509
510 /**
511 * Saves all subscriptions back to disk
512 * @return {Promise} promise resolved or rejected when saving is complete
513 */ 527 */
514 saveToDisk() 528 saveToDisk()
515 { 529 {
516 if (this._saving) 530 if (this._saving)
517 { 531 {
518 this._needsSave = true; 532 this._needsSave = true;
519 return; 533 return;
520 } 534 }
521 535
522 this._saving = true; 536 this._saving = true;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 Cu.reportError(error); 600 Cu.reportError(error);
587 }).then(() => 601 }).then(() =>
588 { 602 {
589 this._saving = false; 603 this._saving = false;
590 if (this._needsSave) 604 if (this._needsSave)
591 { 605 {
592 this._needsSave = false; 606 this._needsSave = false;
593 this.saveToDisk(); 607 this.saveToDisk();
594 } 608 }
595 }); 609 });
596 }, 610 }
597 611
598 /** 612 /**
599 * @typedef FileInfo 613 * @typedef FileInfo
600 * @type {object} 614 * @type {object}
601 * @property {number} index 615 * @property {number} index
602 * @property {number} lastModified 616 * @property {number} lastModified
603 */ 617 */
604 618
605 /** 619 /**
606 * Returns a promise resolving in a list of existing backup files. 620 * Returns a promise resolving in a list of existing backup files.
607 * @return {Promise.<FileInfo[]>} 621 * @returns {Promise.<Array.<FileInfo>>}
608 */ 622 */
609 getBackupFiles() 623 getBackupFiles()
610 { 624 {
611 let backups = []; 625 let backups = [];
612 626
613 let checkBackupFile = index => 627 let checkBackupFile = index =>
614 { 628 {
615 return IO.statFile(this.getBackupName(index)).then(statData => 629 return IO.statFile(this.getBackupName(index)).then(statData =>
616 { 630 {
617 if (!statData.exists) 631 if (!statData.exists)
618 return backups; 632 return backups;
619 633
620 backups.push({ 634 backups.push({
621 index, 635 index,
622 lastModified: statData.lastModified 636 lastModified: statData.lastModified
623 }); 637 });
624 return checkBackupFile(index + 1); 638 return checkBackupFile(index + 1);
625 }).catch(error => 639 }).catch(error =>
626 { 640 {
627 // Something went wrong, return whatever data we got so far. 641 // Something went wrong, return whatever data we got so far.
628 Cu.reportError(error); 642 Cu.reportError(error);
629 return backups; 643 return backups;
630 }); 644 });
631 }; 645 };
632 646
633 return checkBackupFile(1); 647 return checkBackupFile(1);
634 } 648 }
635 }; 649 }
636 650
637 /** 651 /**
638 * Joins subscription's filters to the subscription without any notifications. 652 * Reads the user's filters from disk, manages them in memory, and writes them
639 * @param {Subscription} subscription 653 * back to disk.
640 * filter subscription that should be connected to its filters
641 */ 654 */
642 function addSubscriptionFilters(subscription) 655 let filterStorage = new FilterStorage();
656
657 exports.filterStorage = filterStorage;
658
659 /**
660 * Connects a subscription to its filters without any notifications.
661 * @param {Subscription} subscription The subscription that should be
662 * connected to its filters.
663 */
664 function connectSubscriptionFilters(subscription)
643 { 665 {
644 if (!FilterStorage.knownSubscriptions.has(subscription.url)) 666 if (!filterStorage.knownSubscriptions.has(subscription.url))
645 return; 667 return;
646 668
647 for (let filter of subscription.filters) 669 for (let filter of subscription.filters)
648 filter.addSubscription(subscription); 670 filter.addSubscription(subscription);
649 } 671 }
650 672
651 /** 673 /**
652 * Removes subscription's filters from the subscription without any 674 * Disconnects a subscription from its filters without any notifications.
653 * notifications. 675 * @param {Subscription} subscription The subscription that should be
654 * @param {Subscription} subscription filter subscription to be removed 676 * disconnected from its filters.
655 */ 677 */
656 function removeSubscriptionFilters(subscription) 678 function disconnectSubscriptionFilters(subscription)
657 { 679 {
658 if (!FilterStorage.knownSubscriptions.has(subscription.url)) 680 if (!filterStorage.knownSubscriptions.has(subscription.url))
659 return; 681 return;
660 682
661 for (let filter of subscription.filters) 683 for (let filter of subscription.filters)
662 filter.removeSubscription(subscription); 684 filter.removeSubscription(subscription);
663 } 685 }
OLDNEW
« no previous file with comments | « lib/filterListener.js ('k') | lib/synchronizer.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld