fix: harden startup flow and auth re-entry
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { BrowserWindow, app, shell } from 'electron'
|
||||
import { join } from 'path'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import icon from '../../../resources/icon.png?asset'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { dirname } from 'path'
|
||||
@@ -8,6 +7,10 @@ import { dirname } from 'path'
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
|
||||
function isDevelopment(): boolean {
|
||||
return Boolean(process.env['ELECTRON_RENDERER_URL']) || process.env.NODE_ENV === 'development'
|
||||
}
|
||||
|
||||
export function createMainWindow(): BrowserWindow {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 1200,
|
||||
@@ -32,7 +35,7 @@ export function createMainWindow(): BrowserWindow {
|
||||
return { action: 'deny' }
|
||||
})
|
||||
|
||||
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
||||
if (isDevelopment() && process.env['ELECTRON_RENDERER_URL']) {
|
||||
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
|
||||
} else {
|
||||
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { app, dialog } from 'electron'
|
||||
import { electronApp, optimizer } from '@electron-toolkit/utils'
|
||||
import fs from 'fs'
|
||||
import { join } from 'path'
|
||||
import { ConfigManager } from '../services/config/config-manager'
|
||||
@@ -12,10 +11,23 @@ export function configurePlaywrightBrowsersPath(): string {
|
||||
}
|
||||
|
||||
export function setupElectronRuntime(): void {
|
||||
electronApp.setAppUserModelId('com.electron')
|
||||
app.setAppUserModelId('com.electron')
|
||||
|
||||
app.on('browser-window-created', (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window)
|
||||
window.webContents.on('before-input-event', (event, input) => {
|
||||
const isReloadShortcut = (input.control || input.meta) && input.key.toLowerCase() === 'r'
|
||||
const isToggleDevTools = input.key === 'F12'
|
||||
|
||||
if (!app.isPackaged && isToggleDevTools && input.type === 'keyDown') {
|
||||
window.webContents.toggleDevTools()
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (app.isPackaged && isReloadShortcut) {
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,10 @@ import {
|
||||
} from './bootstrap/runtime'
|
||||
import { setupProcessGuards } from './bootstrap/process-guards'
|
||||
|
||||
const playwrightBrowsersPath = configurePlaywrightBrowsersPath()
|
||||
|
||||
setupProcessGuards()
|
||||
registerMainWindowLifecycle()
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
setupProcessGuards()
|
||||
registerMainWindowLifecycle()
|
||||
const playwrightBrowsersPath = configurePlaywrightBrowsersPath()
|
||||
ensurePlaywrightRuntime(playwrightBrowsersPath)
|
||||
await initializeMainProcessServices()
|
||||
setupElectronRuntime()
|
||||
|
||||
@@ -15,6 +15,8 @@ import type {
|
||||
const log = createLogger('AuthApplicationService')
|
||||
|
||||
export class AuthApplicationService {
|
||||
private silentLoginPromise: Promise<SilentLoginResponse> | null = null
|
||||
|
||||
constructor(
|
||||
private readonly sessionManager: SessionManager = SessionManager.getInstance(),
|
||||
private readonly updateService: UpdateService = UpdateService.getInstance()
|
||||
@@ -25,6 +27,20 @@ export class AuthApplicationService {
|
||||
}
|
||||
|
||||
async silentLogin(): Promise<SilentLoginResponse> {
|
||||
if (this.silentLoginPromise) {
|
||||
log.debug('Reusing in-flight silent login request')
|
||||
return this.silentLoginPromise
|
||||
}
|
||||
|
||||
this.silentLoginPromise = this.performSilentLogin()
|
||||
try {
|
||||
return await this.silentLoginPromise
|
||||
} finally {
|
||||
this.silentLoginPromise = null
|
||||
}
|
||||
}
|
||||
|
||||
private async performSilentLogin(): Promise<SilentLoginResponse> {
|
||||
log.info('Attempting silent login')
|
||||
const success = await this.sessionManager.loginByComputerName()
|
||||
const userInfo = this.sessionManager.getUserInfo()
|
||||
|
||||
@@ -133,7 +133,7 @@ export class ConfigManager {
|
||||
if (this.initialized) return
|
||||
|
||||
// 检测是否为开发环境
|
||||
const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
|
||||
const isDev = process.env.NODE_ENV === 'development' || !(app?.isPackaged ?? false)
|
||||
|
||||
if (isDev) {
|
||||
// 开发环境:配置文件放在项目根目录,方便编辑和调试
|
||||
|
||||
@@ -115,7 +115,7 @@ export function setLogLevel(level: string): void {
|
||||
}
|
||||
|
||||
// Add error-specific file transport in production
|
||||
if (app.isPackaged) {
|
||||
if (app?.isPackaged) {
|
||||
logger.add(
|
||||
new DailyRotateFile({
|
||||
filename: path.join(getLogDir(), 'error-%DATE%.log'),
|
||||
|
||||
@@ -44,7 +44,7 @@ function appendPortableLaunchLog(
|
||||
}
|
||||
|
||||
function getCurrentAppVersion(): string {
|
||||
return typeof app.getVersion === 'function' ? app.getVersion() : '0.0.0'
|
||||
return typeof app?.getVersion === 'function' ? app.getVersion() : '0.0.0'
|
||||
}
|
||||
|
||||
function getCurrentChannel(): ReleaseChannel {
|
||||
@@ -79,7 +79,7 @@ function getSupportState(config: UpdateConfig | null): {
|
||||
return { supported: false, reason: '当前仅支持 Windows 自动更新' }
|
||||
}
|
||||
|
||||
if (app.isPackaged) {
|
||||
if (app?.isPackaged) {
|
||||
return { supported: true }
|
||||
}
|
||||
|
||||
|
||||
@@ -43,9 +43,10 @@ export class SessionManager {
|
||||
* @returns True if login successful, false otherwise
|
||||
*/
|
||||
public async login(username: string, password: string): Promise<boolean> {
|
||||
let dao: InstanceType<(typeof import('./bip-users-dao'))['BIPUsersDAO']> | null = null
|
||||
try {
|
||||
const { BIPUsersDAO } = await import('./bip-users-dao')
|
||||
const dao = new BIPUsersDAO()
|
||||
dao = new BIPUsersDAO()
|
||||
const userInfo = await dao.authenticate(username, password)
|
||||
|
||||
if (userInfo) {
|
||||
@@ -60,6 +61,12 @@ export class SessionManager {
|
||||
} catch (error) {
|
||||
console.error('[SessionManager] Login error:', error)
|
||||
return false
|
||||
} finally {
|
||||
if (dao) {
|
||||
await dao.disconnect().catch((error) => {
|
||||
console.error('[SessionManager] Login disconnect error:', error)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,10 +75,11 @@ export class SessionManager {
|
||||
* @returns True if login successful, false otherwise
|
||||
*/
|
||||
public async loginByComputerName(): Promise<boolean> {
|
||||
let dao: InstanceType<(typeof import('./bip-users-dao'))['BIPUsersDAO']> | null = null
|
||||
try {
|
||||
const { BIPUsersDAO } = await import('./bip-users-dao')
|
||||
const { hostname } = await import('os')
|
||||
const dao = new BIPUsersDAO()
|
||||
dao = new BIPUsersDAO()
|
||||
const computerName = hostname()
|
||||
const userInfo = await dao.authenticateByComputerName(computerName)
|
||||
|
||||
@@ -87,6 +95,12 @@ export class SessionManager {
|
||||
} catch (error) {
|
||||
console.error('[SessionManager] Silent login error:', error)
|
||||
return false
|
||||
} finally {
|
||||
if (dao) {
|
||||
await dao.disconnect().catch((error) => {
|
||||
console.error('[SessionManager] Silent login disconnect error:', error)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,13 +188,20 @@ export class SessionManager {
|
||||
* Get all users from database (for Admin user selection)
|
||||
*/
|
||||
public async getAllUsers(): Promise<UserInfo[]> {
|
||||
let dao: InstanceType<(typeof import('./bip-users-dao'))['BIPUsersDAO']> | null = null
|
||||
try {
|
||||
const { BIPUsersDAO } = await import('./bip-users-dao')
|
||||
const dao = new BIPUsersDAO()
|
||||
dao = new BIPUsersDAO()
|
||||
return await dao.getAllUsers()
|
||||
} catch (error) {
|
||||
console.error('[SessionManager] Get all users error:', error)
|
||||
return []
|
||||
} finally {
|
||||
if (dao) {
|
||||
await dao.disconnect().catch((error) => {
|
||||
console.error('[SessionManager] Get all users disconnect error:', error)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user