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

Side by Side Diff: lib/subscriptionClasses.js

Issue 29335650: Issue 2595 - Use the core code from adblockpluscore (Closed)
Patch Set: Created Feb. 4, 2016, 6:35 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/notification.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
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /**
19 * @fileOverview Definition of Subscription class and its subclasses.
20 */
21
22 Cu.import("resource://gre/modules/Services.jsm");
23
24 let {ActiveFilter, BlockingFilter, WhitelistFilter, ElemHideBase} = require("fil terClasses");
25 let {FilterNotifier} = require("filterNotifier");
26
27 /**
28 * Abstract base class for filter subscriptions
29 *
30 * @param {String} url download location of the subscription
31 * @param {String} [title] title of the filter subscription
32 * @constructor
33 */
34 function Subscription(url, title)
35 {
36 this.url = url;
37 this.filters = [];
38 if (title)
39 this._title = title;
40 else
41 {
42 let {Utils} = require("utils");
43 this._title = Utils.getString("newGroup_title");
44 }
45 Subscription.knownSubscriptions[url] = this;
46 }
47 exports.Subscription = Subscription;
48
49 Subscription.prototype =
50 {
51 /**
52 * Download location of the subscription
53 * @type String
54 */
55 url: null,
56
57 /**
58 * Filters contained in the filter subscription
59 * @type Filter[]
60 */
61 filters: null,
62
63 _title: null,
64 _fixedTitle: false,
65 _disabled: false,
66
67 /**
68 * Title of the filter subscription
69 * @type String
70 */
71 get title()
72 {
73 return this._title;
74 },
75 set title(value)
76 {
77 if (value != this._title)
78 {
79 let oldValue = this._title;
80 this._title = value;
81 FilterNotifier.triggerListeners("subscription.title", this, value, oldValu e);
82 }
83 return this._title;
84 },
85
86 /**
87 * Determines whether the title should be editable
88 * @type Boolean
89 */
90 get fixedTitle()
91 {
92 return this._fixedTitle;
93 },
94 set fixedTitle(value)
95 {
96 if (value != this._fixedTitle)
97 {
98 let oldValue = this._fixedTitle;
99 this._fixedTitle = value;
100 FilterNotifier.triggerListeners("subscription.fixedTitle", this, value, ol dValue);
101 }
102 return this._fixedTitle;
103 },
104
105 /**
106 * Defines whether the filters in the subscription should be disabled
107 * @type Boolean
108 */
109 get disabled()
110 {
111 return this._disabled;
112 },
113 set disabled(value)
114 {
115 if (value != this._disabled)
116 {
117 let oldValue = this._disabled;
118 this._disabled = value;
119 FilterNotifier.triggerListeners("subscription.disabled", this, value, oldV alue);
120 }
121 return this._disabled;
122 },
123
124 /**
125 * Serializes the subscription to an array of strings for writing out on the d isk.
126 * @param {string[]} buffer buffer to push the serialization results into
127 */
128 serialize: function(buffer)
129 {
130 buffer.push("[Subscription]");
131 buffer.push("url=" + this.url);
132 buffer.push("title=" + this._title);
133 if (this._fixedTitle)
134 buffer.push("fixedTitle=true");
135 if (this._disabled)
136 buffer.push("disabled=true");
137 },
138
139 serializeFilters: function(buffer)
140 {
141 for (let filter of this.filters)
142 buffer.push(filter.text.replace(/\[/g, "\\["));
143 },
144
145 toString: function()
146 {
147 let buffer = [];
148 this.serialize(buffer);
149 return buffer.join("\n");
150 }
151 };
152
153 /**
154 * Cache for known filter subscriptions, maps URL to subscription objects.
155 * @type Object
156 */
157 Subscription.knownSubscriptions = Object.create(null);
158
159 /**
160 * Returns a subscription from its URL, creates a new one if necessary.
161 * @param {String} url URL of the subscription
162 * @return {Subscription} subscription or null if the subscription couldn't be c reated
163 */
164 Subscription.fromURL = function(url)
165 {
166 if (url in Subscription.knownSubscriptions)
167 return Subscription.knownSubscriptions[url];
168
169 try
170 {
171 // Test URL for validity
172 url = Services.io.newURI(url, null, null).spec;
173 return new DownloadableSubscription(url, null);
174 }
175 catch (e)
176 {
177 return new SpecialSubscription(url);
178 }
179 };
180
181 /**
182 * Deserializes a subscription
183 *
184 * @param {Object} obj map of serialized properties and their values
185 * @return {Subscription} subscription or null if the subscription couldn't be c reated
186 */
187 Subscription.fromObject = function(obj)
188 {
189 let result;
190 try
191 {
192 obj.url = Services.io.newURI(obj.url, null, null).spec;
193
194 // URL is valid - this is a downloadable subscription
195 result = new DownloadableSubscription(obj.url, obj.title);
196 if ("downloadStatus" in obj)
197 result._downloadStatus = obj.downloadStatus;
198 if ("lastSuccess" in obj)
199 result.lastSuccess = parseInt(obj.lastSuccess, 10) || 0;
200 if ("lastCheck" in obj)
201 result._lastCheck = parseInt(obj.lastCheck, 10) || 0;
202 if ("expires" in obj)
203 result.expires = parseInt(obj.expires, 10) || 0;
204 if ("softExpiration" in obj)
205 result.softExpiration = parseInt(obj.softExpiration, 10) || 0;
206 if ("errors" in obj)
207 result._errors = parseInt(obj.errors, 10) || 0;
208 if ("version" in obj)
209 result.version = parseInt(obj.version, 10) || 0;
210 if ("requiredVersion" in obj)
211 {
212 let {addonVersion} = require("info");
213 result.requiredVersion = obj.requiredVersion;
214 if (Services.vc.compare(result.requiredVersion, addonVersion) > 0)
215 result.upgradeRequired = true;
216 }
217 if ("homepage" in obj)
218 result._homepage = obj.homepage;
219 if ("lastDownload" in obj)
220 result._lastDownload = parseInt(obj.lastDownload, 10) || 0;
221 if ("downloadCount" in obj)
222 result.downloadCount = parseInt(obj.downloadCount, 10) || 0;
223 }
224 catch (e)
225 {
226 // Invalid URL - custom filter group
227 if (!("title" in obj))
228 {
229 // Backwards compatibility - titles and filter types were originally
230 // determined by group identifier.
231 if (obj.url == "~wl~")
232 obj.defaults = "whitelist";
233 else if (obj.url == "~fl~")
234 obj.defaults = "blocking";
235 else if (obj.url == "~eh~")
236 obj.defaults = "elemhide";
237 if ("defaults" in obj)
238 {
239 let {Utils} = require("utils");
240 obj.title = Utils.getString(obj.defaults + "Group_title");
241 }
242 }
243 result = new SpecialSubscription(obj.url, obj.title);
244 if ("defaults" in obj)
245 result.defaults = obj.defaults.split(" ");
246 }
247 if ("fixedTitle" in obj)
248 result._fixedTitle = (obj.fixedTitle == "true");
249 if ("disabled" in obj)
250 result._disabled = (obj.disabled == "true");
251
252 return result;
253 };
254
255 /**
256 * Class for special filter subscriptions (user's filters)
257 * @param {String} url see Subscription()
258 * @param {String} [title] see Subscription()
259 * @constructor
260 * @augments Subscription
261 */
262 function SpecialSubscription(url, title)
263 {
264 Subscription.call(this, url, title);
265 }
266 exports.SpecialSubscription = SpecialSubscription;
267
268 SpecialSubscription.prototype =
269 {
270 __proto__: Subscription.prototype,
271
272 /**
273 * Filter types that should be added to this subscription by default
274 * (entries should correspond to keys in SpecialSubscription.defaultsMap).
275 * @type string[]
276 */
277 defaults: null,
278
279 /**
280 * Tests whether a filter should be added to this group by default
281 * @param {Filter} filter filter to be tested
282 * @return {Boolean}
283 */
284 isDefaultFor: function(filter)
285 {
286 if (this.defaults && this.defaults.length)
287 {
288 for (let type of this.defaults)
289 {
290 if (filter instanceof SpecialSubscription.defaultsMap[type])
291 return true;
292 if (!(filter instanceof ActiveFilter) && type == "blacklist")
293 return true;
294 }
295 }
296
297 return false;
298 },
299
300 /**
301 * See Subscription.serialize()
302 */
303 serialize: function(buffer)
304 {
305 Subscription.prototype.serialize.call(this, buffer);
306 if (this.defaults && this.defaults.length)
307 buffer.push("defaults=" + this.defaults.filter((type) => type in SpecialSu bscription.defaultsMap).join(" "));
308 if (this._lastDownload)
309 buffer.push("lastDownload=" + this._lastDownload);
310 }
311 };
312
313 SpecialSubscription.defaultsMap = {
314 __proto__: null,
315 "whitelist": WhitelistFilter,
316 "blocking": BlockingFilter,
317 "elemhide": ElemHideBase
318 };
319
320 /**
321 * Creates a new user-defined filter group.
322 * @param {String} [title] title of the new filter group
323 * @result {SpecialSubscription}
324 */
325 SpecialSubscription.create = function(title)
326 {
327 let url;
328 do
329 {
330 url = "~user~" + Math.round(Math.random()*1000000);
331 } while (url in Subscription.knownSubscriptions);
332 return new SpecialSubscription(url, title);
333 };
334
335 /**
336 * Creates a new user-defined filter group and adds the given filter to it.
337 * This group will act as the default group for this filter type.
338 */
339 SpecialSubscription.createForFilter = function(/**Filter*/ filter) /**SpecialSub scription*/
340 {
341 let subscription = SpecialSubscription.create();
342 subscription.filters.push(filter);
343 for (let type in SpecialSubscription.defaultsMap)
344 {
345 if (filter instanceof SpecialSubscription.defaultsMap[type])
346 subscription.defaults = [type];
347 }
348 if (!subscription.defaults)
349 subscription.defaults = ["blocking"];
350
351 let {Utils} = require("utils");
352 subscription.title = Utils.getString(subscription.defaults[0] + "Group_title") ;
353 return subscription;
354 };
355
356 /**
357 * Abstract base class for regular filter subscriptions (both internally and ext ernally updated)
358 * @param {String} url see Subscription()
359 * @param {String} [title] see Subscription()
360 * @constructor
361 * @augments Subscription
362 */
363 function RegularSubscription(url, title)
364 {
365 Subscription.call(this, url, title || url);
366 }
367 exports.RegularSubscription = RegularSubscription;
368
369 RegularSubscription.prototype =
370 {
371 __proto__: Subscription.prototype,
372
373 _homepage: null,
374 _lastDownload: 0,
375
376 /**
377 * Filter subscription homepage if known
378 * @type String
379 */
380 get homepage()
381 {
382 return this._homepage;
383 },
384 set homepage(value)
385 {
386 if (value != this._homepage)
387 {
388 let oldValue = this._homepage;
389 this._homepage = value;
390 FilterNotifier.triggerListeners("subscription.homepage", this, value, oldV alue);
391 }
392 return this._homepage;
393 },
394
395 /**
396 * Time of the last subscription download (in seconds since the beginning of t he epoch)
397 * @type Number
398 */
399 get lastDownload()
400 {
401 return this._lastDownload;
402 },
403 set lastDownload(value)
404 {
405 if (value != this._lastDownload)
406 {
407 let oldValue = this._lastDownload;
408 this._lastDownload = value;
409 FilterNotifier.triggerListeners("subscription.lastDownload", this, value, oldValue);
410 }
411 return this._lastDownload;
412 },
413
414 /**
415 * See Subscription.serialize()
416 */
417 serialize: function(buffer)
418 {
419 Subscription.prototype.serialize.call(this, buffer);
420 if (this._homepage)
421 buffer.push("homepage=" + this._homepage);
422 if (this._lastDownload)
423 buffer.push("lastDownload=" + this._lastDownload);
424 }
425 };
426
427 /**
428 * Class for filter subscriptions updated externally (by other extension)
429 * @param {String} url see Subscription()
430 * @param {String} [title] see Subscription()
431 * @constructor
432 * @augments RegularSubscription
433 */
434 function ExternalSubscription(url, title)
435 {
436 RegularSubscription.call(this, url, title);
437 }
438 exports.ExternalSubscription = ExternalSubscription;
439
440 ExternalSubscription.prototype =
441 {
442 __proto__: RegularSubscription.prototype,
443
444 /**
445 * See Subscription.serialize()
446 */
447 serialize: function(buffer)
448 {
449 throw new Error("Unexpected call, external subscriptions should not be seria lized");
450 }
451 };
452
453 /**
454 * Class for filter subscriptions updated externally (by other extension)
455 * @param {String} url see Subscription()
456 * @param {String} [title] see Subscription()
457 * @constructor
458 * @augments RegularSubscription
459 */
460 function DownloadableSubscription(url, title)
461 {
462 RegularSubscription.call(this, url, title);
463 }
464 exports.DownloadableSubscription = DownloadableSubscription;
465
466 DownloadableSubscription.prototype =
467 {
468 __proto__: RegularSubscription.prototype,
469
470 _downloadStatus: null,
471 _lastCheck: 0,
472 _errors: 0,
473
474 /**
475 * Status of the last download (ID of a string)
476 * @type String
477 */
478 get downloadStatus()
479 {
480 return this._downloadStatus;
481 },
482 set downloadStatus(value)
483 {
484 let oldValue = this._downloadStatus;
485 this._downloadStatus = value;
486 FilterNotifier.triggerListeners("subscription.downloadStatus", this, value, oldValue);
487 return this._downloadStatus;
488 },
489
490 /**
491 * Time of the last successful download (in seconds since the beginning of the
492 * epoch).
493 */
494 lastSuccess: 0,
495
496 /**
497 * Time when the subscription was considered for an update last time (in secon ds
498 * since the beginning of the epoch). This will be used to increase softExpira tion
499 * if the user doesn't use Adblock Plus for some time.
500 * @type Number
501 */
502 get lastCheck()
503 {
504 return this._lastCheck;
505 },
506 set lastCheck(value)
507 {
508 if (value != this._lastCheck)
509 {
510 let oldValue = this._lastCheck;
511 this._lastCheck = value;
512 FilterNotifier.triggerListeners("subscription.lastCheck", this, value, old Value);
513 }
514 return this._lastCheck;
515 },
516
517 /**
518 * Hard expiration time of the filter subscription (in seconds since the begin ning of the epoch)
519 * @type Number
520 */
521 expires: 0,
522
523 /**
524 * Soft expiration time of the filter subscription (in seconds since the begin ning of the epoch)
525 * @type Number
526 */
527 softExpiration: 0,
528
529 /**
530 * Number of download failures since last success
531 * @type Number
532 */
533 get errors()
534 {
535 return this._errors;
536 },
537 set errors(value)
538 {
539 if (value != this._errors)
540 {
541 let oldValue = this._errors;
542 this._errors = value;
543 FilterNotifier.triggerListeners("subscription.errors", this, value, oldVal ue);
544 }
545 return this._errors;
546 },
547
548 /**
549 * Version of the subscription data retrieved on last successful download
550 * @type Number
551 */
552 version: 0,
553
554 /**
555 * Minimal Adblock Plus version required for this subscription
556 * @type String
557 */
558 requiredVersion: null,
559
560 /**
561 * Should be true if requiredVersion is higher than current Adblock Plus versi on
562 * @type Boolean
563 */
564 upgradeRequired: false,
565
566 /**
567 * Number indicating how often the object was downloaded.
568 * @type Number
569 */
570 downloadCount: 0,
571
572 /**
573 * See Subscription.serialize()
574 */
575 serialize: function(buffer)
576 {
577 RegularSubscription.prototype.serialize.call(this, buffer);
578 if (this.downloadStatus)
579 buffer.push("downloadStatus=" + this.downloadStatus);
580 if (this.lastSuccess)
581 buffer.push("lastSuccess=" + this.lastSuccess);
582 if (this.lastCheck)
583 buffer.push("lastCheck=" + this.lastCheck);
584 if (this.expires)
585 buffer.push("expires=" + this.expires);
586 if (this.softExpiration)
587 buffer.push("softExpiration=" + this.softExpiration);
588 if (this.errors)
589 buffer.push("errors=" + this.errors);
590 if (this.version)
591 buffer.push("version=" + this.version);
592 if (this.requiredVersion)
593 buffer.push("requiredVersion=" + this.requiredVersion);
594 if (this.downloadCount)
595 buffer.push("downloadCount=" + this.downloadCount);
596 }
597 };
OLDNEW
« no previous file with comments | « lib/notification.js ('k') | lib/synchronizer.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld