gecko/dom/downloads/DownloadsAPI.jsm

269 lines
7.3 KiB
JavaScript
Raw Normal View History

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
this.EXPORTED_SYMBOLS = [];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Downloads.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
function debug(aStr) {
#ifdef MOZ_DEBUG
dump("-*- DownloadsAPI.jsm : " + aStr + "\n");
#endif
}
function sendPromiseMessage(aMm, aMessageName, aData, aError) {
debug("sendPromiseMessage " + aMessageName);
let msg = {
id: aData.id,
promiseId: aData.promiseId
};
if (aError) {
msg.error = aError;
}
aMm.sendAsyncMessage(aMessageName, msg);
}
let DownloadsAPI = {
init: function() {
debug("init");
this._ids = new WeakMap(); // Maps toolkit download objects to ids.
this._index = {}; // Maps ids to downloads.
["Downloads:GetList",
"Downloads:ClearAllDone",
"Downloads:Remove",
"Downloads:Pause",
"Downloads:Resume"].forEach((msgName) => {
ppmm.addMessageListener(msgName, this);
});
let self = this;
Task.spawn(function () {
let list = yield Downloads.getList(Downloads.ALL);
yield list.addView(self);
debug("view added to download list.");
}).then(null, Components.utils.reportError);
this._currentId = 0;
},
/**
* Returns a unique id for each download, hashing the url and the path.
*/
downloadId: function(aDownload) {
let id = this._ids.get(aDownload, null);
if (!id) {
id = "download-" + this._currentId++;
this._ids.set(aDownload, id);
this._index[id] = aDownload;
}
return id;
},
getDownloadById: function(aId) {
return this._index[aId];
},
/**
* Converts a download object into a plain json object that we'll
* send to the DOM side.
*/
jsonDownload: function(aDownload) {
let res = {
totalBytes: aDownload.totalBytes,
currentBytes: aDownload.currentBytes,
url: aDownload.source.url,
path: aDownload.target.path,
contentType: aDownload.contentType,
startTime: aDownload.startTime.getTime()
};
if (aDownload.error) {
res.error = aDownload.error;
}
res.id = this.downloadId(aDownload);
// The state of the download. Can be any of "downloading", "stopped",
// "succeeded", finalized".
// Default to "stopped"
res.state = "stopped";
if (!aDownload.stopped &&
!aDownload.canceled &&
!aDownload.succeeded &&
!aDownload.DownloadError) {
res.state = "downloading";
} else if (aDownload.succeeded) {
res.state = "succeeded";
}
return res;
},
/**
* download view methods.
*/
onDownloadAdded: function(aDownload) {
let download = this.jsonDownload(aDownload);
debug("onDownloadAdded " + uneval(download));
ppmm.broadcastAsyncMessage("Downloads:Added", download);
},
onDownloadRemoved: function(aDownload) {
let download = this.jsonDownload(aDownload);
download.state = "finalized";
debug("onDownloadRemoved " + uneval(download));
ppmm.broadcastAsyncMessage("Downloads:Removed", download);
this._index[this._ids.get(aDownload)] = null;
this._ids.delete(aDownload);
},
onDownloadChanged: function(aDownload) {
let download = this.jsonDownload(aDownload);
debug("onDownloadChanged " + uneval(download));
ppmm.broadcastAsyncMessage("Downloads:Changed", download);
},
receiveMessage: function(aMessage) {
if (!aMessage.target.assertPermission("downloads")) {
debug("No 'downloads' permission!");
return;
}
debug("message: " + aMessage.name);
switch (aMessage.name) {
case "Downloads:GetList":
this.getList(aMessage.data, aMessage.target);
break;
case "Downloads:ClearAllDone":
this.clearAllDone(aMessage.data, aMessage.target);
break;
case "Downloads:Remove":
this.remove(aMessage.data, aMessage.target);
break;
case "Downloads:Pause":
this.pause(aMessage.data, aMessage.target);
break;
case "Downloads:Resume":
this.resume(aMessage.data, aMessage.target);
break;
default:
debug("Invalid message: " + aMessage.name);
}
},
getList: function(aData, aMm) {
debug("getList called!");
let self = this;
Task.spawn(function () {
let list = yield Downloads.getList(Downloads.ALL);
let downloads = yield list.getAll();
let res = [];
downloads.forEach((aDownload) => {
res.push(self.jsonDownload(aDownload));
});
aMm.sendAsyncMessage("Downloads:GetList:Return", res);
}).then(null, Components.utils.reportError);
},
clearAllDone: function(aData, aMm) {
debug("clearAllDone called!");
let self = this;
Task.spawn(function () {
let list = yield Downloads.getList(Downloads.ALL);
yield list.removeFinished();
list = yield Downloads.getList(Downloads.ALL);
let downloads = yield list.getAll();
let res = [];
downloads.forEach((aDownload) => {
res.push(self.jsonDownload(aDownload));
});
aMm.sendAsyncMessage("Downloads:ClearAllDone:Return", res);
}).then(null, Components.utils.reportError);
},
remove: function(aData, aMm) {
debug("remove id " + aData.id);
let download = this.getDownloadById(aData.id);
if (!download) {
sendPromiseMessage(aMm, "Downloads:Remove:Return",
aData, "NoSuchDownload");
return;
}
Task.spawn(function() {
yield download.finalize(true);
let list = yield Downloads.getList(Downloads.ALL);
yield list.remove(download);
}).then(
function() {
sendPromiseMessage(aMm, "Downloads:Remove:Return", aData);
},
function() {
sendPromiseMessage(aMm, "Downloads:Remove:Return",
aData, "RemoveError");
}
);
},
pause: function(aData, aMm) {
debug("pause id " + aData.id);
let download = this.getDownloadById(aData.id);
if (!download) {
sendPromiseMessage(aMm, "Downloads:Pause:Return",
aData, "NoSuchDownload");
return;
}
download.cancel().then(
function() {
sendPromiseMessage(aMm, "Downloads:Pause:Return", aData);
},
function() {
sendPromiseMessage(aMm, "Downloads:Pause:Return",
aData, "PauseError");
}
);
},
resume: function(aData, aMm) {
debug("resume id " + aData.id);
let download = this.getDownloadById(aData.id);
if (!download) {
sendPromiseMessage(aMm, "Downloads:Resume:Return",
aData, "NoSuchDownload");
return;
}
download.start().then(
function() {
sendPromiseMessage(aMm, "Downloads:Resume:Return", aData);
},
function() {
sendPromiseMessage(aMm, "Downloads:Resume:Return",
aData, "ResumeError");
}
);
}
};
DownloadsAPI.init();