main.js 7.5 KB

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