|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /** |
|
8 * Main entry point to get references to all the back-end objects. |
|
9 */ |
|
10 |
|
11 "use strict"; |
|
12 |
|
13 this.EXPORTED_SYMBOLS = [ |
|
14 "Downloads", |
|
15 ]; |
|
16 |
|
17 //////////////////////////////////////////////////////////////////////////////// |
|
18 //// Globals |
|
19 |
|
20 const Cc = Components.classes; |
|
21 const Ci = Components.interfaces; |
|
22 const Cu = Components.utils; |
|
23 const Cr = Components.results; |
|
24 |
|
25 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
26 Cu.import("resource://gre/modules/DownloadCore.jsm"); |
|
27 |
|
28 XPCOMUtils.defineLazyModuleGetter(this, "DownloadCombinedList", |
|
29 "resource://gre/modules/DownloadList.jsm"); |
|
30 XPCOMUtils.defineLazyModuleGetter(this, "DownloadIntegration", |
|
31 "resource://gre/modules/DownloadIntegration.jsm"); |
|
32 XPCOMUtils.defineLazyModuleGetter(this, "DownloadList", |
|
33 "resource://gre/modules/DownloadList.jsm"); |
|
34 XPCOMUtils.defineLazyModuleGetter(this, "DownloadSummary", |
|
35 "resource://gre/modules/DownloadList.jsm"); |
|
36 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper", |
|
37 "resource://gre/modules/DownloadUIHelper.jsm"); |
|
38 XPCOMUtils.defineLazyModuleGetter(this, "Promise", |
|
39 "resource://gre/modules/Promise.jsm"); |
|
40 XPCOMUtils.defineLazyModuleGetter(this, "Task", |
|
41 "resource://gre/modules/Task.jsm"); |
|
42 |
|
43 //////////////////////////////////////////////////////////////////////////////// |
|
44 //// Downloads |
|
45 |
|
46 /** |
|
47 * This object is exposed directly to the consumers of this JavaScript module, |
|
48 * and provides the only entry point to get references to back-end objects. |
|
49 */ |
|
50 this.Downloads = { |
|
51 /** |
|
52 * Work on downloads that were not started from a private browsing window. |
|
53 */ |
|
54 get PUBLIC() "{Downloads.PUBLIC}", |
|
55 /** |
|
56 * Work on downloads that were started from a private browsing window. |
|
57 */ |
|
58 get PRIVATE() "{Downloads.PRIVATE}", |
|
59 /** |
|
60 * Work on both Downloads.PRIVATE and Downloads.PUBLIC downloads. |
|
61 */ |
|
62 get ALL() "{Downloads.ALL}", |
|
63 |
|
64 /** |
|
65 * Creates a new Download object. |
|
66 * |
|
67 * @param aProperties |
|
68 * Provides the initial properties for the newly created download. |
|
69 * This matches the serializable representation of a Download object. |
|
70 * Some of the most common properties in this object include: |
|
71 * { |
|
72 * source: String containing the URI for the download source. |
|
73 * Alternatively, may be an nsIURI, a DownloadSource object, |
|
74 * or an object with the following properties: |
|
75 * { |
|
76 * url: String containing the URI for the download source. |
|
77 * isPrivate: Indicates whether the download originated from a |
|
78 * private window. If omitted, the download is public. |
|
79 * referrer: String containing the referrer URI of the download |
|
80 * source. Can be omitted or null if no referrer should |
|
81 * be sent or the download source is not HTTP. |
|
82 * }, |
|
83 * target: String containing the path of the target file. |
|
84 * Alternatively, may be an nsIFile, a DownloadTarget object, |
|
85 * or an object with the following properties: |
|
86 * { |
|
87 * path: String containing the path of the target file. |
|
88 * }, |
|
89 * saver: String representing the class of the download operation. |
|
90 * If omitted, defaults to "copy". Alternatively, may be the |
|
91 * serializable representation of a DownloadSaver object. |
|
92 * } |
|
93 * |
|
94 * @return {Promise} |
|
95 * @resolves The newly created Download object. |
|
96 * @rejects JavaScript exception. |
|
97 */ |
|
98 createDownload: function D_createDownload(aProperties) |
|
99 { |
|
100 try { |
|
101 return Promise.resolve(Download.fromSerializable(aProperties)); |
|
102 } catch (ex) { |
|
103 return Promise.reject(ex); |
|
104 } |
|
105 }, |
|
106 |
|
107 /** |
|
108 * Downloads data from a remote network location to a local file. |
|
109 * |
|
110 * This download method does not provide user interface, or the ability to |
|
111 * cancel or restart the download programmatically. For that, you should |
|
112 * obtain a reference to a Download object using the createDownload function. |
|
113 * |
|
114 * Since the download cannot be restarted, any partially downloaded data will |
|
115 * not be kept in case the download fails. |
|
116 * |
|
117 * @param aSource |
|
118 * String containing the URI for the download source. Alternatively, |
|
119 * may be an nsIURI or a DownloadSource object. |
|
120 * @param aTarget |
|
121 * String containing the path of the target file. Alternatively, may |
|
122 * be an nsIFile or a DownloadTarget object. |
|
123 * @param aOptions |
|
124 * An optional object used to control the behavior of this function. |
|
125 * You may pass an object with a subset of the following fields: |
|
126 * { |
|
127 * isPrivate: Indicates whether the download originated from a |
|
128 * private window. |
|
129 * } |
|
130 * |
|
131 * @return {Promise} |
|
132 * @resolves When the download has finished successfully. |
|
133 * @rejects JavaScript exception if the download failed. |
|
134 */ |
|
135 fetch: function (aSource, aTarget, aOptions) { |
|
136 return this.createDownload({ |
|
137 source: aSource, |
|
138 target: aTarget, |
|
139 }).then(function D_SD_onSuccess(aDownload) { |
|
140 if (aOptions && ("isPrivate" in aOptions)) { |
|
141 aDownload.source.isPrivate = aOptions.isPrivate; |
|
142 } |
|
143 return aDownload.start(); |
|
144 }); |
|
145 }, |
|
146 |
|
147 /** |
|
148 * Retrieves the specified type of DownloadList object. There is one download |
|
149 * list for each type, and this method always retrieves a reference to the |
|
150 * same download list when called with the same argument. |
|
151 * |
|
152 * Calling this function may cause the list of public downloads to be reloaded |
|
153 * from the previous session, if it wasn't loaded already. |
|
154 * |
|
155 * @param aType |
|
156 * This can be Downloads.PUBLIC, Downloads.PRIVATE, or Downloads.ALL. |
|
157 * Downloads added to the Downloads.PUBLIC and Downloads.PRIVATE lists |
|
158 * are reflected in the Downloads.ALL list, and downloads added to the |
|
159 * Downloads.ALL list are also added to either the Downloads.PUBLIC or |
|
160 * the Downloads.PRIVATE list based on their properties. |
|
161 * |
|
162 * @return {Promise} |
|
163 * @resolves The requested DownloadList or DownloadCombinedList object. |
|
164 * @rejects JavaScript exception. |
|
165 */ |
|
166 getList: function (aType) |
|
167 { |
|
168 if (!this._promiseListsInitialized) { |
|
169 this._promiseListsInitialized = Task.spawn(function () { |
|
170 let publicList = new DownloadList(); |
|
171 let privateList = new DownloadList(); |
|
172 let combinedList = new DownloadCombinedList(publicList, privateList); |
|
173 |
|
174 try { |
|
175 yield DownloadIntegration.addListObservers(publicList, false); |
|
176 yield DownloadIntegration.addListObservers(privateList, true); |
|
177 yield DownloadIntegration.initializePublicDownloadList(publicList); |
|
178 } catch (ex) { |
|
179 Cu.reportError(ex); |
|
180 } |
|
181 |
|
182 let publicSummary = yield this.getSummary(Downloads.PUBLIC); |
|
183 let privateSummary = yield this.getSummary(Downloads.PRIVATE); |
|
184 let combinedSummary = yield this.getSummary(Downloads.ALL); |
|
185 |
|
186 yield publicSummary.bindToList(publicList); |
|
187 yield privateSummary.bindToList(privateList); |
|
188 yield combinedSummary.bindToList(combinedList); |
|
189 |
|
190 this._lists[Downloads.PUBLIC] = publicList; |
|
191 this._lists[Downloads.PRIVATE] = privateList; |
|
192 this._lists[Downloads.ALL] = combinedList; |
|
193 }.bind(this)); |
|
194 } |
|
195 |
|
196 return this._promiseListsInitialized.then(() => this._lists[aType]); |
|
197 }, |
|
198 |
|
199 /** |
|
200 * Promise resolved when the initialization of the download lists has |
|
201 * completed, or null if initialization has never been requested. |
|
202 */ |
|
203 _promiseListsInitialized: null, |
|
204 |
|
205 /** |
|
206 * After initialization, this object is populated with one key for each type |
|
207 * of download list that can be returned (Downloads.PUBLIC, Downloads.PRIVATE, |
|
208 * or Downloads.ALL). The values are the DownloadList objects. |
|
209 */ |
|
210 _lists: {}, |
|
211 |
|
212 /** |
|
213 * Retrieves the specified type of DownloadSummary object. There is one |
|
214 * download summary for each type, and this method always retrieves a |
|
215 * reference to the same download summary when called with the same argument. |
|
216 * |
|
217 * Calling this function does not cause the list of public downloads to be |
|
218 * reloaded from the previous session. The summary will behave as if no |
|
219 * downloads are present until the getList method is called. |
|
220 * |
|
221 * @param aType |
|
222 * This can be Downloads.PUBLIC, Downloads.PRIVATE, or Downloads.ALL. |
|
223 * |
|
224 * @return {Promise} |
|
225 * @resolves The requested DownloadList or DownloadCombinedList object. |
|
226 * @rejects JavaScript exception. |
|
227 */ |
|
228 getSummary: function (aType) |
|
229 { |
|
230 if (aType != Downloads.PUBLIC && aType != Downloads.PRIVATE && |
|
231 aType != Downloads.ALL) { |
|
232 throw new Error("Invalid aType argument."); |
|
233 } |
|
234 |
|
235 if (!(aType in this._summaries)) { |
|
236 this._summaries[aType] = new DownloadSummary(); |
|
237 } |
|
238 |
|
239 return Promise.resolve(this._summaries[aType]); |
|
240 }, |
|
241 |
|
242 /** |
|
243 * This object is populated by the getSummary method with one key for each |
|
244 * type of object that can be returned (Downloads.PUBLIC, Downloads.PRIVATE, |
|
245 * or Downloads.ALL). The values are the DownloadSummary objects. |
|
246 */ |
|
247 _summaries: {}, |
|
248 |
|
249 /** |
|
250 * Returns the system downloads directory asynchronously. |
|
251 * Mac OSX: |
|
252 * User downloads directory |
|
253 * XP/2K: |
|
254 * My Documents/Downloads |
|
255 * Vista and others: |
|
256 * User downloads directory |
|
257 * Linux: |
|
258 * XDG user dir spec, with a fallback to Home/Downloads |
|
259 * Android: |
|
260 * standard downloads directory i.e. /sdcard |
|
261 * |
|
262 * @return {Promise} |
|
263 * @resolves The downloads directory string path. |
|
264 */ |
|
265 getSystemDownloadsDirectory: function D_getSystemDownloadsDirectory() { |
|
266 return DownloadIntegration.getSystemDownloadsDirectory(); |
|
267 }, |
|
268 |
|
269 /** |
|
270 * Returns the preferred downloads directory based on the user preferences |
|
271 * in the current profile asynchronously. |
|
272 * |
|
273 * @return {Promise} |
|
274 * @resolves The downloads directory string path. |
|
275 */ |
|
276 getPreferredDownloadsDirectory: function D_getPreferredDownloadsDirectory() { |
|
277 return DownloadIntegration.getPreferredDownloadsDirectory(); |
|
278 }, |
|
279 |
|
280 /** |
|
281 * Returns the temporary directory where downloads are placed before the |
|
282 * final location is chosen, or while the document is opened temporarily |
|
283 * with an external application. This may or may not be the system temporary |
|
284 * directory, based on the platform asynchronously. |
|
285 * |
|
286 * @return {Promise} |
|
287 * @resolves The downloads directory string path. |
|
288 */ |
|
289 getTemporaryDownloadsDirectory: function D_getTemporaryDownloadsDirectory() { |
|
290 return DownloadIntegration.getTemporaryDownloadsDirectory(); |
|
291 }, |
|
292 |
|
293 /** |
|
294 * Constructor for a DownloadError object. When you catch an exception during |
|
295 * a download, you can use this to verify if "ex instanceof Downloads.Error", |
|
296 * before reading the exception properties with the error details. |
|
297 */ |
|
298 Error: DownloadError, |
|
299 }; |