DownloadsManager.jsm 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
  2. XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
  3. const {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm");
  4. XPCOMUtils.defineLazyModuleGetters(this, {
  5. BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
  6. DownloadsCommon: "resource:///modules/DownloadsCommon.jsm",
  7. DownloadsViewUI: "resource:///modules/DownloadsViewUI.jsm",
  8. FileUtils: "resource://gre/modules/FileUtils.jsm",
  9. });
  10. const DOWNLOAD_CHANGED_DELAY_TIME = 1000; // time in ms to delay timer for downloads changed events
  11. this.DownloadsManager = class DownloadsManager {
  12. constructor(store) {
  13. this._downloadData = null;
  14. this._store = null;
  15. this._downloadItems = new Map();
  16. this._downloadTimer = null;
  17. }
  18. setTimeout(callback, delay) {
  19. let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  20. timer.initWithCallback(callback, delay, Ci.nsITimer.TYPE_ONE_SHOT);
  21. return timer;
  22. }
  23. formatDownload(download) {
  24. return {
  25. hostname: new URL(download.source.url).hostname,
  26. url: download.source.url,
  27. path: download.target.path,
  28. title: DownloadsViewUI.getDisplayName(download),
  29. description: DownloadsViewUI.getSizeWithUnits(download) ||
  30. DownloadsCommon.strings.sizeUnknown,
  31. referrer: download.source.referrer,
  32. date_added: download.endTime,
  33. };
  34. }
  35. init(store) {
  36. this._store = store;
  37. this._downloadData = DownloadsCommon.getData(null /* null for non-private downloads */,
  38. true, false, true);
  39. this._downloadData.addView(this);
  40. }
  41. onDownloadAdded(download) {
  42. if (!this._downloadItems.has(download.source.url)) {
  43. this._downloadItems.set(download.source.url, download);
  44. // On startup, all existing downloads fire this notification, so debounce them
  45. if (this._downloadTimer) {
  46. this._downloadTimer.delay = DOWNLOAD_CHANGED_DELAY_TIME;
  47. } else {
  48. this._downloadTimer = this.setTimeout(() => {
  49. this._downloadTimer = null;
  50. this._store.dispatch({type: at.DOWNLOAD_CHANGED});
  51. }, DOWNLOAD_CHANGED_DELAY_TIME);
  52. }
  53. }
  54. }
  55. onDownloadRemoved(download) {
  56. if (this._downloadItems.has(download.source.url)) {
  57. this._downloadItems.delete(download.source.url);
  58. this._store.dispatch({type: at.DOWNLOAD_CHANGED});
  59. }
  60. }
  61. async getDownloads(threshold, {numItems = this._downloadItems.size, onlySucceeded = false, onlyExists = false}) {
  62. if (!threshold) {
  63. return [];
  64. }
  65. let results = [];
  66. // Only get downloads within the time threshold specified and sort by recency
  67. const downloadThreshold = Date.now() - threshold;
  68. let downloads = [...this._downloadItems.values()]
  69. .filter(download => download.endTime > downloadThreshold)
  70. .sort((download1, download2) => download1.endTime < download2.endTime);
  71. for (const download of downloads) {
  72. // Only include downloads where the file still exists
  73. if (onlyExists) {
  74. // Refresh download to ensure the 'exists' attribute is up to date
  75. await download.refresh();
  76. if (!download.target.exists) { continue; }
  77. }
  78. // Only include downloads that were completed successfully
  79. if (onlySucceeded) {
  80. if (!download.succeeded) { continue; }
  81. }
  82. const formattedDownloadForHighlights = this.formatDownload(download);
  83. results.push(formattedDownloadForHighlights);
  84. if (results.length === numItems) {
  85. break;
  86. }
  87. }
  88. return results;
  89. }
  90. uninit() {
  91. if (this._downloadData) {
  92. this._downloadData.removeView(this);
  93. this._downloadData = null;
  94. }
  95. if (this._downloadTimer) {
  96. this._downloadTimer.cancel();
  97. this._downloadTimer = null;
  98. }
  99. }
  100. onAction(action) {
  101. let doDownloadAction = callback => {
  102. let download = this._downloadItems.get(action.data.url);
  103. if (download) {
  104. callback(download);
  105. }
  106. };
  107. switch (action.type) {
  108. case at.COPY_DOWNLOAD_LINK:
  109. doDownloadAction(download => {
  110. DownloadsCommon.copyDownloadLink(download);
  111. });
  112. break;
  113. case at.REMOVE_DOWNLOAD_FILE:
  114. doDownloadAction(download => {
  115. DownloadsCommon.deleteDownload(download).catch(Cu.reportError);
  116. });
  117. break;
  118. case at.SHOW_DOWNLOAD_FILE:
  119. doDownloadAction(download => {
  120. DownloadsCommon.showDownloadedFile(
  121. new FileUtils.File(download.target.path));
  122. });
  123. break;
  124. case at.OPEN_DOWNLOAD_FILE:
  125. doDownloadAction(download => {
  126. DownloadsCommon.openDownloadedFile(
  127. new FileUtils.File(download.target.path), null,
  128. BrowserWindowTracker.getTopWindow());
  129. });
  130. break;
  131. case at.UNINIT:
  132. this.uninit();
  133. break;
  134. }
  135. }
  136. };
  137. this.EXPORTED_SYMBOLS = ["DownloadsManager"];