重启之后清除登录信息

This commit is contained in:
2025-07-15 19:55:59 +08:00
parent 4caff7542e
commit 0b2974e2c9
18 changed files with 1873 additions and 86 deletions

View File

@@ -3,28 +3,46 @@ import { electronApp, optimizer } from '@electron-toolkit/utils'
import Store from 'electron-store'
import { createWindow, createDrageWindow, unregisterAllShortcuts } from './window.js'
import { setupIPC } from './ipc.js'
import { createTray, destroyTray } from './tray.js'
import { getStoreValue } from './store.js'
import { createTray, destroyTray,clearBrowserCache } from './tray.js'
import XEUtils from 'xe-utils'
import fs from 'fs'
import path from 'path'
import dayjs from 'dayjs'
import logger from './utils/logger'
import { clearAllSessionData } from './utils/cacheUtils.js'
import SingleInstanceManager from './utils/singleInstance.js'
import { setStoreValue, getStoreValue ,deleteStore} from './store.js'
import AutoLaunch from 'auto-launch'
import WebSocketClient from './utils/WebSocketClient';
let wsClient=null
wsClient=new WebSocketClient({
autoReconnect: true,
autoReconnectAttempts: 9999,
autoReconnectInterval: 5000,
timeout: 30000,
})
// 延迟创建WebSocket连接等待应用完全启动后再连接
function createWebSocketClient() {
try {
wsClient = new WebSocketClient({
autoReconnect: true,
autoReconnectAttempts: 9999,
autoReconnectInterval: 5000,
timeout: 30000,
});
wsClient.on('open', () => {
logger.info('WebSocket连接已打开')
});
wsClient.on('open', () => {
logger.info('WebSocket连接已打开')
});
wsClient.on('error', (error) => {
logger.error('WebSocket连接错误:', error)
});
wsClient.on('close', (data) => {
logger.info('WebSocket连接已关闭:', data)
});
} catch (error) {
logger.error('创建WebSocket客户端失败:', error)
}
}
var minecraftAutoLauncher = new AutoLaunch({
@@ -53,40 +71,132 @@ if(!XEUtils.isEmpty(difySite)){
logger.info(`当前运行平台: ${process.platform}`)
if (process.platform === 'win32') {
logger.info('Windows 系统,设置控制台编码为 UTF-8')
require('child_process').execSync('chcp 65001', { stdio: 'ignore' })
try {
require('child_process').execSync('chcp 65001', { stdio: 'ignore' })
} catch (error) {
logger.error('设置控制台编码失败:', error)
}
} else {
logger.info('非 Windows 系统,使用默认编码')
}
logger.info('%cRed text. %cGreen text', 'color: red', 'color: green')
const store = new Store()
try {
const store = new Store()
logger.info('Store 初始化成功')
} catch (error) {
logger.error('Store 初始化失败:', error)
}
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors')
app.commandLine.appendSwitch('ignore-certificate-errors')
app.disableHardwareAcceleration()
// 添加缓存相关配置,避免缓存错误
app.commandLine.appendSwitch('disable-http-cache')
app.commandLine.appendSwitch('disable-background-timer-throttling')
app.commandLine.appendSwitch('disable-renderer-backgrounding')
try {
app.disableHardwareAcceleration()
logger.info('硬件加速已禁用')
} catch (error) {
logger.error('禁用硬件加速失败:', error)
}
logger.info(app.getPath('userData'))
logger.info('应用启动,日志文件路径:', logger.getLogPath())
// 添加更多启动信息
logger.info('开始检查单实例锁...')
// 创建单实例管理器
const singleInstanceManager = new SingleInstanceManager()
// 清理缓存目录
function cleanupCacheDirectories() {
try {
const userDataPath = app.getPath('userData')
const cachePaths = [
path.join(userDataPath, 'Cache'),
path.join(userDataPath, 'Code Cache'),
path.join(userDataPath, 'GPUCache'),
path.join(userDataPath, 'Service Worker'),
path.join(userDataPath, 'Session Storage')
]
for (const cachePath of cachePaths) {
if (fs.existsSync(cachePath)) {
logger.info(`清理缓存目录: ${cachePath}`)
try {
// 递归删除目录
const deleteRecursive = (dirPath) => {
if (fs.existsSync(dirPath)) {
const files = fs.readdirSync(dirPath)
for (const file of files) {
const curPath = path.join(dirPath, file)
if (fs.lstatSync(curPath).isDirectory()) {
deleteRecursive(curPath)
} else {
try {
fs.unlinkSync(curPath)
} catch (error) {
logger.warn(`无法删除缓存文件: ${curPath}`, error.message)
}
}
}
try {
fs.rmdirSync(dirPath)
} catch (error) {
logger.warn(`无法删除缓存目录: ${dirPath}`, error.message)
}
}
}
deleteRecursive(cachePath)
logger.info(`缓存目录清理完成: ${cachePath}`)
} catch (error) {
logger.error(`清理缓存目录失败: ${cachePath}`, error)
}
}
}
} catch (error) {
logger.error('清理缓存目录失败:', error)
}
}
// 检查是否为第一个实例
const gotTheLock = app.requestSingleInstanceLock()
const isFirstInstance = singleInstanceManager.checkSingleInstance()
if (!gotTheLock) {
// 如果不是第一个实例,尝试激活第一个实例的窗口
const windows = BrowserWindow.getAllWindows()
if (windows.length > 0) {
const mainWindow = windows[0]
if (mainWindow.isMinimized()) {
mainWindow.restore()
if (!isFirstInstance) {
logger.info('检测到已有实例运行,尝试激活现有实例')
// 尝试激活第一个实例的窗口
try {
const windows = BrowserWindow.getAllWindows()
if (windows.length > 0) {
const mainWindow = windows[0]
if (mainWindow.isMinimized()) {
mainWindow.restore()
}
mainWindow.show()
mainWindow.focus()
logger.info('成功激活现有实例窗口')
app.quit() // 退出当前实例
} else {
logger.warn('未找到现有实例窗口,可能是锁未正确释放')
logger.info('尝试强制启动新实例...')
// 继续启动
}
mainWindow.show()
mainWindow.focus()
} catch (error) {
logger.error('激活现有实例失败:', error)
logger.info('尝试强制启动新实例...')
// 继续启动
}
app.quit() // 退出当前实例
} else {
logger.info('这是第一个实例,继续启动')
// 这是第一个实例
// 监听第二个实例的启动
@@ -104,6 +214,10 @@ if (!gotTheLock) {
})
app.whenReady().then(() => {
logger.info('应用已准备就绪,开始初始化...');
// 清理缓存目录
cleanupCacheDirectories()
// 获取默认会话并全局设置允许第三方 Cookie
const defaultSession = session.defaultSession;
@@ -134,6 +248,13 @@ if (!gotTheLock) {
createTray()
setupIPC()
// exe退出三秒之后即认为关闭过exe程序退出登录
checkIsKeepAlive()
// 延迟创建WebSocket连接
setTimeout(() => {
createWebSocketClient()
}, 2000); // 延迟2秒创建WebSocket连接
minecraftAutoLauncher.isEnabled()
.then(function(isEnabled){
@@ -151,26 +272,134 @@ if (!gotTheLock) {
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
logger.info('应用初始化完成');
})
// 修改窗口关闭行为
app.on('window-all-closed', () => {
app.on('window-all-closed', async (event) => {
if (process.platform !== 'darwin') {
event.preventDefault();
if (!app.isQuiting) {
// 如果不是主动退出,则隐藏所有窗口
BrowserWindow.getAllWindows().forEach(window => {
window.hide()
})
// 清除所有会话数据
try {
await clearAllSessionData('window-all-closed');
} catch (error) {
logger.error('窗口关闭时清理缓存失败:', error);
}
// 清理完成后退出应用
app.quit();
} else {
// 如果是主动退出,则销毁托盘并退出应用
destroyTray()
app.quit()
}
}
})
app.on('before-quit', async (event) => {
// 在应用程序即将退出时执行操作,例如保存数据
event.preventDefault();
// 清除所有会话数据
try {
await clearAllSessionData('before-quit');
} catch (error) {
logger.error('应用退出时清理缓存失败:', error);
}
// 清理完成后退出应用
app.quit();
});
// 在应用退出时注销所有快捷键
app.on('will-quit', () => {
app.on('will-quit', async (event) => {
event.preventDefault();
// 清除所有会话数据
try {
await clearAllSessionData('will-quit');
} catch (error) {
logger.error('应用退出时清理缓存失败:', error);
}
unregisterAllShortcuts()
// 清理完成后退出应用
app.quit();
})
// 监听进程退出信号,确保在系统强制关闭时也能清理缓存
process.on('SIGTERM', async () => {
logger.info('收到 SIGTERM 信号,开始清理缓存');
try {
await clearAllSessionData('SIGTERM');
} catch (error) {
logger.error('SIGTERM 时清理缓存失败:', error);
}
process.exit(0);
});
process.on('SIGINT', async () => {
logger.info('收到 SIGINT 信号,开始清理缓存');
try {
await clearAllSessionData('SIGINT');
} catch (error) {
logger.error('SIGINT 时清理缓存失败:', error);
}
process.exit(0);
});
// 监听未捕获的异常,确保应用崩溃时也能记录日志
process.on('uncaughtException', (error) => {
logger.error('未捕获的异常:', error);
// 不要立即退出,给应用一个恢复的机会
logger.error('应用遇到未捕获的异常,但将继续运行');
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('未处理的 Promise 拒绝:', reason);
// 不要立即退出,给应用一个恢复的机会
logger.error('应用遇到未处理的 Promise 拒绝,但将继续运行');
});
}
export function checkIsKeepAlive(){
const checkIsKeepAliveTimer=setInterval(async () => {
const lastAliveTime = getStoreValue("lastAliveTime")||null
if (lastAliveTime!=null){
const nowTime=dayjs();
const lastTime=dayjs(lastAliveTime);
const diff=nowTime.diff(lastTime, 'second')
// 上次在线事件在三秒之前则认为关闭过exe程序
if (diff>5){
logger.info('上次在线事件在三秒之前则认为关闭过exe程序')
await clearAllSessionData('超时5秒');
deleteStore("lastAliveTime")
}else{
setStoreValue("lastAliveTime",dayjs())
}
}
}, 1000 * 2)
}

View File

@@ -10,7 +10,7 @@ import path from 'path';
log.initialize();
import {checkForUpdates} from "./utils/updateUtils"
import logger from './utils/logger'
import dayjs from 'dayjs'
function isValidUrl(_url) {
const containsApp = _url.includes('/app/');
@@ -34,9 +34,8 @@ export function setupIPC() {
setStoreValue("difySite", data.difySite);
setStoreValue("test_12222222", "test_12222222");
setStoreValue("lastAliveTime",dayjs())
difyRetryRequestTimer()

View File

@@ -1,38 +1,22 @@
import { Tray, Menu, app, BrowserWindow } from 'electron'
import { Tray, Menu, app, BrowserWindow, shell } from 'electron'
import { join } from 'path'
import icon from '../../resources/icon.png?asset'
import { getMainWindow, createWindow, createApiConfigWindow, createConfigWindow ,getDragWindow} from './window.js'
import { getStoreValue, setStoreValue, clearStore } from './store.js'
import { createDrageWindow, getDrageWindow } from './window.js'
import logger from './utils/logger'
import { clearAllWindowsCache } from './utils/cacheUtils.js'
import fs from 'fs'
import path from 'path'
let tray = null
import {checkForUpdates} from "./utils/updateUtils"
async function clearBrowserCache() {
export async function clearBrowserCache() {
try {
// 清除所有窗口的浏览器缓存
const windows = BrowserWindow.getAllWindows()
for (const window of windows) {
const session = window.webContents.session
await session.clearStorageData({
storages: [
'appcache',
'cookies',
'filesystem',
'indexdb',
'localstorage',
'shadercache',
'websql',
'serviceworkers',
'cachestorage'
]
})
}
logger.info('浏览器缓存清除成功')
// 使用统一的缓存清理函数
await clearAllWindowsCache('tray-clear-cache');
} catch (error) {
logger.error('清除浏览器缓存失败:', error)
}
@@ -108,6 +92,7 @@ export function createTray() {
checkForUpdates(menuItem,true)
}
},
{ type: 'separator' },
{
label: '清除缓存',

View File

@@ -6,16 +6,19 @@ import { Notification } from "electron";
class WebSocketClient {
constructor(options = {}) {
this.reconnectInterval = 5000; // 重连间隔时间
this.reconnectInterval = options.reconnectInterval || 5000; // 重连间隔时间
this.lockReconnect = false;
this.ws = null;
this.pingTimeout = null;
this.reconnectAttempts = 0;
this.messageHandlers = new Map();
this.isConnected = false;
this.options = options;
// 初始化时立即创建连接
this.createConnect();
// 延迟创建连接,避免在应用启动时立即连接
setTimeout(() => {
this.createConnect();
}, 1000);
}
createConnect() {
@@ -26,10 +29,10 @@ class WebSocketClient {
// 检查必要的连接信息是否存在
if (!apiUrl || !userInfo || !token) {
logger.error("WebSocket连接信息不完整等待重试");
logger.error("apiUrl:", apiUrl);
logger.error("userInfo:", userInfo);
logger.error("token:", token);
logger.info("WebSocket连接信息不完整等待重试");
logger.info("apiUrl:", apiUrl);
logger.info("userInfo:", userInfo);
logger.info("token:", token);
this.scheduleReconnect();
return;
}
@@ -92,10 +95,8 @@ class WebSocketClient {
this.ws = new WebSocket(this.url, token, this.options);
this.ws.on('open', () => {
logger.info('😀😀😀😀 WebSocket connect create ok 😀😀😀😀');
logger.info('😀😀😀😀 WebSocket connect create ok 😀😀😀😀');
logger.info('😀😀😀😀 WebSocket connect create ok 😀😀😀😀');
logger.info('WebSocket protocol:', this.ws.protocol); // 添加协议日志
logger.info('WebSocket 连接成功');
logger.info('WebSocket protocol:', this.ws.protocol);
this.isConnected = true;
this.reconnectAttempts = 0;
this.lockReconnect = false;
@@ -105,8 +106,19 @@ class WebSocketClient {
this.ws.on('message', (data) => {
try {
logger.info('收到消息:', data.toString());
const message = JSON.parse(data);
const messageStr = data.toString();
const message = JSON.parse(messageStr);
// 减少心跳消息的日志打印
if (message.cmd === 'heartcheck') {
// 心跳消息不打印日志,或者只在调试模式下打印
if (process.env.NODE_ENV === 'development') {
logger.debug('收到心跳消息');
}
} else {
logger.info('收到消息:', messageStr);
}
this.handleMessage(message);
} catch (error) {
logger.error('消息解析错误:', error);

View File

@@ -0,0 +1,93 @@
import { session } from 'electron'
import logger from './logger.js'
/**
* 清除所有会话数据的统一函数
* @param {string} context - 清理上下文,用于日志记录
* @returns {Promise<void>}
*/
export async function clearAllSessionData(context = 'unknown') {
logger.info(`[${context}] 开始清除所有会话数据`);
try {
await new Promise((resolve, reject) => {
session.defaultSession.clearStorageData({
storages: [
'appcache',
'cookies',
'filesystem',
'indexdb',
'localstorage',
'shadercache',
'websql',
'serviceworkers',
'cachestorage'
]
}, (error) => {
if (error) {
logger.error(`[${context}] 清除会话数据失败:`, error);
reject(error);
} else {
logger.info(`[${context}] 会话数据清除成功`);
resolve();
}
});
});
// 强制同步日志
logger.info(`[${context}] 缓存清理完成`);
// 等待一小段时间确保日志写入
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
logger.error(`[${context}] 清理缓存失败:`, error);
throw error;
}
}
/**
* 清除所有窗口的浏览器缓存
* @param {string} context - 清理上下文,用于日志记录
* @returns {Promise<void>}
*/
export async function clearAllWindowsCache(context = 'unknown') {
logger.info(`[${context}] 开始清除所有窗口的浏览器缓存`);
try {
const { BrowserWindow } = require('electron');
const windows = BrowserWindow.getAllWindows();
for (const window of windows) {
const session = window.webContents.session;
await new Promise((resolve, reject) => {
session.clearStorageData({
storages: [
'appcache',
'cookies',
'filesystem',
'indexdb',
'localstorage',
'shadercache',
'websql',
'serviceworkers',
'cachestorage'
]
}, (error) => {
if (error) {
logger.error(`[${context}] 清除窗口缓存失败:`, error);
reject(error);
} else {
resolve();
}
});
});
}
logger.info(`[${context}] 所有窗口缓存清除成功`);
} catch (error) {
logger.error(`[${context}] 清除窗口缓存失败:`, error);
throw error;
}
}

View File

@@ -1,14 +1,72 @@
import log from 'electron-log/main';
import { app } from 'electron';
import path from 'path';
log.initialize();
// 配置日志立即写入
log.transports.file.level = 'info';
log.transports.console.level = 'info';
// 确保日志立即写入文件
log.transports.file.sync = true;
// 获取日志文件路径
const logFilePath = log.transports.file.getFile().path;
log.info(`日志文件路径: ${logFilePath}`);
// 日志级别配置
const LOG_LEVELS = {
ERROR: 0,
WARN: 1,
INFO: 2,
DEBUG: 3
};
let currentLogLevel = LOG_LEVELS.INFO; // 默认日志级别
// 设置日志级别
export function setLogLevel(level) {
if (typeof level === 'string') {
currentLogLevel = LOG_LEVELS[level.toUpperCase()] || LOG_LEVELS.INFO;
} else {
currentLogLevel = level;
}
}
// 检查是否应该打印日志
function shouldLog(level) {
return level <= currentLogLevel;
}
export const logger = {
log: log.info,
info: log.info,
error: log.error,
warn: log.warn,
debug: log.debug
log: (message, ...args) => {
if (shouldLog(LOG_LEVELS.INFO)) {
log.info(message, ...args);
}
},
info: (message, ...args) => {
if (shouldLog(LOG_LEVELS.INFO)) {
log.info(message, ...args);
}
},
error: (message, ...args) => {
if (shouldLog(LOG_LEVELS.ERROR)) {
log.error(message, ...args);
}
},
warn: (message, ...args) => {
if (shouldLog(LOG_LEVELS.WARN)) {
log.warn(message, ...args);
}
},
debug: (message, ...args) => {
if (shouldLog(LOG_LEVELS.DEBUG)) {
log.debug(message, ...args);
}
},
getLogPath: () => logFilePath,
setLogLevel: setLogLevel
}
export default logger

View File

@@ -0,0 +1,205 @@
import { app } from 'electron'
import fs from 'fs'
import path from 'path'
import logger from './logger.js'
/**
* 单实例锁管理工具
*/
export class SingleInstanceManager {
constructor() {
this.lockFile = null
this.isLocked = false
}
/**
* 清理可能存在的无效单实例锁
*/
cleanupInvalidLock() {
try {
const userDataPath = app.getPath('userData')
const possibleLockFiles = [
path.join(userDataPath, 'single-instance-lock'),
path.join(userDataPath, 'lockfile'),
path.join(userDataPath, '.lock'),
path.join(process.cwd(), 'single-instance-lock'),
path.join(process.cwd(), 'lockfile'),
path.join(process.cwd(), '.lock')
]
for (const lockFile of possibleLockFiles) {
if (fs.existsSync(lockFile)) {
logger.info(`发现锁文件: ${lockFile}`)
// 检查锁文件是否有效(检查进程是否还在运行)
try {
const lockContent = fs.readFileSync(lockFile, 'utf8')
const pid = parseInt(lockContent.trim())
if (pid && this.isProcessRunning(pid)) {
logger.info(`进程 ${pid} 仍在运行,锁文件有效`)
} else {
logger.info(`进程 ${pid} 不存在,尝试删除无效锁文件`)
this.safeDeleteFile(lockFile)
}
} catch (error) {
logger.info(`锁文件无效,尝试删除: ${lockFile}`)
this.safeDeleteFile(lockFile)
}
}
}
} catch (error) {
logger.error('清理无效锁文件失败:', error)
}
}
/**
* 安全删除文件,处理文件被占用的情况
*/
safeDeleteFile(filePath) {
try {
// 首先尝试直接删除
fs.unlinkSync(filePath)
logger.info(`成功删除文件: ${filePath}`)
} catch (error) {
if (error.code === 'EBUSY' || error.code === 'EACCES') {
logger.warn(`文件被占用,无法删除: ${filePath}`)
logger.warn(`错误信息: ${error.message}`)
// 在 Windows 上尝试使用 del 命令
if (process.platform === 'win32') {
try {
const { execSync } = require('child_process')
execSync(`del /F /Q "${filePath}"`, { stdio: 'ignore' })
logger.info(`使用 del 命令删除文件: ${filePath}`)
} catch (delError) {
logger.error(`del 命令删除失败: ${filePath}`, delError)
}
}
} else {
logger.error(`删除文件失败: ${filePath}`, error)
}
}
}
/**
* 检查进程是否还在运行
*/
isProcessRunning(pid) {
try {
// 在 Windows 上使用 tasklist 命令检查进程
if (process.platform === 'win32') {
const { execSync } = require('child_process')
const result = execSync(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { encoding: 'utf8' })
return result.includes(pid.toString())
} else {
// 在 Unix 系统上使用 kill -0 检查进程
const { execSync } = require('child_process')
execSync(`kill -0 ${pid}`, { stdio: 'ignore' })
return true
}
} catch (error) {
return false
}
}
/**
* 创建锁文件
*/
createLock() {
try {
const userDataPath = app.getPath('userData')
this.lockFile = path.join(userDataPath, 'single-instance-lock')
// 写入当前进程的 PID
fs.writeFileSync(this.lockFile, process.pid.toString())
this.isLocked = true
logger.info(`创建单实例锁文件: ${this.lockFile}, PID: ${process.pid}`)
// 监听应用退出事件,清理锁文件
app.on('before-quit', () => {
this.removeLock()
})
app.on('will-quit', () => {
this.removeLock()
})
// 监听进程退出信号
process.on('exit', () => {
this.removeLock()
})
process.on('SIGINT', () => {
this.removeLock()
process.exit(0)
})
process.on('SIGTERM', () => {
this.removeLock()
process.exit(0)
})
} catch (error) {
logger.error('创建锁文件失败:', error)
}
}
/**
* 移除锁文件
*/
removeLock() {
if (this.lockFile && this.isLocked) {
try {
if (fs.existsSync(this.lockFile)) {
fs.unlinkSync(this.lockFile)
logger.info(`移除锁文件: ${this.lockFile}`)
}
this.isLocked = false
} catch (error) {
logger.error('移除锁文件失败:', error)
}
}
}
/**
* 检查是否为第一个实例
*/
checkSingleInstance() {
// 首先清理可能存在的无效锁
this.cleanupInvalidLock()
// 尝试获取单实例锁
const gotTheLock = app.requestSingleInstanceLock()
logger.info(`单实例锁检查结果: ${gotTheLock}`)
if (gotTheLock) {
// 成功获取锁,创建锁文件
this.createLock()
return true
} else {
// 无法获取锁,检查是否真的有必要阻止启动
logger.info('检测到已有实例运行')
// 检查是否有实际的窗口存在
const windows = require('electron').BrowserWindow.getAllWindows()
if (windows.length === 0) {
logger.warn('未找到现有实例窗口,可能是锁文件问题,允许强制启动')
// 尝试强制获取锁
try {
this.createLock()
return true
} catch (error) {
logger.error('强制创建锁失败:', error)
return false
}
} else {
logger.info(`找到 ${windows.length} 个现有窗口,阻止新实例启动`)
return false
}
}
}
}
export default SingleInstanceManager

View File

@@ -11,13 +11,12 @@ import { setStoreValue, getStoreValue,deleteStore } from './store.js'
import {checkForUpdates} from "./utils/updateUtils"
import dayjs from 'dayjs'
let mainWindow = null
let difyfullScreenWindow = null
let drageWindow = null
let apiConfigWindow = null
let configWindow = null
import { clearAllSessionData } from './utils/cacheUtils.js'
// 权限授权
async function checkMediaAccess(mediaType){
const result = systemPreferences.getMediaAccessStatus(mediaType)
@@ -109,6 +108,9 @@ export async function createWindow() {
mainWindow.webContents.on('before-input-event', (event, input) => {
if (input.key === 'F12') {
mainWindow.webContents.toggleDevTools()
} else if (input.key === 'F5') {
logger.info('主窗口 F5 快捷键触发')
mainWindow.reload()
}
})
@@ -164,9 +166,11 @@ export async function createWindow() {
// 加载存储的 URL
mainWindow.loadURL(h5_client_url)
// 超过30分钟不活动则退出登录
// 接口超过30分钟不活动则退出登录
await tokenExpireTimer()
setTimeout(()=>{
try {
// 注册全局快捷键
@@ -189,21 +193,44 @@ export async function createWindow() {
});
}
// 添加一个专门的快捷键注册函数
function registerShortcuts(window) {
function registerShortcuts(window=null) {
// 先注销可能存在的F5快捷键
globalShortcut.unregister('F5')
// 注册 F5 刷新快捷键
globalShortcut.register('F5', () => {
const success = globalShortcut.register('F5', () => {
logger.info('F5 快捷键触发')
if (window && !window.isDestroyed()) {
window.reload()
try {
// 获取当前焦点窗口
const focusedWindow = BrowserWindow.getFocusedWindow()
logger.info('当前焦点窗口:', focusedWindow ? '存在' : '不存在')
if (focusedWindow && !focusedWindow.isDestroyed()) {
logger.info('刷新当前焦点窗口')
focusedWindow.reload()
} else if (mainWindow && !mainWindow.isDestroyed()) {
logger.info('没有焦点窗口,刷新主窗口')
mainWindow.reload()
} else if (difyfullScreenWindow && !difyfullScreenWindow.isDestroyed()) {
logger.info('主窗口不可用,刷新全屏窗口')
difyfullScreenWindow.reload()
} else {
logger.warn('没有可用的窗口进行刷新')
}
} catch (error) {
logger.error('F5快捷键执行出错:', error)
}
})
logger.info(`F5快捷键注册${success ? '成功' : '失败'}`)
const isRegistered_F12 = globalShortcut.isRegistered('F12');
logger.info(`Is CommandOrControl+X registered: ${isRegistered_F12}`);
logger.info(`Is F12 registered: ${isRegistered_F12}`);
// 桌面端快要退出的时候,注销快捷键
app.on('will-quit', () => {
@@ -236,6 +263,8 @@ export async function createNewWindow(url, access_token, refresh_token,sandbox=f
difyfullScreenWindow.on('ready-to-show', () => {
difyfullScreenWindow.show()
// 确保快捷键在新窗口显示后也能工作
registerShortcuts(difyfullScreenWindow)
})
let code = `localStorage.setItem("IsHsAiApp","IsHsAiApp");localStorage.setItem("console_token","${access_token}");localStorage.setItem("refresh_token","12");`
@@ -298,6 +327,9 @@ export async function createNewWindow(url, access_token, refresh_token,sandbox=f
difyfullScreenWindow.webContents.on('before-input-event', (event, input) => {
if (input.key === 'F12') {
difyfullScreenWindow.webContents.toggleDevTools()
} else if (input.key === 'F5') {
logger.info('全屏窗口 F5 快捷键触发')
difyfullScreenWindow.reload()
}
})
@@ -467,18 +499,29 @@ export function createDrageWindow() {
drageWindow.setPosition(screenWidth - drageWindow.getSize()[0] -100, screenHeight - drageWindow.getSize()[1] - 100)
}
export async function tokenExpireTimer(){
let lastLogTime = 0; // 记录上次打印日志的时间
const LOG_INTERVAL = 60000; // 日志打印间隔60秒打印一次
const tokenExpireTimer = setInterval(async () => {
logger.info("tokenExpireTimer 触发")
const currentTime = Date.now();
const lastActiveTime = getStoreValue("lastActiveTime")||null
if (lastActiveTime!=null){
logger.info("tokenExpireTimer 触发 对比时间戳")
try {
const nowTime=dayjs();
const lastTime=dayjs(lastActiveTime);
const diff=nowTime.diff(lastTime, 'minute')
logger.info("tokenExpireTimer 触发 对比时间戳差距为:"+diff)
// 只在特定条件下打印日志,减少日志频率
if (currentTime - lastLogTime > LOG_INTERVAL) {
logger.info(`tokenExpireTimer 检查 - 时间差距: ${diff}分钟`)
lastLogTime = currentTime;
}
if ( diff> 30) {
logger.info(`用户超时退出登录 - 时间差距: ${diff}分钟`)
deleteStore("lastActiveTime")
try {
// 清除所有窗口的浏览器缓存
@@ -512,7 +555,7 @@ export async function tokenExpireTimer(){
}
} catch (e) {
logger.error('tokenExpireTimer 执行错误:', e)
}
}
}, 1000 * 10)
@@ -610,3 +653,32 @@ export function closeConfigWindow() {
configWindow = null
}
}
// 测试快捷键是否正常工作
export function testShortcuts() {
logger.info('测试快捷键功能...')
// 检查F5快捷键是否已注册
const isF5Registered = globalShortcut.isRegistered('F5')
logger.info(`F5快捷键是否已注册: ${isF5Registered}`)
// 获取所有已注册的快捷键
const allShortcuts = globalShortcut.isRegistered('F5') ? ['F5'] : []
logger.info(`已注册的快捷键: ${allShortcuts.join(', ')}`)
// 获取当前焦点窗口
const focusedWindow = BrowserWindow.getFocusedWindow()
logger.info(`当前焦点窗口: ${focusedWindow ? '存在' : '不存在'}`)
if (focusedWindow) {
logger.info(`焦点窗口标题: ${focusedWindow.getTitle()}`)
logger.info(`焦点窗口是否销毁: ${focusedWindow.isDestroyed()}`)
}
return {
f5Registered: isF5Registered,
focusedWindow: focusedWindow ? 'exists' : 'none',
mainWindow: mainWindow && !mainWindow.isDestroyed() ? 'exists' : 'none',
difyWindow: difyfullScreenWindow && !difyfullScreenWindow.isDestroyed() ? 'exists' : 'none'
}
}