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

Delta Between Two Patch Sets: lib/synchronizer.js

Issue 29873570: Issue 6923 - Only parse metadata from special comments at the top of the file (Closed)
Left Patch Set: Created Sept. 3, 2018, 6:43 p.m.
Right Patch Set: Addressed comment about tests Created Sept. 10, 2018, 6:50 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 | test/synchronizer.js » ('j') | 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 18 matching lines...) Expand all
29 const {filterNotifier} = require("./filterNotifier"); 29 const {filterNotifier} = require("./filterNotifier");
30 const {Prefs} = require("prefs"); 30 const {Prefs} = require("prefs");
31 const {Subscription, 31 const {Subscription,
32 DownloadableSubscription} = require("./subscriptionClasses"); 32 DownloadableSubscription} = require("./subscriptionClasses");
33 33
34 const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE; 34 const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE;
35 const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR; 35 const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
36 const DEFAULT_EXPIRATION_INTERVAL = 5 * MILLIS_IN_DAY; 36 const DEFAULT_EXPIRATION_INTERVAL = 5 * MILLIS_IN_DAY;
37 37
38 /** 38 /**
39 * The object providing actual downloading functionality. 39 * Downloads filter subscriptions whenever necessary.
40 * @type {Downloader}
41 */ 40 */
42 let downloader = null; 41 class Synchronizer
43
44 /**
45 * This object is responsible for downloading filter subscriptions whenever
46 * necessary.
47 * @class
48 */
49 let Synchronizer = exports.Synchronizer =
50 { 42 {
51 /** 43 /**
52 * Called on module startup. 44 * @hideconstructor
53 */ 45 */
54 init() 46 constructor()
55 { 47 {
56 downloader = new Downloader(this._getDownloadables.bind(this), 48 /**
57 INITIAL_DELAY, CHECK_INTERVAL); 49 * The object providing actual downloading functionality.
50 * @type {Downloader}
51 */
52 this._downloader = new Downloader(this._getDownloadables.bind(this),
53 INITIAL_DELAY, CHECK_INTERVAL);
58 onShutdown.add(() => 54 onShutdown.add(() =>
59 { 55 {
60 downloader.cancel(); 56 this._downloader.cancel();
61 }); 57 });
62 58
63 downloader.onExpirationChange = this._onExpirationChange.bind(this); 59 this._downloader.onExpirationChange = this._onExpirationChange.bind(this);
64 downloader.onDownloadStarted = this._onDownloadStarted.bind(this); 60 this._downloader.onDownloadStarted = this._onDownloadStarted.bind(this);
65 downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this); 61 this._downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this);
66 downloader.onDownloadError = this._onDownloadError.bind(this); 62 this._downloader.onDownloadError = this._onDownloadError.bind(this);
67 }, 63 }
68 64
69 /** 65 /**
70 * Checks whether a subscription is currently being downloaded. 66 * Checks whether a subscription is currently being downloaded.
71 * @param {string} url URL of the subscription 67 * @param {string} url URL of the subscription
72 * @return {boolean} 68 * @returns {boolean}
73 */ 69 */
74 isExecuting(url) 70 isExecuting(url)
75 { 71 {
76 return downloader.isDownloading(url); 72 return this._downloader.isDownloading(url);
77 }, 73 }
78 74
79 /** 75 /**
80 * Starts the download of a subscription. 76 * Starts the download of a subscription.
81 * @param {DownloadableSubscription} subscription 77 * @param {DownloadableSubscription} subscription
82 * Subscription to be downloaded 78 * Subscription to be downloaded
83 * @param {boolean} manual 79 * @param {boolean} manual
84 * true for a manually started download (should not trigger fallback 80 * <code>true</code> for a manually started download (should not trigger
85 * requests) 81 * fallback requests)
86 */ 82 */
87 execute(subscription, manual) 83 execute(subscription, manual)
88 { 84 {
89 downloader.download(this._getDownloadable(subscription, manual)); 85 this._downloader.download(this._getDownloadable(subscription, manual));
90 }, 86 }
91 87
92 /** 88 /**
93 * Yields Downloadable instances for all subscriptions that can be downloaded. 89 * Yields {@link Downloadable} instances for all subscriptions that can be
90 * downloaded.
91 * @yields {Downloadable}
94 */ 92 */
95 *_getDownloadables() 93 *_getDownloadables()
96 { 94 {
97 if (!Prefs.subscriptions_autoupdate) 95 if (!Prefs.subscriptions_autoupdate)
98 return; 96 return;
99 97
100 for (let subscription of FilterStorage.subscriptions) 98 for (let subscription of FilterStorage.subscriptions)
101 { 99 {
102 if (subscription instanceof DownloadableSubscription) 100 if (subscription instanceof DownloadableSubscription)
103 yield this._getDownloadable(subscription, false); 101 yield this._getDownloadable(subscription, false);
104 } 102 }
105 }, 103 }
106 104
107 /** 105 /**
108 * Creates a Downloadable instance for a subscription. 106 * Creates a {@link Downloadable} instance for a subscription.
109 * @param {Subscription} subscription 107 * @param {Subscription} subscription
110 * @param {boolean} manual 108 * @param {boolean} manual
111 * @return {Downloadable} 109 * @returns {Downloadable}
112 */ 110 */
113 _getDownloadable(subscription, manual) 111 _getDownloadable(subscription, manual)
114 { 112 {
115 let result = new Downloadable(subscription.url); 113 let result = new Downloadable(subscription.url);
116 if (subscription.lastDownload != subscription.lastSuccess) 114 if (subscription.lastDownload != subscription.lastSuccess)
117 result.lastError = subscription.lastDownload * MILLIS_IN_SECOND; 115 result.lastError = subscription.lastDownload * MILLIS_IN_SECOND;
118 result.lastCheck = subscription.lastCheck * MILLIS_IN_SECOND; 116 result.lastCheck = subscription.lastCheck * MILLIS_IN_SECOND;
119 result.lastVersion = subscription.version; 117 result.lastVersion = subscription.version;
120 result.softExpiration = subscription.softExpiration * MILLIS_IN_SECOND; 118 result.softExpiration = subscription.softExpiration * MILLIS_IN_SECOND;
121 result.hardExpiration = subscription.expires * MILLIS_IN_SECOND; 119 result.hardExpiration = subscription.expires * MILLIS_IN_SECOND;
122 result.manual = manual; 120 result.manual = manual;
123 result.downloadCount = subscription.downloadCount; 121 result.downloadCount = subscription.downloadCount;
124 return result; 122 return result;
125 }, 123 }
126 124
127 _onExpirationChange(downloadable) 125 _onExpirationChange(downloadable)
128 { 126 {
129 let subscription = Subscription.fromURL(downloadable.url); 127 let subscription = Subscription.fromURL(downloadable.url);
130 subscription.lastCheck = Math.round( 128 subscription.lastCheck = Math.round(
131 downloadable.lastCheck / MILLIS_IN_SECOND 129 downloadable.lastCheck / MILLIS_IN_SECOND
132 ); 130 );
133 subscription.softExpiration = Math.round( 131 subscription.softExpiration = Math.round(
134 downloadable.softExpiration / MILLIS_IN_SECOND 132 downloadable.softExpiration / MILLIS_IN_SECOND
135 ); 133 );
136 subscription.expires = Math.round( 134 subscription.expires = Math.round(
137 downloadable.hardExpiration / MILLIS_IN_SECOND 135 downloadable.hardExpiration / MILLIS_IN_SECOND
138 ); 136 );
139 }, 137 }
140 138
141 _onDownloadStarted(downloadable) 139 _onDownloadStarted(downloadable)
142 { 140 {
143 let subscription = Subscription.fromURL(downloadable.url); 141 let subscription = Subscription.fromURL(downloadable.url);
144 filterNotifier.emit("subscription.downloading", subscription); 142 filterNotifier.emit("subscription.downloading", subscription);
145 }, 143 }
146 144
147 _onDownloadSuccess(downloadable, responseText, errorCallback, 145 _onDownloadSuccess(downloadable, responseText, errorCallback,
148 redirectCallback) 146 redirectCallback)
149 { 147 {
150 let lines = responseText.split(/[\r\n]+/); 148 let lines = responseText.split(/[\r\n]+/);
151 let headerMatch = /\[Adblock(?:\s*Plus\s*([\d.]+)?)?\]/i.exec(lines[0]); 149 let headerMatch = /\[Adblock(?:\s*Plus\s*([\d.]+)?)?\]/i.exec(lines[0]);
152 if (!headerMatch) 150 if (!headerMatch)
153 return errorCallback("synchronize_invalid_data"); 151 return errorCallback("synchronize_invalid_data");
154 let minVersion = headerMatch[1]; 152 let minVersion = headerMatch[1];
155 153
156 let params = { 154 let params = {
157 redirect: null, 155 redirect: null,
158 homepage: null, 156 homepage: null,
159 title: null, 157 title: null,
160 version: null, 158 version: null,
161 expires: null 159 expires: null
162 }; 160 };
163 for (let i = 1; i < lines.length; i++) 161 for (let i = 1; i < lines.length; i++)
164 { 162 {
165 let match = /^\s*!\s*(\S.*?)\s*:\s*(.*)/.exec(lines[i]); 163 let match = /^\s*!\s*(?:(\w+)\s*:\s*(.*)|\S)/.exec(lines[i]);
Sebastian Noack 2018/09/03 18:47:13 You might wonder why I changed this regular expres
Manish Jethani 2018/09/04 07:14:41 Acknowledged.
Sebastian Noack 2018/09/04 15:32:38 You have a point there. But in this regard, IMO we
166 if (!match) 164 if (!match)
167 break; 165 break;
168 166
169 let keyword = match[1].toLowerCase(); 167 if (typeof match[1] != "undefined")
170 if (keyword in params) 168 {
Manish Jethani 2018/09/04 07:14:41 BTW I find in my tests that `params.hasOwnProperty
Sebastian Noack 2018/09/04 14:22:06 IMO the in-operator reads much nicer, and this isn
Manish Jethani 2018/09/04 15:01:45 Acknowledged. (Aside from performance, it's also
171 { 169 let keyword = match[1].toLowerCase();
172 params[keyword] = match[2]; 170 if (params.hasOwnProperty(keyword))
173 lines.splice(i--, 1); 171 {
Manish Jethani 2018/09/04 07:14:41 Since we're considering malformed keywords as well
Sebastian Noack 2018/09/04 14:22:06 Historically, if it's not recognized as supported
Manish Jethani 2018/09/04 15:01:45 OK, fair enough. I'd like to consider not using `s
172 params[keyword] = match[2];
173 lines.splice(i--, 1);
174 }
174 } 175 }
175 } 176 }
176 177
177 if (params.redirect) 178 if (params.redirect)
178 return redirectCallback(params.redirect); 179 return redirectCallback(params.redirect);
179 180
180 // Handle redirects 181 // Handle redirects
181 let subscription = Subscription.fromURL(downloadable.redirectURL || 182 let subscription = Subscription.fromURL(downloadable.redirectURL ||
182 downloadable.url); 183 downloadable.url);
183 if (downloadable.redirectURL && 184 if (downloadable.redirectURL &&
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 if (match[2]) 244 if (match[2])
244 expirationInterval = interval * MILLIS_IN_HOUR; 245 expirationInterval = interval * MILLIS_IN_HOUR;
245 else 246 else
246 expirationInterval = interval * MILLIS_IN_DAY; 247 expirationInterval = interval * MILLIS_IN_DAY;
247 } 248 }
248 } 249 }
249 250
250 let [ 251 let [
251 softExpiration, 252 softExpiration,
252 hardExpiration 253 hardExpiration
253 ] = downloader.processExpirationInterval(expirationInterval); 254 ] = this._downloader.processExpirationInterval(expirationInterval);
254 subscription.softExpiration = Math.round(softExpiration / MILLIS_IN_SECOND); 255 subscription.softExpiration = Math.round(softExpiration / MILLIS_IN_SECOND);
255 subscription.expires = Math.round(hardExpiration / MILLIS_IN_SECOND); 256 subscription.expires = Math.round(hardExpiration / MILLIS_IN_SECOND);
256 257
257 if (minVersion) 258 if (minVersion)
258 subscription.requiredVersion = minVersion; 259 subscription.requiredVersion = minVersion;
259 else 260 else
260 delete subscription.requiredVersion; 261 delete subscription.requiredVersion;
261 262
262 // Process filters 263 // Process filters
263 lines.shift(); 264 lines.shift();
264 let filters = []; 265 let filters = [];
265 for (let line of lines) 266 for (let line of lines)
266 { 267 {
267 line = Filter.normalize(line); 268 line = Filter.normalize(line);
268 if (line) 269 if (line)
269 filters.push(Filter.fromText(line)); 270 filters.push(Filter.fromText(line));
270 } 271 }
271 272
272 FilterStorage.updateSubscriptionFilters(subscription, filters); 273 FilterStorage.updateSubscriptionFilters(subscription, filters);
273 }, 274 }
274 275
275 _onDownloadError(downloadable, downloadURL, error, channelStatus, 276 _onDownloadError(downloadable, downloadURL, error, channelStatus,
276 responseStatus, redirectCallback) 277 responseStatus, redirectCallback)
277 { 278 {
278 let subscription = Subscription.fromURL(downloadable.url); 279 let subscription = Subscription.fromURL(downloadable.url);
279 subscription.lastDownload = Math.round(Date.now() / MILLIS_IN_SECOND); 280 subscription.lastDownload = Math.round(Date.now() / MILLIS_IN_SECOND);
280 subscription.downloadStatus = error; 281 subscription.downloadStatus = error;
281 282
282 // Request fallback URL if necessary - for automatic updates only 283 // Request fallback URL if necessary - for automatic updates only
283 if (!downloadable.manual) 284 if (!downloadable.manual)
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 { 331 {
331 let data = "[Adblock]\n" + 332 let data = "[Adblock]\n" +
332 subscription.filters.map(f => f.text).join("\n"); 333 subscription.filters.map(f => f.text).join("\n");
333 redirectCallback("data:text/plain," + encodeURIComponent(data)); 334 redirectCallback("data:text/plain," + encodeURIComponent(data));
334 } 335 }
335 }, false); 336 }, false);
336 request.send(null); 337 request.send(null);
337 } 338 }
338 } 339 }
339 } 340 }
340 }; 341 }
341 Synchronizer.init(); 342
343 /**
344 * This object is responsible for downloading filter subscriptions whenever
345 * necessary.
346 * @type {Synchronizer}
347 */
348 let synchronizer = new Synchronizer();
349
350 exports.Synchronizer = synchronizer;
LEFTRIGHT

Powered by Google App Engine
This is Rietveld