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

Delta Between Two Patch Sets: lib/notification.js

Issue 5330039625220096: Issue 1162 - Cache notification URL matcher
Left Patch Set: Rebased to e2203d4fd258 Created Jan. 29, 2018, 12:44 p.m.
Right Patch Set: Fixed regression: Error if notification data not yet initialized Created Jan. 29, 2018, 3:36 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 | « no previous file | 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
(...skipping 20 matching lines...) Expand all
31 31
32 const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE; 32 const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE;
33 const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR; 33 const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
34 const EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY; 34 const EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY;
35 const TYPE = { 35 const TYPE = {
36 information: 0, 36 information: 0,
37 question: 1, 37 question: 1,
38 relentless: 2, 38 relentless: 2,
39 critical: 3 39 critical: 3
40 }; 40 };
41 const MATCHER = Symbol("Notification matcher");
41 42
42 let showListeners = []; 43 let showListeners = [];
43 let questionListeners = {}; 44 let questionListeners = {};
44 45
45 function getNumericalSeverity(notification) 46 function getNumericalSeverity(notification)
46 { 47 {
47 if (notification.type in TYPE) 48 if (notification.type in TYPE)
48 return TYPE[notification.type]; 49 return TYPE[notification.type];
49 return TYPE.information; 50 return TYPE.information;
50 } 51 }
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 96
96 // Compare version suffix (e.g. 0.1alpha < 0.1b1 < 01.b2 < 0.1). 97 // Compare version suffix (e.g. 0.1alpha < 0.1b1 < 01.b2 < 0.1).
97 // However, note that this is a simple string comparision, meaning: b10 < b2 98 // However, note that this is a simple string comparision, meaning: b10 < b2
98 if (tail1 == tail2) 99 if (tail1 == tail2)
99 return 0; 100 return 0;
100 if (!tail1 || tail2 && tail1 > tail2) 101 if (!tail1 || tail2 && tail1 > tail2)
101 return 1; 102 return 1;
102 return -1; 103 return -1;
103 } 104 }
104 105
106 /**
107 * Initializes notification's matcher based on notification's URL filters
108 * @param {Object} notification
109 */
105 function initNotificationMatcher(notification) 110 function initNotificationMatcher(notification)
106 { 111 {
107 if ("_matcher" in notification || !(notification.urlFilters instanceof Array)) 112 if (MATCHER in notification || !(notification.urlFilters instanceof Array))
108 return; 113 return;
109 114
110 let matcher = new Matcher(); 115 let matcher = new Matcher();
111 for (let urlFilter of notification.urlFilters) 116 for (let urlFilter of notification.urlFilters)
117 {
112 matcher.add(Filter.fromText(urlFilter)); 118 matcher.add(Filter.fromText(urlFilter));
113 matcher.toJSON = () => {}; 119 }
114 notification._matcher = matcher; 120 notification[MATCHER] = matcher;
121 }
122
123 /**
124 * Matches URL against notification's URL filters
125 * @param {Object} notification
126 * @param {string} [url]
127 * @return {boolean} whether notification and URL match
128 */
129 function matchesUrl(notification, url)
130 {
131 // No matching necessary if there's nothing to match
132 if (typeof url !== "string" && !(MATCHER in notification))
133 return true;
134
135 // Notification shouldn't match if extension is disabled
136 if (!Prefs.enabled)
137 return false;
138
139 // Notification shouldn't match if matching cannot be done
140 if (typeof url !== "string" || !(MATCHER in notification))
141 return false;
sergei 2018/01/30 17:25:05 It somehow conflicts with above if (typeof url !==
Thomas Greiner 2018/01/30 19:17:53 The logic behind it is that if the notification do
sergei 2018/01/30 21:06:48 Acknowledged.
142
143 let host;
144 try
145 {
146 host = new URL(url).hostname;
147 }
148 catch (e)
149 {
150 host = "";
151 }
152
153 // Notification shouldn't match if extension is disabled on provided domain
154 let exception = defaultMatcher.matchesAny(
155 url, RegExpFilter.typeMap.DOCUMENT, host, false, null
156 );
157 if (exception instanceof WhitelistFilter)
158 return false;
159
160 // Notification should match if one of its filters matches
161 let filter = notification[MATCHER].matchesAny(
162 url, RegExpFilter.typeMap.DOCUMENT, host, false, null
163 );
164 return !!filter;
115 } 165 }
116 166
117 /** 167 /**
118 * The object providing actual downloading functionality. 168 * The object providing actual downloading functionality.
119 * @type {Downloader} 169 * @type {Downloader}
120 */ 170 */
121 let downloader = null; 171 let downloader = null;
172
173 /**
174 * List of notifications provided by the extension
175 * @type {Object[]}
176 */
122 let localData = []; 177 let localData = [];
123 let remoteData = [];
124 178
125 /** 179 /**
126 * Regularly fetches notifications and decides which to show. 180 * Regularly fetches notifications and decides which to show.
127 * @class 181 * @class
128 */ 182 */
129 let Notification = exports.Notification = 183 let Notification = exports.Notification =
130 { 184 {
131 /** 185 /**
132 * Called on module startup. 186 * Called on module startup.
133 */ 187 */
134 init() 188 init()
135 { 189 {
136 let notificationdata = Prefs.notificationdata.data; 190 let {data} = Prefs.notificationdata;
sergei 2018/01/30 17:25:05 Prefs' properties can be not ready yet, I would re
sergei 2018/01/30 17:28:24 Perhaps alternatively we could do it in `matchesUr
Thomas Greiner 2018/01/30 19:17:53 In theory that's correct but in practice this is n
sergei 2018/01/30 21:06:48 It does happen on practice (at least I observed th
kzar 2018/01/31 11:06:27 How about using the Prefs.untilLoaded Promise?
sergei 2018/02/05 12:49:34 It seems the best option.
137 if (notificationdata) 191 if (data)
138 { 192 {
139 for (let notification of notificationdata.notifications) 193 for (let notification of data.notifications)
194 {
140 initNotificationMatcher(notification); 195 initNotificationMatcher(notification);
141 remoteData = notificationdata.notifications; 196 }
142 } 197 }
143 198
144 downloader = new Downloader(this._getDownloadables.bind(this), 199 downloader = new Downloader(this._getDownloadables.bind(this),
145 INITIAL_DELAY, CHECK_INTERVAL); 200 INITIAL_DELAY, CHECK_INTERVAL);
146 downloader.onExpirationChange = this._onExpirationChange.bind(this); 201 downloader.onExpirationChange = this._onExpirationChange.bind(this);
147 downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this); 202 downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this);
148 downloader.onDownloadError = this._onDownloadError.bind(this); 203 downloader.onDownloadError = this._onDownloadError.bind(this);
149 onShutdown.add(() => downloader.cancel()); 204 onShutdown.add(() => downloader.cancel());
150 }, 205 },
151 206
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 for (let notification of data.notifications) 245 for (let notification of data.notifications)
191 { 246 {
192 if ("severity" in notification) 247 if ("severity" in notification)
193 { 248 {
194 if (!("type" in notification)) 249 if (!("type" in notification))
195 notification.type = notification.severity; 250 notification.type = notification.severity;
196 delete notification.severity; 251 delete notification.severity;
197 } 252 }
198 initNotificationMatcher(notification); 253 initNotificationMatcher(notification);
199 } 254 }
200 remoteData = data.notifications;
201 Prefs.notificationdata.data = data; 255 Prefs.notificationdata.data = data;
202 } 256 }
203 catch (e) 257 catch (e)
204 { 258 {
205 Cu.reportError(e); 259 Cu.reportError(e);
206 errorCallback("synchronize_invalid_data"); 260 errorCallback("synchronize_invalid_data");
207 return; 261 return;
208 } 262 }
209 263
210 Prefs.notificationdata.lastError = 0; 264 Prefs.notificationdata.lastError = 0;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 showListeners.splice(index, 1); 303 showListeners.splice(index, 1);
250 }, 304 },
251 305
252 /** 306 /**
253 * Determines which notification is to be shown next. 307 * Determines which notification is to be shown next.
254 * @param {string} url URL to match notifications to (optional) 308 * @param {string} url URL to match notifications to (optional)
255 * @return {Object} notification to be shown, or null if there is none 309 * @return {Object} notification to be shown, or null if there is none
256 */ 310 */
257 _getNextToShow(url) 311 _getNextToShow(url)
258 { 312 {
313 let remoteData = [];
314 if (typeof Prefs.notificationdata.data == "object" &&
315 Prefs.notificationdata.data.notifications instanceof Array)
316 {
317 remoteData = Prefs.notificationdata.data.notifications;
318 }
259 let notifications = localData.concat(remoteData); 319 let notifications = localData.concat(remoteData);
260 if (notifications.length === 0) 320 if (notifications.length === 0)
261 return null; 321 return null;
262 322
263 const {addonName, addonVersion, application, 323 const {addonName, addonVersion, application,
264 applicationVersion, platform, platformVersion} = require("info"); 324 applicationVersion, platform, platformVersion} = require("info");
265 325
266 let targetChecks = { 326 let targetChecks = {
267 extension: v => v == addonName, 327 extension: v => v == addonName,
268 extensionMinVersion: 328 extensionMinVersion:
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 continue; 367 continue;
308 } 368 }
309 369
310 if (notification.type !== "relentless" && 370 if (notification.type !== "relentless" &&
311 Prefs.notifications_ignoredcategories.indexOf("*") != -1) 371 Prefs.notifications_ignoredcategories.indexOf("*") != -1)
312 { 372 {
313 continue; 373 continue;
314 } 374 }
315 } 375 }
316 376
317 if (typeof url === "string" || "_matcher" in notification) 377 if (!matchesUrl(notification, url))
Thomas Greiner 2018/01/29 15:39:20 This block contains relevant changes that were mad
318 { 378 continue;
319 if (Prefs.enabled && typeof url === "string" &&
320 "_matcher" in notification)
321 {
322 let host;
323 try
324 {
325 host = new URL(url).hostname;
326 }
327 catch (e)
328 {
329 host = "";
330 }
331
332 let exception = defaultMatcher.matchesAny(
333 url, RegExpFilter.typeMap.DOCUMENT, host, false, null
334 );
335 if (exception instanceof WhitelistFilter)
336 continue;
337
338 if (!notification._matcher.matchesAny(url,
339 RegExpFilter.typeMap.DOCUMENT, host, false, null))
340 continue;
341 }
342 else
343 continue;
344 }
345 379
346 if (notification.targets instanceof Array) 380 if (notification.targets instanceof Array)
347 { 381 {
348 let match = false; 382 let match = false;
349 383
350 for (let target of notification.targets) 384 for (let target of notification.targets)
351 { 385 {
352 if (Object.keys(target).every(key => 386 if (Object.keys(target).every(key =>
353 targetChecks.hasOwnProperty(key) && 387 targetChecks.hasOwnProperty(key) &&
354 targetChecks[key](target[key]))) 388 targetChecks[key](target[key])))
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 else if (index != -1 && forceValue !== true) 562 else if (index != -1 && forceValue !== true)
529 categories.splice(index, 1); 563 categories.splice(index, 1);
530 564
531 // HACK: JSON values aren't saved unless they are assigned a 565 // HACK: JSON values aren't saved unless they are assigned a
532 // different object. 566 // different object.
533 Prefs.notifications_ignoredcategories = 567 Prefs.notifications_ignoredcategories =
534 JSON.parse(JSON.stringify(categories)); 568 JSON.parse(JSON.stringify(categories));
535 } 569 }
536 }; 570 };
537 Notification.init(); 571 Notification.init();
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld