downloadCtl.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. 'use strict';
  2. import { BrowserWindow } from 'electron';
  3. import { downloadService } from '../service/download/downloadService';
  4. import { logger } from 'ee-core/log';
  5. /** 进度推送通道:界面订阅它刷新"下载中"的进度与状态 */
  6. export const DOWNLOAD_PROGRESS_CHANNEL = 'downloadCtl:progress';
  7. /**
  8. * 把 in-flight 状态推给所有渲染进程。
  9. *
  10. * <p>智能工作台顶栏也挂了下载管理器,且 AI 工具产物多半在那边产生;
  11. * 只发主窗口会让智能窗口永远看不到进度。
  12. */
  13. function broadcast(item) {
  14. for (const win of BrowserWindow.getAllWindows()) {
  15. if (win.isDestroyed() || win.webContents.isDestroyed()) continue;
  16. try {
  17. win.webContents.send(DOWNLOAD_PROGRESS_CHANNEL, item);
  18. } catch (e) {
  19. logger.warn('[downloadCtl] 广播下载进度失败:', e instanceof Error ? e.message : String(e));
  20. }
  21. }
  22. }
  23. /**
  24. * 下载管理器 IPC:通道名 controller/downloadCtl/<方法>(ee-core 按文件名自动注册)。
  25. *
  26. * 统一返回项目约定 {success, data|message}:失败(路径非法/记录不存在/文件被移走)不抛到 Electron 层,
  27. * 前端看 message 即可提示。
  28. */
  29. class DownloadCtl {
  30. /** 保存一次下载:params { fileName, mime?, data(ArrayBuffer|base64), source? } */
  31. async saveDownload(params) {
  32. try {
  33. return { success: true, data: downloadService.save(params) };
  34. } catch (e) {
  35. return { success: false, message: this.message(e, '下载失败') };
  36. }
  37. }
  38. /**
  39. * 后台下载:主进程流式拉取 URL 落盘并推送进度。
  40. * params { url, fileName?, headers?, source?, mime? }
  41. */
  42. async startDownload(params) {
  43. try {
  44. downloadService.setNotifier(broadcast);
  45. return { success: true, data: downloadService.start(params) };
  46. } catch (e) {
  47. return { success: false, message: this.message(e, '下载失败') };
  48. }
  49. }
  50. /** 下载清单 + 当前生效目录 */
  51. async listDownloads() {
  52. try {
  53. return { success: true, data: { dir: downloadService.getDownloadDir(), items: downloadService.list() } };
  54. } catch (e) {
  55. return { success: false, message: this.message(e, '读取下载列表失败') };
  56. }
  57. }
  58. async getDownloadDir() {
  59. try {
  60. return { success: true, data: { dir: downloadService.getDownloadDir() } };
  61. } catch (e) {
  62. return { success: false, message: this.message(e, '读取下载目录失败') };
  63. }
  64. }
  65. /** 设置下载目录;params { dir } 传空恢复系统默认 */
  66. async setDownloadDir(params) {
  67. try {
  68. return { success: true, data: { dir: downloadService.setDownloadDir(params?.dir) } };
  69. } catch (e) {
  70. return { success: false, message: this.message(e, '设置下载目录失败') };
  71. }
  72. }
  73. /** 用系统默认程序打开已下载的文件 */
  74. async openDownloadFile(params) {
  75. try {
  76. return { success: true, data: await downloadService.openFile(params?.id) };
  77. } catch (e) {
  78. return { success: false, message: this.message(e, '打开文件失败') };
  79. }
  80. }
  81. /** 在文件管理器里定位已下载的文件 */
  82. async revealDownload(params) {
  83. try {
  84. return { success: true, data: downloadService.revealFile(params?.id) };
  85. } catch (e) {
  86. return { success: false, message: this.message(e, '定位文件失败') };
  87. }
  88. }
  89. /** 打开下载目录 */
  90. async openDownloadDir() {
  91. try {
  92. return { success: true, data: await downloadService.openDir() };
  93. } catch (e) {
  94. return { success: false, message: this.message(e, '打开下载目录失败') };
  95. }
  96. }
  97. /** 只从清单移除记录,不删磁盘上的文件 */
  98. async removeDownload(params) {
  99. try {
  100. return { success: true, data: downloadService.remove(params?.id) };
  101. } catch (e) {
  102. return { success: false, message: this.message(e, '移除记录失败') };
  103. }
  104. }
  105. async clearDownloads() {
  106. try {
  107. return { success: true, data: downloadService.clear() };
  108. } catch (e) {
  109. return { success: false, message: this.message(e, '清空记录失败') };
  110. }
  111. }
  112. message(error, fallback) {
  113. const msg = error instanceof Error ? error.message : String(error);
  114. logger.warn('[downloadCtl]', fallback, msg);
  115. return msg || fallback;
  116. }
  117. }
  118. export default DownloadCtl;