updateManager.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. const axios = require('axios');
  2. const fs = require('fs');
  3. const path = require('path');
  4. const AdmZip = require('adm-zip');
  5. const { dialog } = require('electron');
  6. const constants = require('./constants');
  7. const utils = require('./utils');
  8. const serverManager = require('./serverManager');
  9. //const menuManager = require('./menuManager'); // 引入 menuManager
  10. // 获取本地版本号
  11. const getLocalVersion = () => {
  12. const appSettingsPath = path.join(constants.serverPath, 'server', 'appsettings.json');
  13. try {
  14. if (fs.existsSync(appSettingsPath)) {
  15. const appSettings = JSON.parse(fs.readFileSync(appSettingsPath, 'utf-8'));
  16. return appSettings.Version || '1.250101.01'; // 默认版本号
  17. }
  18. } catch (error) {
  19. console.error('Error reading appsettings.json:', error);
  20. return '1.250101.01';
  21. }
  22. };
  23. // 从云端获取历史版本信息
  24. const getRemoteVersions = async () => {
  25. try {
  26. const response = await axios.get(constants.remoteVersionsUrl, {
  27. validateStatus: (status) => status === 200 || status === 404, // 允许 404 状态码
  28. timeout: 5000 // 设置超时时间为 5 秒
  29. });
  30. if (response.status === 404) {
  31. console.error('Remote versions file not found.');
  32. return null;
  33. }
  34. return response.data.versions; // 返回版本号数组
  35. } catch (error) {
  36. if (error.code === 'ECONNABORTED') {
  37. console.error('Request to fetch remote versions timed out.');
  38. } else {
  39. console.error('Error fetching remote versions:', error);
  40. }
  41. return null;
  42. }
  43. };
  44. // 下载文件
  45. const downloadFile = async (url, outputPath) => {
  46. try {
  47. const writer = fs.createWriteStream(outputPath);
  48. console.log(`Downloading file from ${url}...`);
  49. const response = await axios({
  50. url,
  51. method: 'GET',
  52. responseType: 'stream',
  53. timeout: 10000 // 设置超时时间为 10 秒
  54. });
  55. response.data.pipe(writer);
  56. await new Promise((resolve, reject) => {
  57. writer.on('finish', resolve);
  58. writer.on('error', reject);
  59. });
  60. console.log('Download completed.');
  61. return true;
  62. } catch (error) {
  63. if (error.code === 'ECONNABORTED') {
  64. console.error('Download timed out.');
  65. } else {
  66. console.error('Error downloading file:', error);
  67. }
  68. return false;
  69. }
  70. };
  71. // 检查是否需要更新
  72. const checkForUpdates = async (win, createMenuCallback) => {
  73. const localVersion = utils.formatVersion(getLocalVersion());
  74. console.log('Local version:', localVersion);
  75. const remoteVersions = await getRemoteVersions();
  76. if (!remoteVersions || remoteVersions.length === 0) {
  77. console.log('No remote versions found.');
  78. //menuManager.createMenu(win); // 未检测到新版本时更新菜单
  79. if (typeof createMenuCallback === 'function') {
  80. createMenuCallback(win); // 确保回调函数是函数
  81. } else {
  82. console.error('createMenuCallback is not a function');
  83. }
  84. return;
  85. }
  86. // 获取最新版本号
  87. const latestRemoteVersion = utils.formatVersion(remoteVersions[remoteVersions.length - 1]);
  88. console.log('Latest remote version:', latestRemoteVersion);
  89. if (utils.compareVersions(localVersion, latestRemoteVersion)) {
  90. const { response } = await dialog.showMessageBox({
  91. type: 'info',
  92. title: '版本更新',
  93. message: `是否更新到(${latestRemoteVersion}) 版本?`,
  94. buttons: ['是', '否']
  95. });
  96. if (response === 0) { // 用户选择 Yes
  97. await updateServer(latestRemoteVersion, win, createMenuCallback);
  98. }
  99. } else {
  100. console.log('未检测到新版本。');
  101. const { response } = await dialog.showMessageBox({
  102. type: 'info',
  103. title: '版本更新',
  104. message: `未检测到新版本。`,
  105. buttons: ['关闭']
  106. });
  107. //menuManager.createMenu(win); // 未检测到新版本时更新菜单
  108. if (typeof createMenuCallback === 'function') {
  109. createMenuCallback(win); // 确保回调函数是函数
  110. } else {
  111. console.error('createMenuCallback is not a function');
  112. }
  113. }
  114. };
  115. // 下载并更新 IES.ExamServer.exe
  116. const updateServer = async (latestVersion, win, createMenuCallback) => {
  117. try {
  118. const zipUrl = `${constants.remoteZipBaseUrl}/server-${latestVersion}.zip`; // 构造下载 URL
  119. const zipPath = path.join(constants.serverPath, 'IES.ExamServer.zip');
  120. // 1. 下载最新的 IES.ExamServer.zip
  121. const downloadSuccess = await downloadFile(zipUrl, zipPath);
  122. if (!downloadSuccess) {
  123. throw new Error('Failed to download IES.ExamServer.zip.');
  124. }
  125. try {
  126. // 2. 关闭 IES.ExamServer.exe
  127. console.log('Shutting down IES.ExamServer...');
  128. const response = await axios.get(`${constants.baseUrl}/index/shutdown?delay=0`, {
  129. httpsAgent: constants.agent,
  130. validateStatus: (status) => status === 200 || status === 404, // 允许 404 状态码
  131. timeout: 5000 // 设置超时时间为 5 秒
  132. });
  133. if (response.status === 404) {
  134. console.error('API: index/shutdown not found.');
  135. }
  136. if (response.status === 200) {
  137. console.log('IES.ExamServer shutdown completed.');
  138. }
  139. } catch (error) {
  140. console.error('Error Shutting down IES.ExamServer...', error);
  141. }
  142. await utils.delay(2000);
  143. // 3. 解压 IES.ExamServer.zip
  144. console.log('Extracting IES.ExamServer.zip...');
  145. const zip = new AdmZip(zipPath);
  146. zip.extractAllTo(path.join(constants.serverPath, 'server'), true); // 覆盖解压
  147. console.log('Extraction completed.');
  148. // 4. 启动新的 IES.ExamServer.exe
  149. console.log('Starting IES.ExamServer...');
  150. await serverManager.startServer();
  151. console.log('IES.ExamServer started successfully.');
  152. // 5. 重新加载页面
  153. if (win) {
  154. win.loadURL(constants.baseUrl, {
  155. agent: constants.agent
  156. });
  157. }
  158. // 6. 更新菜单栏
  159. //menuManager.createMenu(win); // 更新成功后更新菜单
  160. if (typeof createMenuCallback === 'function') {
  161. createMenuCallback(win); // 确保回调函数是函数
  162. } else {
  163. console.error('createMenuCallback is not a function');
  164. }
  165. const { response } = await dialog.showMessageBox({
  166. type: 'info',
  167. title: '版本更新',
  168. message: `更新成功。`,
  169. buttons: ['关闭']
  170. });
  171. } catch (error) {
  172. console.error('Error updating server:', error);
  173. }
  174. };
  175. module.exports = {
  176. checkForUpdates
  177. };