You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

630 lines
18 KiB

const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const fs = require('fs')
const os = require('os')
const WindowStateManager = require('./windowState')
// 窗口状态管理器(延迟初始化)
let windowStateManager = null
// 设置进程编码,确保中文正常显示
process.env.LANG = 'zh_CN.UTF-8'
process.env.LC_ALL = 'zh_CN.UTF-8'
// 获取项目根目录绝对路径
const appRoot = path.resolve(__dirname, '../..')
// 获取本地IP地址
function getLocalIPAddresses() {
try {
const interfaces = os.networkInterfaces()
const addresses = []
for (const name of Object.keys(interfaces)) {
for (const interface of interfaces[name]) {
// 跳过内部地址和非IPv4地址
if (interface.family === 'IPv4' && !interface.internal) {
addresses.push({
name: name,
address: interface.address,
netmask: interface.netmask,
family: interface.family
})
}
}
}
// 优先返回非回环地址
const nonLoopback = addresses.filter(addr => addr.address !== '127.0.0.1')
return nonLoopback.length > 0 ? nonLoopback[0] : addresses[0] || null
} catch (error) {
console.error('获取本地IP地址失败:', error)
return null
}
}
let mainWindow
let errorLogCount = 0
let logFilePath
// 检查是否为开发环境(延迟初始化)
let isDev = null
function getIsDev() {
if (isDev === null) {
try {
isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
} catch (error) {
// 如果app对象还没有准备好,默认使用开发环境
isDev = process.env.NODE_ENV === 'development' || true
}
}
return isDev
}
// 初始化日志系统
function initLogging() {
try {
// 创建日志目录
const logDir = path.join(app.getPath('userData'), 'logs')
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true })
}
// 设置日志文件路径
const timestamp = new Date().toISOString().split('T')[0]
logFilePath = path.join(logDir, `gofaster-${timestamp}.log`)
// 重定向控制台输出到日志文件,设置UTF-8编码
const logStream = fs.createWriteStream(logFilePath, {
flags: 'a',
encoding: 'utf8'
})
// 重写console.log
const originalLog = console.log
console.log = function(...args) {
const timestamp = new Date().toISOString()
const message = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
).join(' ')
logStream.write(`[${timestamp}] [INFO] ${message}\n`)
originalLog.apply(console, args)
}
// 重写console.error
const originalError = console.error
console.error = function(...args) {
const timestamp = new Date().toISOString()
const message = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
).join(' ')
errorLogCount++
logStream.write(`[${timestamp}] [ERROR] ${message}\n`)
originalError.apply(console, args)
// 通知渲染进程错误计数更新
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('error-log-updated', { count: errorLogCount })
}
}
// 重写console.warn
const originalWarn = console.warn
console.warn = function(...args) {
const timestamp = new Date().toISOString()
const message = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
).join(' ')
logStream.write(`[${timestamp}] [WARN] ${message}\n`)
originalWarn.apply(console, args)
}
} catch (error) {
console.error('初始化日志系统失败:', error)
}
}
// 开发环境热重载 - 只在非watch模式下启用
if (getIsDev() && !process.argv.includes('--watch')) {
try {
// 修复热重载配置
require('electron-reload')(appRoot, {
electron: path.join(__dirname, '..', '..', 'node_modules', 'electron', 'dist', 'electron.exe'),
hardResetMethod: 'exit',
// 添加更稳定的配置
forceHardReset: true,
ignored: [
/node_modules|[\/\\]\./,
/dist|[\/\\]\./,
/\.git|[\/\\]\./
]
});
} catch (error) {
console.log('Hot reload failed:', error.message);
}
}
// 监听文件变化(用于watch模式)
if (getIsDev() && process.argv.includes('--watch')) {
// 监听dist目录变化
const distPath = path.join(appRoot, 'dist/renderer');
if (fs.existsSync(distPath)) {
let reloadTimeout = null;
fs.watch(distPath, { recursive: true }, (eventType, filename) => {
if (filename && mainWindow && !mainWindow.isDestroyed()) {
// 添加防抖机制,避免频繁重载
if (reloadTimeout) {
clearTimeout(reloadTimeout);
}
reloadTimeout = setTimeout(() => {
try {
mainWindow.reload();
} catch (error) {
console.log('Page reload failed:', error.message);
}
}, 500); // 500ms防抖延迟
}
});
}
}
function createWindow() {
try {
// 加载保存的窗口状态
let windowState
if (!windowStateManager) {
console.warn('窗口状态管理器未初始化,使用默认状态')
windowState = {
width: 1200,
height: 800,
x: undefined,
y: undefined,
isMaximized: false,
isFullScreen: false
}
} else {
windowState = windowStateManager.loadState()
}
mainWindow = new BrowserWindow({
width: windowState.width,
height: windowState.height,
x: windowState.x,
y: windowState.y,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(appRoot, 'src/preload.js'),
// 强化安全配置
webSecurity: true,
allowRunningInsecureContent: false,
experimentalFeatures: false,
// 禁用Node.js集成
nodeIntegrationInWorker: false,
nodeIntegrationInSubFrames: false,
// 沙箱模式
sandbox: false, // 保持false以支持preload脚本
// 禁用eval相关功能
enableBlinkFeatures: '',
disableBlinkFeatures: 'Auxclick'
},
// 添加字体配置,确保中文正常显示
titleBarStyle: 'default',
show: false // 先隐藏窗口,等加载完成后再显示
})
// 如果保存的状态是最大化或全屏,应用这些状态
if (windowState.isMaximized) {
mainWindow.maximize()
} else if (windowState.isFullScreen) {
mainWindow.setFullScreen(true)
}
// 开发环境下抑制安全警告
if (getIsDev()) {
mainWindow.webContents.on('did-frame-finish-load', () => {
// 移除有问题的JavaScript执行,避免IPC通信错误
// 简化JavaScript注入,避免序列化错误
mainWindow.webContents.executeJavaScript(`
// 重写console.warn和console.error来抑制特定警告
const originalWarn = console.warn;
const originalError = console.error;
console.warn = function(...args) {
const message = args.join(' ');
if (message.includes('Electron Security Warning') ||
message.includes('Insecure Content-Security-Policy') ||
message.includes('unsafe-eval')) {
return; // 抑制这些警告
}
originalWarn.apply(console, args);
};
console.error = function(...args) {
const message = args.join(' ');
if (message.includes('Electron Security Warning') ||
message.includes('Insecure Content-Security-Policy') ||
message.includes('unsafe-eval')) {
return; // 抑制这些警告
}
originalError.apply(console, args);
};
`).catch(err => {
console.log('JavaScript injection failed:', err.message);
// 注入失败不影响应用运行
});
});
// 抑制Electron安全警告
mainWindow.webContents.on('console-message', (event, level, message, line, sourceId) => {
// 抑制Autofill相关警告
if (message.includes('Autofill.enable failed') ||
message.includes('Autofill.setAddresses failed') ||
message.includes('Request Autofill')) {
event.preventDefault();
return false;
}
// 抑制Electron安全警告
if (message.includes('Electron Security Warning') ||
message.includes('Insecure Content-Security-Policy') ||
message.includes('unsafe-eval')) {
event.preventDefault();
return false;
}
});
}
const loadPath = path.join(appRoot, 'dist/renderer/index.html')
// 检查文件是否存在
if (!fs.existsSync(loadPath)) {
// 在watch模式下等待文件构建完成
if (getIsDev() && process.argv.includes('--watch')) {
const checkFile = () => {
if (fs.existsSync(loadPath)) {
loadMainWindow();
} else {
setTimeout(checkFile, 1000); // 每秒检查一次
}
};
checkFile();
return; // 重要:如果文件不存在,直接返回,不执行后续代码
} else {
// 非watch模式,直接显示错误
console.error('File not found:', loadPath);
mainWindow.loadURL(`data:text/html,<h1>Build file not found, please run npm run dev first</h1>`);
return;
}
}
// 文件存在,直接加载
loadMainWindow();
function loadMainWindow() {
mainWindow.loadFile(loadPath).then(() => {
// 开发环境下打开开发者工具
if (getIsDev()) {
mainWindow.webContents.openDevTools()
}
// 页面加载完成后显示窗口
mainWindow.show()
}).catch(err => {
console.error('Load failed:', err)
mainWindow.loadURL(`data:text/html,<h1>Load failed: ${err.toString()}</h1>`)
// 即使加载失败也要显示窗口
mainWindow.show()
})
}
// 添加窗口状态监听器
// 窗口大小改变时保存状态(防抖)
let resizeTimeout
mainWindow.on('resize', () => {
clearTimeout(resizeTimeout)
resizeTimeout = setTimeout(() => {
if (!mainWindow.isMaximized() && !mainWindow.isFullScreen() && windowStateManager) {
windowStateManager.saveState(mainWindow)
}
}, 500) // 500ms防抖
})
// 窗口移动时保存状态(防抖)
let moveTimeout
mainWindow.on('move', () => {
clearTimeout(moveTimeout)
moveTimeout = setTimeout(() => {
if (!mainWindow.isMaximized() && !mainWindow.isFullScreen() && windowStateManager) {
windowStateManager.saveState(mainWindow)
}
}, 500) // 500ms防抖
})
// 窗口最大化状态变化时保存状态
mainWindow.on('maximize', () => {
if (windowStateManager) {
windowStateManager.saveState(mainWindow)
}
})
mainWindow.on('unmaximize', () => {
if (windowStateManager) {
windowStateManager.saveState(mainWindow)
}
})
// 窗口全屏状态变化时保存状态
mainWindow.on('enter-full-screen', () => {
if (windowStateManager) {
windowStateManager.saveState(mainWindow)
}
})
mainWindow.on('leave-full-screen', () => {
if (windowStateManager) {
windowStateManager.saveState(mainWindow)
}
})
// 窗口即将关闭事件(更早触发)
mainWindow.on('close', (event) => {
// 立即发送事件,不等待
if (!mainWindow.isDestroyed()) {
mainWindow.webContents.send('app-will-close')
}
})
// 窗口关闭事件
mainWindow.on('closed', () => {
// 保存窗口状态
if (windowStateManager) {
windowStateManager.saveState(mainWindow)
}
mainWindow = null
})
} catch (error) {
console.error('Failed to create window:', error)
}
}
app.whenReady().then(() => {
// 初始化窗口状态管理器
windowStateManager = new WindowStateManager('main')
// 初始化日志系统
initLogging()
createWindow()
// 修复IPC通信问题
ipcMain.on('request-status', (event) => {
try {
const statusData = {
status: 'running',
timestamp: Date.now()
}
event.sender.send('status-update', statusData)
} catch (error) {
console.error('IPC communication error:', error);
}
})
// 添加获取进程内存信息的API
ipcMain.handle('get-process-memory-info', async (event) => {
try {
// 使用 process.memoryUsage 获取内存信息
const memoryUsage = process.memoryUsage();
// 获取更详细的系统内存信息
let systemMemoryInfo = {};
try {
// 尝试使用 require('os') 获取系统内存信息
const os = require('os');
systemMemoryInfo = {
totalMemory: os.totalmem(),
freeMemory: os.freemem(),
usedMemory: os.totalmem() - os.freemem()
};
} catch (osError) {
console.warn('Cannot get system memory info:', osError.message);
}
return {
// 进程内存使用情况
privateBytes: memoryUsage.rss, // Resident Set Size - 进程占用的物理内存
sharedBytes: memoryUsage.external, // 外部内存使用
heapUsed: memoryUsage.heapUsed, // JavaScript堆内存使用
heapTotal: memoryUsage.heapTotal, // JavaScript堆内存总量
// 系统内存信息
systemTotal: systemMemoryInfo.totalMemory || 0,
systemFree: systemMemoryInfo.freeMemory || 0,
systemUsed: systemMemoryInfo.usedMemory || 0
};
} catch (error) {
console.error('Failed to get memory info:', error);
// 返回默认值
return {
privateBytes: 0,
sharedBytes: 0,
heapUsed: 0,
heapTotal: 0,
systemTotal: 0,
systemFree: 0,
systemUsed: 0
};
}
});
// 添加更新窗口标题的API
ipcMain.handle('update-window-title', async (event, newTitle) => {
try {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.setTitle(newTitle);
return { success: true, message: '窗口标题更新成功' };
} else {
return { success: false, message: '主窗口不存在或已销毁' };
}
} catch (error) {
console.error('更新窗口标题失败:', error);
return { success: false, message: '更新窗口标题失败: ' + error.message };
}
});
// 获取错误日志计数
ipcMain.handle('get-error-log-count', async () => {
return { count: errorLogCount }
});
// 获取日志文件路径
ipcMain.handle('get-log-file-path', async () => {
return { path: logFilePath }
});
// 打开日志文件所在文件夹
ipcMain.handle('open-log-folder', async () => {
try {
const path = require('path');
const logDir = path.dirname(logFilePath);
require('electron').shell.openPath(logDir);
return { success: true, message: '日志文件夹已打开' };
} catch (error) {
console.error('打开日志文件夹失败:', error);
return { success: false, message: '打开日志文件夹失败: ' + error.message };
}
});
// 获取本地IP地址
ipcMain.handle('get-local-ip', async () => {
try {
const ipInfo = getLocalIPAddresses();
if (ipInfo) {
return {
success: true,
ip: ipInfo.address,
interface: ipInfo.name,
netmask: ipInfo.netmask
};
} else {
return {
success: false,
message: '无法获取本地IP地址',
fallback: '127.0.0.1'
};
}
} catch (error) {
console.error('获取本地IP地址失败:', error);
return {
success: false,
message: '获取本地IP地址失败: ' + error.message,
fallback: '127.0.0.1'
};
}
});
// 窗口状态管理相关的IPC处理器
ipcMain.handle('reset-window-state', async () => {
try {
if (!windowStateManager) {
return {
success: false,
message: '窗口状态管理器未初始化'
}
}
const result = windowStateManager.resetState()
return {
success: result,
message: result ? '窗口状态已重置' : '没有找到保存的窗口状态'
}
} catch (error) {
console.error('重置窗口状态失败:', error)
return {
success: false,
message: '重置窗口状态失败: ' + error.message
}
}
})
ipcMain.handle('get-window-state-info', async () => {
try {
if (!windowStateManager) {
return {
success: false,
message: '窗口状态管理器未初始化'
}
}
const hasState = windowStateManager.hasSavedState()
const statePath = windowStateManager.getStatePath()
let currentState = null
if (hasState) {
try {
const stateData = fs.readFileSync(statePath, 'utf8')
currentState = JSON.parse(stateData)
} catch (error) {
console.error('读取当前窗口状态失败:', error)
}
}
return {
hasSavedState: hasState,
statePath: statePath,
currentState: currentState
}
} catch (error) {
console.error('获取窗口状态信息失败:', error)
return {
success: false,
message: '获取窗口状态信息失败: ' + error.message
}
}
})
}); // 闭合 app.whenReady().then() 的回调函数
app.on('window-all-closed', () => {
// 由于已经在窗口 close 事件中处理了退出登录,这里直接退出
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (mainWindow === null) createWindow()
})
// 添加错误处理
process.on('uncaughtException', (error) => {
console.error('Uncaught exception:', error)
})
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled promise rejection:', reason)
})
// 测试日志系统 - 在开发环境下生成一些测试错误
if (getIsDev()) {
setTimeout(() => {
console.error('测试错误日志 1: 这是一个模拟的错误信息')
}, 5000)
setTimeout(() => {
console.error('测试错误日志 2: 另一个模拟的错误信息')
}, 10000)
}