main.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. const { app, BrowserWindow, Menu, session,ipcMain } = require('electron');
  2. const path = require('path');
  3. const fs = require('fs');
  4. const crypto = require('crypto');
  5. const isDev = process.env.NODE_ENV === 'development';
  6. const algorithm = 'aes-256-ctr';
  7. const password = 'skyfffire-password';
  8. const key = crypto.createHash('sha256').update(password).digest();
  9. let memoryCache = {};
  10. const loginFilePath = path.join(app.getPath('userData'), 'loginSession.json');
  11. const symbolFilePath = path.join(app.getPath('userData'), 'symbolSession.json');
  12. const dbBasePath = path.join(app.getPath('userData'))
  13. function readData(filePath) {
  14. try {
  15. if (fs.existsSync(filePath)) {
  16. const rawData = fs.readFileSync(filePath);
  17. return JSON.parse(rawData);
  18. }
  19. } catch (error) {
  20. console.error('Error reading data:', error);
  21. }
  22. return {};
  23. }
  24. function writeData(filePath, data) {
  25. try {
  26. fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
  27. } catch (error) {
  28. console.error(`Error writing data to ${filePath}:`, error);
  29. }
  30. }
  31. // Function to decrypt a file and store its content in memory
  32. function decryptFile(filePath) {
  33. const fileContent = fs.readFileSync(filePath);
  34. const iv = fileContent.slice(0, 16); // Extract IV
  35. const encrypted = fileContent.slice(16); // Extract encrypted data
  36. const decipher = crypto.createDecipheriv(algorithm, key, iv);
  37. const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
  38. let relativePath = path.relative(process.resourcesPath, filePath).replace(/\\/g, '/');
  39. if (isDev) relativePath = relativePath.replace('../../../..', '')
  40. memoryCache[relativePath] = decrypted;
  41. }
  42. // Recursively decrypt files in a directory and store their content in memory
  43. function decryptDirectory(directoryPath) {
  44. const files = fs.readdirSync(directoryPath);
  45. files.forEach(file => {
  46. const fullPath = path.join(directoryPath, file);
  47. if (fs.lstatSync(fullPath).isDirectory()) {
  48. decryptDirectory(fullPath);
  49. } else {
  50. decryptFile(fullPath);
  51. }
  52. });
  53. }
  54. function createWindow() {
  55. const directoryToDecrypt = isDev ? path.join(__dirname, 'build', 'static') : path.join(process.resourcesPath, 'app.asar', 'static');
  56. decryptDirectory(directoryToDecrypt);
  57. const win = new BrowserWindow({
  58. width: 1600,
  59. height: 900,
  60. icon: path.join(__dirname, 'favicon.ico'), // 设置窗口图标
  61. webPreferences: {
  62. preload: path.join(__dirname, 'src', 'preload.js'), // 确认预加载脚本路径正确
  63. nodeIntegration: false,
  64. contextIsolation: true,
  65. },
  66. });
  67. // Load the index.html from disk
  68. const index = isDev ? path.join(__dirname, 'build', 'index.html') : 'index.html';
  69. win.loadFile(index); // 确保路径正确
  70. // 打开调试工具
  71. if (isDev) win.webContents.openDevTools();
  72. // 创建菜单模板,只包含一个刷新按钮
  73. const menuTemplate = [
  74. {
  75. label: 'View',
  76. submenu: [
  77. {
  78. label: 'Reload',
  79. accelerator: 'CmdOrCtrl+R',
  80. click: () => {
  81. win.reload();
  82. },
  83. },
  84. ],
  85. },
  86. ];
  87. // 创建菜单
  88. const menu = Menu.buildFromTemplate(menuTemplate);
  89. // 设置应用程序的菜单
  90. Menu.setApplicationMenu(menu);
  91. console.log(Object.keys(memoryCache))
  92. }
  93. let memoryDbData = []
  94. let memoryDbPath = undefined
  95. app.whenReady().then(() => {
  96. ipcMain.handle('get-login-info-data', () => {
  97. return readData(loginFilePath);
  98. });
  99. ipcMain.handle('set-login-info-data', (event, newData) => {
  100. writeData(loginFilePath, newData);
  101. });
  102. ipcMain.handle('get-symbol-data', () => {
  103. return readData(symbolFilePath);
  104. });
  105. ipcMain.handle('set-symbol-data', (event, newData) => {
  106. writeData(symbolFilePath, newData);
  107. });
  108. ipcMain.handle('set-db-data', (event, dataList, symbol) => {
  109. const finalPath = path.join(dbBasePath, `${symbol}.json`)
  110. writeData(finalPath, dataList)
  111. console.log(`Local db is set. ${finalPath}`)
  112. })
  113. ipcMain.handle('get-db-data', (event, symbol) => {
  114. const finalPath = path.join(dbBasePath, `${symbol}.json`)
  115. const rst = readData(finalPath)
  116. if (JSON.stringify(rst) === '{}') {
  117. console.log(`No local db is found:${finalPath}`)
  118. return []
  119. } else {
  120. console.log(`Local db is found:${finalPath}, length: ${rst.length}`)
  121. return rst
  122. }
  123. })
  124. ipcMain.handle('flush-memory-db-data', (event, data, symbol) => {
  125. memoryDbData = data
  126. if (!memoryDbPath) memoryDbPath = path.join(dbBasePath, `${symbol}.json`)
  127. // console.log(`Memory db is flush。length: ${memoryDbData.length}, symbol: ${symbol}`)
  128. })
  129. });
  130. app.on('ready', () => {
  131. // Intercept file requests and serve from memory
  132. session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
  133. const url = new URL(details.url);
  134. const filePath = path.normalize(decodeURIComponent(url.pathname));
  135. let relativePath = filePath.replace(path.normalize(process.resourcesPath), '').replace(/\\/g, '/').replace('//', '');
  136. if (isDev && relativePath.indexOf('react-stock-heatmap/example') !== -1) {
  137. relativePath = relativePath.split('react-stock-heatmap/example')[1]
  138. }
  139. // console.log(relativePath)
  140. if (memoryCache[relativePath]) {
  141. let sanitizedRelativePath = relativePath.replace('app.asar', 'app_asar'); // 避免路径中包含 app.asar
  142. // console.log(app.getPath('temp'), sanitizedRelativePath)
  143. const tempFilePath = path.join(app.getPath('temp'), sanitizedRelativePath);
  144. // console.log(`Temp File Path: ${tempFilePath}`);
  145. const tempDir = path.dirname(tempFilePath);
  146. // console.log(`Temp Directory Path: ${tempDir}`);
  147. // 确保临时目录路径存在
  148. if (!fs.existsSync(tempDir)) {
  149. // console.log(`Creating directory: ${tempDir}`);
  150. fs.mkdirSync(tempDir, { recursive: true });
  151. // console.log(`Directory created: ${tempDir}`);
  152. } else {
  153. // console.log(`Directory already exists: ${tempDir}`);
  154. }
  155. // 确保目录存在后再写入文件
  156. if (fs.existsSync(tempDir)) {
  157. // console.log(`Writing file: ${tempFilePath}`);
  158. fs.writeFileSync(tempFilePath, memoryCache[relativePath]);
  159. // console.log(`File written: ${tempFilePath}`);
  160. // console.log(`Intercepting request for: ${relativePath}, redirectURL: ${tempFilePath}`);
  161. callback({ cancel: false, redirectURL: tempFilePath });
  162. } else {
  163. // console.error(`Directory does not exist after creation attempt: ${tempDir}`);
  164. callback({ cancel: false });
  165. }
  166. } else {
  167. callback({ cancel: false });
  168. }
  169. });
  170. createWindow();
  171. });
  172. app.on('window-all-closed', () => {
  173. if (memoryDbData.length > 0 && memoryDbPath) {
  174. writeData(memoryDbPath, memoryDbData);
  175. console.log(`Exit saved db is ok. length: ${memoryDbData.length}, path:${memoryDbPath}`)
  176. }
  177. if (process.platform !== 'darwin') {
  178. app.quit();
  179. }
  180. });
  181. app.on('activate', () => {
  182. if (BrowserWindow.getAllWindows().length === 0) {
  183. createWindow();
  184. }
  185. });