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

Delta Between Two Patch Sets: lib/filterStorage.js

Issue 29853570: Issue 6908 - Pass updated subscription's old filters as an event argument (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Created Aug. 11, 2018, 2:52 p.m.
Right Patch Set: Rebase Created Aug. 29, 2018, 6:03 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « lib/filterListener.js ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 FilterStorage class responsible for managing user's
22 * subscriptions and filters. 22 * 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 32
32 /** 33 /**
33 * Version number of the filter storage file format. 34 * Version number of the filter storage file format.
34 * @type {number} 35 * @type {number}
35 */ 36 */
36 let formatVersion = 5; 37 let formatVersion = 5;
37 38
38 /** 39 /**
39 * This class reads user's filters from disk, manages them in memory 40 * This class reads user's filters from disk, manages them in memory
40 * and writes them back. 41 * and writes them back.
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 */ 125 */
125 addSubscription(subscription) 126 addSubscription(subscription)
126 { 127 {
127 if (FilterStorage.knownSubscriptions.has(subscription.url)) 128 if (FilterStorage.knownSubscriptions.has(subscription.url))
128 return; 129 return;
129 130
130 FilterStorage.subscriptions.push(subscription); 131 FilterStorage.subscriptions.push(subscription);
131 FilterStorage.knownSubscriptions.set(subscription.url, subscription); 132 FilterStorage.knownSubscriptions.set(subscription.url, subscription);
132 addSubscriptionFilters(subscription); 133 addSubscriptionFilters(subscription);
133 134
134 FilterNotifier.triggerListeners("subscription.added", subscription); 135 filterNotifier.emit("subscription.added", subscription);
135 }, 136 },
136 137
137 /** 138 /**
138 * Removes a filter subscription from the list 139 * Removes a filter subscription from the list
139 * @param {Subscription} subscription filter subscription to be removed 140 * @param {Subscription} subscription filter subscription to be removed
140 */ 141 */
141 removeSubscription(subscription) 142 removeSubscription(subscription)
142 { 143 {
143 for (let i = 0; i < FilterStorage.subscriptions.length; i++) 144 for (let i = 0; i < FilterStorage.subscriptions.length; i++)
144 { 145 {
145 if (FilterStorage.subscriptions[i].url == subscription.url) 146 if (FilterStorage.subscriptions[i].url == subscription.url)
146 { 147 {
147 removeSubscriptionFilters(subscription); 148 removeSubscriptionFilters(subscription);
148 149
149 FilterStorage.subscriptions.splice(i--, 1); 150 FilterStorage.subscriptions.splice(i--, 1);
150 FilterStorage.knownSubscriptions.delete(subscription.url); 151 FilterStorage.knownSubscriptions.delete(subscription.url);
151 FilterNotifier.triggerListeners("subscription.removed", subscription); 152
153 // This should be the last remaining reference to the Subscription
154 // object.
155 Subscription.knownSubscriptions.delete(subscription.url);
156
157 filterNotifier.emit("subscription.removed", subscription);
152 return; 158 return;
153 } 159 }
154 } 160 }
155 }, 161 },
156 162
157 /** 163 /**
158 * Moves a subscription in the list to a new position. 164 * Moves a subscription in the list to a new position.
159 * @param {Subscription} subscription filter subscription to be moved 165 * @param {Subscription} subscription filter subscription to be moved
160 * @param {Subscription} [insertBefore] filter subscription to insert before 166 * @param {Subscription} [insertBefore] filter subscription to insert before
161 * (if omitted the subscription will be put at the end of the list) 167 * (if omitted the subscription will be put at the end of the list)
(...skipping 11 matching lines...) Expand all
173 if (newPos < 0) 179 if (newPos < 0)
174 newPos = FilterStorage.subscriptions.length; 180 newPos = FilterStorage.subscriptions.length;
175 181
176 if (currentPos < newPos) 182 if (currentPos < newPos)
177 newPos--; 183 newPos--;
178 if (currentPos == newPos) 184 if (currentPos == newPos)
179 return; 185 return;
180 186
181 FilterStorage.subscriptions.splice(currentPos, 1); 187 FilterStorage.subscriptions.splice(currentPos, 1);
182 FilterStorage.subscriptions.splice(newPos, 0, subscription); 188 FilterStorage.subscriptions.splice(newPos, 0, subscription);
183 FilterNotifier.triggerListeners("subscription.moved", subscription); 189 filterNotifier.emit("subscription.moved", subscription);
184 }, 190 },
185 191
186 /** 192 /**
187 * Replaces the list of filters in a subscription by a new list 193 * Replaces the list of filters in a subscription by a new list
188 * @param {Subscription} subscription filter subscription to be updated 194 * @param {Subscription} subscription filter subscription to be updated
189 * @param {Filter[]} filters new filter list 195 * @param {Filter[]} filters new filter list
190 */ 196 */
191 updateSubscriptionFilters(subscription, filters) 197 updateSubscriptionFilters(subscription, filters)
192 { 198 {
193 removeSubscriptionFilters(subscription); 199 removeSubscriptionFilters(subscription);
194 let oldFilters = subscription.filters; 200 let oldFilters = subscription.filters;
195 subscription.filters = filters; 201 subscription.filters = filters;
196 addSubscriptionFilters(subscription); 202 addSubscriptionFilters(subscription);
197 FilterNotifier.triggerListeners("subscription.updated", subscription, 203 filterNotifier.emit("subscription.updated", subscription, oldFilters);
198 oldFilters);
199 }, 204 },
200 205
201 /** 206 /**
202 * Adds a user-defined filter to the list 207 * Adds a user-defined filter to the list
203 * @param {Filter} filter 208 * @param {Filter} filter
204 * @param {SpecialSubscription} [subscription] 209 * @param {SpecialSubscription} [subscription]
205 * particular group that the filter should be added to 210 * particular group that the filter should be added to
206 * @param {number} [position] 211 * @param {number} [position]
207 * position within the subscription at which the filter should be added 212 * position within the subscription at which the filter should be added
208 */ 213 */
209 addFilter(filter, subscription, position) 214 addFilter(filter, subscription, position)
210 { 215 {
211 if (!subscription) 216 if (!subscription)
212 { 217 {
213 if (filter.subscriptions.some(s => s instanceof SpecialSubscription && 218 for (let currentSubscription of filter.subscriptions)
214 !s.disabled)) 219 {
215 { 220 if (currentSubscription instanceof SpecialSubscription &&
216 return; // No need to add 221 !currentSubscription.disabled)
222 {
223 return; // No need to add
224 }
217 } 225 }
218 subscription = FilterStorage.getGroupForFilter(filter); 226 subscription = FilterStorage.getGroupForFilter(filter);
219 } 227 }
220 if (!subscription) 228 if (!subscription)
221 { 229 {
222 // No group for this filter exists, create one 230 // No group for this filter exists, create one
223 subscription = SpecialSubscription.createForFilter(filter); 231 subscription = SpecialSubscription.createForFilter(filter);
224 this.addSubscription(subscription); 232 this.addSubscription(subscription);
225 return; 233 return;
226 } 234 }
227 235
228 if (typeof position == "undefined") 236 if (typeof position == "undefined")
229 position = subscription.filters.length; 237 position = subscription.filters.length;
230 238
231 if (filter.subscriptions.indexOf(subscription) < 0) 239 filter.subscriptions.add(subscription);
232 filter.subscriptions.push(subscription);
233 subscription.filters.splice(position, 0, filter); 240 subscription.filters.splice(position, 0, filter);
234 FilterNotifier.triggerListeners("filter.added", filter, subscription, 241 filterNotifier.emit("filter.added", filter, subscription, position);
235 position);
236 }, 242 },
237 243
238 /** 244 /**
239 * Removes a user-defined filter from the list 245 * Removes a user-defined filter from the list
240 * @param {Filter} filter 246 * @param {Filter} filter
241 * @param {SpecialSubscription} [subscription] a particular filter group that 247 * @param {SpecialSubscription} [subscription] a particular filter group that
242 * the filter should be removed from (if ommited will be removed from all 248 * the filter should be removed from (if ommited will be removed from all
243 * subscriptions) 249 * subscriptions)
244 * @param {number} [position] position inside the filter group at which the 250 * @param {number} [position] position inside the filter group at which the
245 * filter should be removed (if ommited all instances will be removed) 251 * filter should be removed (if ommited all instances will be removed)
246 */ 252 */
247 removeFilter(filter, subscription, position) 253 removeFilter(filter, subscription, position)
248 { 254 {
249 let subscriptions = ( 255 let subscriptions = (
250 subscription ? [subscription] : filter.subscriptions.slice() 256 subscription ? [subscription] : filter.subscriptions
251 ); 257 );
252 for (let i = 0; i < subscriptions.length; i++) 258 for (let currentSubscription of subscriptions)
253 { 259 {
254 let currentSubscription = subscriptions[i];
255 if (currentSubscription instanceof SpecialSubscription) 260 if (currentSubscription instanceof SpecialSubscription)
256 { 261 {
257 let positions = []; 262 let positions = [];
258 if (typeof position == "undefined") 263 if (typeof position == "undefined")
259 { 264 {
260 let index = -1; 265 let index = -1;
261 do 266 do
262 { 267 {
263 index = currentSubscription.filters.indexOf(filter, index + 1); 268 index = currentSubscription.filters.indexOf(filter, index + 1);
264 if (index >= 0) 269 if (index >= 0)
265 positions.push(index); 270 positions.push(index);
266 } while (index >= 0); 271 } while (index >= 0);
267 } 272 }
268 else 273 else
269 positions.push(position); 274 positions.push(position);
270 275
271 for (let j = positions.length - 1; j >= 0; j--) 276 for (let j = positions.length - 1; j >= 0; j--)
272 { 277 {
273 let currentPosition = positions[j]; 278 let currentPosition = positions[j];
274 if (currentSubscription.filters[currentPosition] == filter) 279 if (currentSubscription.filters[currentPosition] == filter)
275 { 280 {
276 currentSubscription.filters.splice(currentPosition, 1); 281 currentSubscription.filters.splice(currentPosition, 1);
277 if (currentSubscription.filters.indexOf(filter) < 0) 282 if (currentSubscription.filters.indexOf(filter) < 0)
278 { 283 filter.subscriptions.delete(currentSubscription);
279 let index = filter.subscriptions.indexOf(currentSubscription); 284 filterNotifier.emit("filter.removed", filter, currentSubscription,
280 if (index >= 0) 285 currentPosition);
281 filter.subscriptions.splice(index, 1);
282 }
283 FilterNotifier.triggerListeners(
284 "filter.removed", filter, currentSubscription, currentPosition
285 );
286 } 286 }
287 } 287 }
288 } 288 }
289 } 289 }
290 }, 290 },
291 291
292 /** 292 /**
293 * Moves a user-defined filter to a new position 293 * Moves a user-defined filter to a new position
294 * @param {Filter} filter 294 * @param {Filter} filter
295 * @param {SpecialSubscription} subscription filter group where the filter is 295 * @param {SpecialSubscription} subscription filter group where the filter is
296 * located 296 * located
297 * @param {number} oldPosition current position of the filter 297 * @param {number} oldPosition current position of the filter
298 * @param {number} newPosition new position of the filter 298 * @param {number} newPosition new position of the filter
299 */ 299 */
300 moveFilter(filter, subscription, oldPosition, newPosition) 300 moveFilter(filter, subscription, oldPosition, newPosition)
301 { 301 {
302 if (!(subscription instanceof SpecialSubscription) || 302 if (!(subscription instanceof SpecialSubscription) ||
303 subscription.filters[oldPosition] != filter) 303 subscription.filters[oldPosition] != filter)
304 { 304 {
305 return; 305 return;
306 } 306 }
307 307
308 newPosition = Math.min(Math.max(newPosition, 0), 308 newPosition = Math.min(Math.max(newPosition, 0),
309 subscription.filters.length - 1); 309 subscription.filters.length - 1);
310 if (oldPosition == newPosition) 310 if (oldPosition == newPosition)
311 return; 311 return;
312 312
313 subscription.filters.splice(oldPosition, 1); 313 subscription.filters.splice(oldPosition, 1);
314 subscription.filters.splice(newPosition, 0, filter); 314 subscription.filters.splice(newPosition, 0, filter);
315 FilterNotifier.triggerListeners("filter.moved", filter, subscription, 315 filterNotifier.emit("filter.moved", filter, subscription, oldPosition,
316 oldPosition, newPosition); 316 newPosition);
317 }, 317 },
318 318
319 /** 319 /**
320 * Increases the hit count for a filter by one 320 * Increases the hit count for a filter by one
321 * @param {Filter} filter 321 * @param {Filter} filter
322 */ 322 */
323 increaseHitCount(filter) 323 increaseHitCount(filter)
324 { 324 {
325 if (!Prefs.savestats || !(filter instanceof ActiveFilter)) 325 if (!Prefs.savestats || !(filter instanceof ActiveFilter))
326 return; 326 return;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 for (let subscription of parser.subscriptions) 372 for (let subscription of parser.subscriptions)
373 knownSubscriptions.set(subscription.url, subscription); 373 knownSubscriptions.set(subscription.url, subscription);
374 374
375 this.fileProperties = parser.fileProperties; 375 this.fileProperties = parser.fileProperties;
376 this.subscriptions = parser.subscriptions; 376 this.subscriptions = parser.subscriptions;
377 this.knownSubscriptions = knownSubscriptions; 377 this.knownSubscriptions = knownSubscriptions;
378 Filter.knownFilters = parser.knownFilters; 378 Filter.knownFilters = parser.knownFilters;
379 Subscription.knownSubscriptions = parser.knownSubscriptions; 379 Subscription.knownSubscriptions = parser.knownSubscriptions;
380 380
381 if (!silent) 381 if (!silent)
382 FilterNotifier.triggerListeners("load"); 382 filterNotifier.emit("load");
383 } 383 }
384 }; 384 };
385 }, 385 },
386 386
387 /** 387 /**
388 * Loads all subscriptions from the disk. 388 * Loads all subscriptions from the disk.
389 * @return {Promise} promise resolved or rejected when loading is complete 389 * @return {Promise} promise resolved or rejected when loading is complete
390 */ 390 */
391 loadFromDisk() 391 loadFromDisk()
392 { 392 {
(...skipping 27 matching lines...) Expand all
420 throw new Error("No data in the file"); 420 throw new Error("No data in the file");
421 } 421 }
422 }); 422 });
423 }).catch(error => 423 }).catch(error =>
424 { 424 {
425 Cu.reportError(error); 425 Cu.reportError(error);
426 return tryBackup(1); 426 return tryBackup(1);
427 }).then(() => 427 }).then(() =>
428 { 428 {
429 this.initialized = true; 429 this.initialized = true;
430 FilterNotifier.triggerListeners("load"); 430 filterNotifier.emit("load");
431 }); 431 });
432 }, 432 },
433 433
434 /** 434 /**
435 * Constructs the file name for a patterns.ini backup. 435 * Constructs the file name for a patterns.ini backup.
436 * @param {number} backupIndex 436 * @param {number} backupIndex
437 * number of the backup file (1 being the most recent) 437 * number of the backup file (1 being the most recent)
438 * @return {string} backup file name 438 * @return {string} backup file name
439 */ 439 */
440 getBackupName(backupIndex) 440 getBackupName(backupIndex)
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 return renameBackup(Prefs.patternsbackups - 1); 588 return renameBackup(Prefs.patternsbackups - 1);
589 }).catch(error => 589 }).catch(error =>
590 { 590 {
591 // Errors during backup creation shouldn't prevent writing filters. 591 // Errors during backup creation shouldn't prevent writing filters.
592 Cu.reportError(error); 592 Cu.reportError(error);
593 }).then(() => 593 }).then(() =>
594 { 594 {
595 return IO.writeToFile(this.sourceFile, this.exportData()); 595 return IO.writeToFile(this.sourceFile, this.exportData());
596 }).then(() => 596 }).then(() =>
597 { 597 {
598 FilterNotifier.triggerListeners("save"); 598 filterNotifier.emit("save");
599 }).catch(error => 599 }).catch(error =>
600 { 600 {
601 // If saving failed, report error but continue - we still have to process 601 // If saving failed, report error but continue - we still have to process
602 // flags. 602 // flags.
603 Cu.reportError(error); 603 Cu.reportError(error);
604 }).then(() => 604 }).then(() =>
605 { 605 {
606 this._saving = false; 606 this._saving = false;
607 if (this._needsSave) 607 if (this._needsSave)
608 { 608 {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
655 * Joins subscription's filters to the subscription without any notifications. 655 * Joins subscription's filters to the subscription without any notifications.
656 * @param {Subscription} subscription 656 * @param {Subscription} subscription
657 * filter subscription that should be connected to its filters 657 * filter subscription that should be connected to its filters
658 */ 658 */
659 function addSubscriptionFilters(subscription) 659 function addSubscriptionFilters(subscription)
660 { 660 {
661 if (!FilterStorage.knownSubscriptions.has(subscription.url)) 661 if (!FilterStorage.knownSubscriptions.has(subscription.url))
662 return; 662 return;
663 663
664 for (let filter of subscription.filters) 664 for (let filter of subscription.filters)
665 filter.subscriptions.push(subscription); 665 filter.subscriptions.add(subscription);
666 } 666 }
667 667
668 /** 668 /**
669 * Removes subscription's filters from the subscription without any 669 * Removes subscription's filters from the subscription without any
670 * notifications. 670 * notifications.
671 * @param {Subscription} subscription filter subscription to be removed 671 * @param {Subscription} subscription filter subscription to be removed
672 */ 672 */
673 function removeSubscriptionFilters(subscription) 673 function removeSubscriptionFilters(subscription)
674 { 674 {
675 if (!FilterStorage.knownSubscriptions.has(subscription.url)) 675 if (!FilterStorage.knownSubscriptions.has(subscription.url))
676 return; 676 return;
677 677
678 for (let filter of subscription.filters) 678 for (let filter of subscription.filters)
679 { 679 filter.subscriptions.delete(subscription);
680 let i = filter.subscriptions.indexOf(subscription);
681 if (i >= 0)
682 filter.subscriptions.splice(i, 1);
683 }
684 } 680 }
685
686 /**
687 * Listener returned by FilterStorage.importData(), parses filter data.
688 * @constructor
689 */
690 function INIParser()
691 {
692 this.fileProperties = this.curObj = {};
693 this.subscriptions = [];
694 this.knownFilters = new Map();
695 this.knownSubscriptions = new Map();
696 }
697 INIParser.prototype =
698 {
699 linesProcessed: 0,
700 subscriptions: null,
701 knownFilters: null,
702 knownSubscriptions: null,
703 wantObj: true,
704 fileProperties: null,
705 curObj: null,
706 curSection: null,
707
708 process(val)
709 {
710 let origKnownFilters = Filter.knownFilters;
711 Filter.knownFilters = this.knownFilters;
712 let origKnownSubscriptions = Subscription.knownSubscriptions;
713 Subscription.knownSubscriptions = this.knownSubscriptions;
714 let match;
715 try
716 {
717 if (this.wantObj === true && (match = /^(\w+)=(.*)$/.exec(val)))
718 this.curObj[match[1]] = match[2];
719 else if (val === null || (match = /^\s*\[(.+)\]\s*$/.exec(val)))
720 {
721 if (this.curObj)
722 {
723 // Process current object before going to next section
724 switch (this.curSection)
725 {
726 case "filter":
727 if ("text" in this.curObj)
728 Filter.fromObject(this.curObj);
729 break;
730 case "subscription": {
731 let subscription = Subscription.fromObject(this.curObj);
732 if (subscription)
733 this.subscriptions.push(subscription);
734 break;
735 }
736 case "subscription filters":
737 if (this.subscriptions.length)
738 {
739 let subscription = this.subscriptions[
740 this.subscriptions.length - 1
741 ];
742 for (let text of this.curObj)
743 {
744 let filter = Filter.fromText(text);
745 subscription.filters.push(filter);
746 filter.subscriptions.push(subscription);
747 }
748 }
749 break;
750 }
751 }
752
753 if (val === null)
754 return;
755
756 this.curSection = match[1].toLowerCase();
757 switch (this.curSection)
758 {
759 case "filter":
760 case "subscription":
761 this.wantObj = true;
762 this.curObj = {};
763 break;
764 case "subscription filters":
765 this.wantObj = false;
766 this.curObj = [];
767 break;
768 default:
769 this.wantObj = null;
770 this.curObj = null;
771 }
772 }
773 else if (this.wantObj === false && val)
774 this.curObj.push(val.replace(/\\\[/g, "["));
775 }
776 finally
777 {
778 Filter.knownFilters = origKnownFilters;
779 Subscription.knownSubscriptions = origKnownSubscriptions;
780 }
781 }
782 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld