ota.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. 'use strict';
  2. const Addon = require('ee-core/addon');
  3. const { Controller } = require('ee-core');
  4. const config = require('../config/config.default');
  5. const path = require('path');
  6. const fs = require('fs');
  7. const { ipcMain, app, BrowserWindow, shell, dialog } = require('electron');
  8. const { session } = require('electron');
  9. const CoreWindow = require("ee-core/electron/window");
  10. const Log = require('ee-core/log');
  11. const { spawn } = require('child_process');
  12. /**
  13. * example
  14. * @class
  15. */
  16. class OTAController extends Controller {
  17. constructor(ctx) {
  18. super(ctx);
  19. }
  20. async updateVersion(url) {
  21. const status = {
  22. error: -1,
  23. available: 1,
  24. noAvailable: 2,
  25. downloading: 3,
  26. downloaded: 4,
  27. };
  28. const win = new BrowserWindow({ show: false });
  29. // 设置下载路径为系统临时目录
  30. win.webContents.downloadURL(url);
  31. win.webContents.session.removeAllListeners('will-download');
  32. win.webContents.session.on('will-download', (event, item, webContents) => {
  33. // event.preventDefault();
  34. // 设置默认下载路径为系统下载目录
  35. const fileName = item.getFilename();
  36. const downloadPath = path.join(app.getPath('downloads'), fileName);
  37. console.log('下载路径:', downloadPath);
  38. // 确保目录存在
  39. const dir = path.dirname(downloadPath);
  40. if (!fs.existsSync(dir)) {
  41. fs.mkdirSync(dir, { recursive: true });
  42. }
  43. if (fs.existsSync(downloadPath)) {
  44. fs.unlinkSync(downloadPath); // 删除旧文件
  45. }
  46. console.log(item);
  47. item.setSavePath(downloadPath);
  48. item.on('updated', (event, state) => {
  49. Log.info('[addon:updated] 状态: ', state);
  50. if (state === 'interrupted') {
  51. Log.error('[addon:autoUpdater] 下载中断');
  52. } else if (state === 'progressing') {
  53. const receivedBytes = item.getReceivedBytes();
  54. const totalBytes = item.getTotalBytes();
  55. const percentNumber = Math.floor((receivedBytes / totalBytes) * 100);
  56. const transferredSize = this.bytesChange(receivedBytes);
  57. const totalSize = this.bytesChange(totalBytes);
  58. const text = `已下载 ${percentNumber}% (${transferredSize}/${totalSize})`;
  59. let info = {
  60. status: status.downloading,
  61. desc: text,
  62. percentNumber: percentNumber,
  63. totalSize: totalSize,
  64. transferredSize: transferredSize
  65. };
  66. Log.info('[addon:updated] 下载进度: ', text);
  67. this.sendStatusToWindow(info);
  68. }
  69. });
  70. item.once('done', (event, state) => {
  71. Log.info('[addon:done] 状态: ', state);
  72. if (state === 'completed') {
  73. Log.info('[addon:autoUpdater] 文件已下载完成: ', item.getSavePath());
  74. let info = {
  75. status: status.downloaded,
  76. desc: '下载完成',
  77. filePath: item.getSavePath()
  78. };
  79. this.sendStatusToWindow(info);
  80. // 提醒用户选择操作
  81. dialog.showMessageBox({
  82. type: 'info',
  83. title: '下载完成',
  84. message: '文件已下载完成,请选择操作:',
  85. buttons: ['关闭智惠映并自动安装', '打开目录手动安装', '取消']
  86. }).then(result => {
  87. if (result.response === 0) {
  88. // 用户选择“立即安装”,执行安装操作
  89. this.install(item.getSavePath());
  90. } else if (result.response === 1) {
  91. // 用户选择“打开目录”,打开文件所在目录
  92. shell.openPath(path.dirname(item.getSavePath()));
  93. }
  94. });
  95. } else {
  96. Log.error('[addon:autoUpdater] 下载失败: ', state);
  97. let info = {
  98. status: status.error,
  99. desc: `下载失败: ${state}`
  100. };
  101. this.sendStatusToWindow(info);
  102. }
  103. win.close(); // 关闭隐藏窗口
  104. });
  105. });
  106. }
  107. install(filePath) {
  108. // 启动安装程序并脱离主进程
  109. const child = spawn(filePath, [], {
  110. detached: true,
  111. stdio: 'ignore'
  112. });
  113. child.on('error', (err) => {
  114. console.error('启动安装程序失败:', err);
  115. });
  116. // 让安装程序独立运行后,退出当前应用
  117. child.unref();
  118. app.quit();
  119. }
  120. /**
  121. * 向前端发消息
  122. */
  123. sendStatusToWindow(content = {}) {
  124. const textJson = JSON.stringify(content);
  125. const channel = 'app.updater';
  126. this.app.electron['ota'].webContents.send(channel, textJson);
  127. /* const win = CoreWindow.getMainWindow();
  128. win.webContents.send(channel, textJson);*/
  129. }
  130. /**
  131. * 单位转换
  132. */
  133. bytesChange (limit) {
  134. let size = "";
  135. if(limit < 0.1 * 1024){
  136. size = limit.toFixed(2) + "B";
  137. }else if(limit < 0.1 * 1024 * 1024){
  138. size = (limit/1024).toFixed(2) + "KB";
  139. }else if(limit < 0.1 * 1024 * 1024 * 1024){
  140. size = (limit/(1024 * 1024)).toFixed(2) + "MB";
  141. }else{
  142. size = (limit/(1024 * 1024 * 1024)).toFixed(2) + "GB";
  143. }
  144. let sizeStr = size + "";
  145. let index = sizeStr.indexOf(".");
  146. let dou = sizeStr.substring(index + 1 , index + 3);
  147. if(dou == "00"){
  148. return sizeStr.substring(0, index) + sizeStr.substring(index + 3, index + 5);
  149. }
  150. return size;
  151. }
  152. }
  153. OTAController.toString = () => '[class OTAController]';
  154. module.exports = OTAController;