const { app, BrowserWindow, Menu, session, ipcMain, screen } = require('electron'); const path = require('path'); const fs = require('fs'); const crypto = require('crypto'); const isDev = process.env.NODE_ENV === 'development'; const algorithm = 'aes-256-ctr'; const password = 'skyfffire-password'; const key = crypto.createHash('sha256').update(password).digest(); let memoryCache = {}; const loginFilePath = path.join(app.getPath('userData'), 'loginSession2.json'); const symbolFilePath = path.join(app.getPath('userData'), 'symbolSession.json'); const persistentFilePath = path.join(app.getPath('userData'), 'persistentSession.json'); const mergeFilePath = path.join(app.getPath('userData'), 'mergeSession.json'); const dbBasePath = path.join(app.getPath('userData')) function readData(filePath) { try { if (fs.existsSync(filePath)) { const rawData = fs.readFileSync(filePath); return JSON.parse(rawData); } } catch (error) { console.error('Error reading data:', error); } return {}; } function writeData(filePath, data) { try { fs.writeFileSync(filePath, JSON.stringify(data, null, 2)); } catch (error) { console.error(`Error writing data to ${filePath}:`, error); } } // Function to decrypt a file and store its content in memory function decryptFile(filePath) { const fileContent = fs.readFileSync(filePath); const iv = fileContent.slice(0, 16); // Extract IV const encrypted = fileContent.slice(16); // Extract encrypted data const decipher = crypto.createDecipheriv(algorithm, key, iv); const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]); let relativePath = path.relative(process.resourcesPath, filePath).replace(/\\/g, '/'); if (isDev) relativePath = relativePath.replace('../../../..', '') memoryCache[relativePath] = decrypted; } // Recursively decrypt files in a directory and store their content in memory function decryptDirectory(directoryPath) { const files = fs.readdirSync(directoryPath); files.forEach(file => { const fullPath = path.join(directoryPath, file); if (fs.lstatSync(fullPath).isDirectory()) { decryptDirectory(fullPath); } else { decryptFile(fullPath); } }); } function createWindow() { const directoryToDecrypt = isDev ? path.join(__dirname, 'build', 'static') : path.join(process.resourcesPath, 'app.asar', 'static'); decryptDirectory(directoryToDecrypt); const { width, height } = screen.getPrimaryDisplay().workAreaSize; console.log(`Screen resolution: ${width}x${height}`); const WIDTH = parseInt(1600 * width / 1920) const HEIGHT = parseInt(900 * width / 1920) const win = new BrowserWindow({ width: WIDTH, height: HEIGHT, icon: path.join(__dirname, 'favicon.ico'), // 设置窗口图标 webPreferences: { preload: path.join(__dirname, 'src', 'preload.js'), // 确认预加载脚本路径正确 nodeIntegration: false, contextIsolation: true, }, }); // Load the index.html from disk const index = isDev ? path.join(__dirname, 'build', 'index.html') : 'index.html'; win.loadFile(index); // 确保路径正确 // 打开调试工具 if (isDev) win.webContents.openDevTools(); // 创建菜单模板,只包含一个刷新按钮 const menuTemplate = [ { label: 'View', submenu: [ { label: 'Reload', accelerator: 'CmdOrCtrl+R', click: () => { win.reload(); }, }, ], }, ]; // 创建菜单 const menu = Menu.buildFromTemplate(menuTemplate); // 设置应用程序的菜单 Menu.setApplicationMenu(menu); console.log(Object.keys(memoryCache)) } let memoryDbData = [] let memoryDbPath = undefined app.whenReady().then(() => { ipcMain.handle('get-login-info-data', () => { return readData(loginFilePath); }); ipcMain.handle('set-login-info-data', (event, newData) => { writeData(loginFilePath, newData); }); ipcMain.handle('get-symbol-data', () => { return readData(symbolFilePath); }); ipcMain.handle('set-symbol-data', (event, newData) => { writeData(symbolFilePath, newData); }); ipcMain.handle('get-is-persistent-data', () => { return readData(persistentFilePath); }); ipcMain.handle('set-is-persistent-data', (event, newData) => { writeData(persistentFilePath, newData); }); ipcMain.handle('get-is-merge-data', () => { return readData(mergeFilePath); }); ipcMain.handle('set-is-merge-data', (event, newData) => { writeData(mergeFilePath, newData); }); ipcMain.handle('set-db-data', (event, dataList, symbol) => { const finalPath = path.join(dbBasePath, `${symbol}.json`) writeData(finalPath, dataList) console.log(`Local db is set. ${finalPath}`) }) ipcMain.handle('get-db-data', (event, symbol) => { const finalPath = path.join(dbBasePath, `${symbol}.json`) const rst = readData(finalPath) if (JSON.stringify(rst) === '{}') { console.log(`No local db is found:${finalPath}`) return [] } else { console.log(`Local db is found:${finalPath}, length: ${rst.length}`) return rst } }) ipcMain.handle('flush-memory-db-data', (event, data, symbol) => { memoryDbData = data if (!memoryDbPath) memoryDbPath = path.join(dbBasePath, `${symbol}.json`) // console.log(`Memory db is flush。length: ${memoryDbData.length}, symbol: ${symbol}`) }) }); app.on('ready', () => { // Intercept file requests and serve from memory session.defaultSession.webRequest.onBeforeRequest((details, callback) => { const url = new URL(details.url); const filePath = path.normalize(decodeURIComponent(url.pathname)); let relativePath = filePath.replace(path.normalize(process.resourcesPath), '').replace(/\\/g, '/').replace('//', ''); if (isDev && relativePath.indexOf('react-stock-heatmap/example') !== -1) { relativePath = relativePath.split('react-stock-heatmap/example')[1] } // console.log(relativePath) if (memoryCache[relativePath]) { let sanitizedRelativePath = relativePath.replace('app.asar', 'app_asar'); // 避免路径中包含 app.asar // console.log(app.getPath('temp'), sanitizedRelativePath) const tempFilePath = path.join(app.getPath('temp'), sanitizedRelativePath); // console.log(`Temp File Path: ${tempFilePath}`); const tempDir = path.dirname(tempFilePath); // console.log(`Temp Directory Path: ${tempDir}`); // 确保临时目录路径存在 if (!fs.existsSync(tempDir)) { // console.log(`Creating directory: ${tempDir}`); fs.mkdirSync(tempDir, { recursive: true }); // console.log(`Directory created: ${tempDir}`); } else { // console.log(`Directory already exists: ${tempDir}`); } // 确保目录存在后再写入文件 if (fs.existsSync(tempDir)) { // console.log(`Writing file: ${tempFilePath}`); fs.writeFileSync(tempFilePath, memoryCache[relativePath]); // console.log(`File written: ${tempFilePath}`); // console.log(`Intercepting request for: ${relativePath}, redirectURL: ${tempFilePath}`); callback({ cancel: false, redirectURL: tempFilePath }); } else { // console.error(`Directory does not exist after creation attempt: ${tempDir}`); callback({ cancel: false }); } } else { callback({ cancel: false }); } }); createWindow(); }); app.on('window-all-closed', () => { if (memoryDbData.length > 0 && memoryDbPath) { writeData(memoryDbPath, memoryDbData); console.log(`Exit saved db is ok. length: ${memoryDbData.length}, path:${memoryDbPath}`) } if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } });