2025-09-25 15:31:11 +08:00
|
|
|
|
import { reactive } from 'vue'
|
2025-09-24 16:43:10 +08:00
|
|
|
|
import type { WindowService } from './WindowService'
|
|
|
|
|
|
import type { ResourceService } from './ResourceService'
|
|
|
|
|
|
import type { ApplicationSandboxEngine } from './ApplicationSandboxEngine'
|
|
|
|
|
|
import { v4 as uuidv4 } from 'uuid'
|
2025-09-25 15:31:11 +08:00
|
|
|
|
import { externalAppDiscovery } from './ExternalAppDiscovery'
|
2025-09-24 16:43:10 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 应用状态枚举
|
|
|
|
|
|
*/
|
|
|
|
|
|
export enum AppLifecycleState {
|
|
|
|
|
|
INSTALLING = 'installing',
|
|
|
|
|
|
INSTALLED = 'installed',
|
|
|
|
|
|
STARTING = 'starting',
|
|
|
|
|
|
RUNNING = 'running',
|
|
|
|
|
|
SUSPENDED = 'suspended',
|
|
|
|
|
|
STOPPING = 'stopping',
|
|
|
|
|
|
STOPPED = 'stopped',
|
|
|
|
|
|
UNINSTALLING = 'uninstalling',
|
|
|
|
|
|
ERROR = 'error',
|
|
|
|
|
|
CRASHED = 'crashed',
|
2025-10-10 10:08:05 +08:00
|
|
|
|
AVAILABLE = 'available' // 外置应用可用但未注册状态
|
2025-09-24 16:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 应用清单文件接口
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface AppManifest {
|
|
|
|
|
|
id: string
|
|
|
|
|
|
name: string
|
|
|
|
|
|
version: string
|
|
|
|
|
|
description: string
|
|
|
|
|
|
author: string
|
|
|
|
|
|
homepage?: string
|
|
|
|
|
|
icon: string
|
|
|
|
|
|
entryPoint: string // 入口文件路径
|
|
|
|
|
|
permissions: string[]
|
|
|
|
|
|
minSystemVersion?: string
|
|
|
|
|
|
dependencies?: Record<string, string>
|
|
|
|
|
|
window?: {
|
|
|
|
|
|
width: number
|
|
|
|
|
|
height: number
|
|
|
|
|
|
minWidth?: number
|
|
|
|
|
|
minHeight?: number
|
|
|
|
|
|
maxWidth?: number
|
|
|
|
|
|
maxHeight?: number
|
|
|
|
|
|
resizable?: boolean
|
|
|
|
|
|
center?: boolean
|
|
|
|
|
|
}
|
|
|
|
|
|
background?: {
|
|
|
|
|
|
persistent?: boolean
|
|
|
|
|
|
scripts?: string[]
|
|
|
|
|
|
}
|
|
|
|
|
|
contentSecurity?: {
|
|
|
|
|
|
policy?: string
|
|
|
|
|
|
allowedDomains?: string[]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 应用实例接口
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface AppInstance {
|
|
|
|
|
|
id: string
|
|
|
|
|
|
manifest: AppManifest
|
|
|
|
|
|
state: AppLifecycleState
|
|
|
|
|
|
windowId?: string
|
|
|
|
|
|
sandboxId?: string
|
|
|
|
|
|
processId: string
|
|
|
|
|
|
installedAt: Date
|
|
|
|
|
|
startedAt?: Date
|
|
|
|
|
|
lastActiveAt?: Date
|
|
|
|
|
|
stoppedAt?: Date
|
|
|
|
|
|
errorCount: number
|
|
|
|
|
|
crashCount: number
|
|
|
|
|
|
memoryUsage: number
|
|
|
|
|
|
cpuUsage: number
|
|
|
|
|
|
version: string
|
|
|
|
|
|
autoStart: boolean
|
|
|
|
|
|
persistent: boolean
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 应用启动选项
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface AppStartOptions {
|
|
|
|
|
|
windowConfig?: {
|
|
|
|
|
|
x?: number
|
|
|
|
|
|
y?: number
|
|
|
|
|
|
width?: number
|
|
|
|
|
|
height?: number
|
|
|
|
|
|
state?: 'normal' | 'minimized' | 'maximized'
|
|
|
|
|
|
}
|
|
|
|
|
|
args?: Record<string, any>
|
|
|
|
|
|
background?: boolean
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 应用生命周期事件
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface AppLifecycleEvents {
|
|
|
|
|
|
onInstalled: (appId: string, manifest: AppManifest) => void
|
|
|
|
|
|
onUninstalled: (appId: string) => void
|
|
|
|
|
|
onStarted: (appId: string, processId: string) => void
|
|
|
|
|
|
onStopped: (appId: string, processId: string) => void
|
|
|
|
|
|
onSuspended: (appId: string, processId: string) => void
|
|
|
|
|
|
onResumed: (appId: string, processId: string) => void
|
|
|
|
|
|
onError: (appId: string, error: Error) => void
|
|
|
|
|
|
onCrashed: (appId: string, reason: string) => void
|
|
|
|
|
|
onStateChanged: (appId: string, newState: AppLifecycleState, oldState: AppLifecycleState) => void
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 应用生命周期管理器
|
|
|
|
|
|
*/
|
|
|
|
|
|
export class ApplicationLifecycleManager {
|
|
|
|
|
|
private installedApps = reactive(new Map<string, AppInstance>())
|
|
|
|
|
|
private runningProcesses = reactive(new Map<string, AppInstance>())
|
|
|
|
|
|
private appFiles = new Map<string, Map<string, Blob | string>>() // 应用文件存储
|
|
|
|
|
|
|
|
|
|
|
|
private windowService: WindowService
|
|
|
|
|
|
private resourceService: ResourceService
|
|
|
|
|
|
private sandboxEngine: ApplicationSandboxEngine
|
|
|
|
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
|
|
windowService: WindowService,
|
|
|
|
|
|
resourceService: ResourceService,
|
2025-10-10 10:08:05 +08:00
|
|
|
|
sandboxEngine: ApplicationSandboxEngine
|
2025-09-24 16:43:10 +08:00
|
|
|
|
) {
|
|
|
|
|
|
this.windowService = windowService
|
|
|
|
|
|
this.resourceService = resourceService
|
|
|
|
|
|
this.sandboxEngine = sandboxEngine
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 启动应用
|
|
|
|
|
|
*/
|
|
|
|
|
|
async startApp(appId: string, options: AppStartOptions = {}): Promise<string> {
|
|
|
|
|
|
let app = this.installedApps.get(appId)
|
|
|
|
|
|
|
2025-10-10 10:08:05 +08:00
|
|
|
|
console.log('-----------------------------')
|
|
|
|
|
|
|
2025-09-24 16:43:10 +08:00
|
|
|
|
// 如果应用未安装,检查是否为外置应用
|
2025-09-25 15:31:11 +08:00
|
|
|
|
let isExternalApp = false
|
2025-09-24 16:43:10 +08:00
|
|
|
|
if (!app) {
|
|
|
|
|
|
const externalApp = externalAppDiscovery.getApp(appId)
|
|
|
|
|
|
if (externalApp) {
|
2025-09-25 15:31:11 +08:00
|
|
|
|
console.log(`[LifecycleManager] 发现外置应用 ${appId}`)
|
|
|
|
|
|
isExternalApp = true
|
2025-10-10 10:08:05 +08:00
|
|
|
|
|
2025-09-25 15:31:11 +08:00
|
|
|
|
// 为外部应用创建临时实例
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
app = {
|
|
|
|
|
|
id: externalApp.manifest.id,
|
|
|
|
|
|
manifest: externalApp.manifest,
|
|
|
|
|
|
state: AppLifecycleState.INSTALLED,
|
|
|
|
|
|
processId: '',
|
|
|
|
|
|
installedAt: now,
|
|
|
|
|
|
errorCount: 0,
|
|
|
|
|
|
crashCount: 0,
|
|
|
|
|
|
memoryUsage: 0,
|
|
|
|
|
|
cpuUsage: 0,
|
|
|
|
|
|
version: externalApp.manifest.version,
|
|
|
|
|
|
autoStart: false,
|
2025-10-10 10:08:05 +08:00
|
|
|
|
persistent: false
|
2025-09-25 15:31:11 +08:00
|
|
|
|
}
|
2025-09-24 16:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!app) {
|
|
|
|
|
|
throw new Error(`应用 ${appId} 未安装且未发现`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (app.state === AppLifecycleState.RUNNING) {
|
|
|
|
|
|
throw new Error(`应用 ${appId} 已在运行`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const processId = uuidv4()
|
|
|
|
|
|
app.processId = processId
|
|
|
|
|
|
|
|
|
|
|
|
this.updateAppState(app, AppLifecycleState.STARTING)
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否为内置应用
|
2025-10-10 10:08:05 +08:00
|
|
|
|
let isBuiltInApp = true
|
2025-09-24 16:43:10 +08:00
|
|
|
|
|
|
|
|
|
|
// 创建窗体(如果不是后台应用)
|
|
|
|
|
|
let windowId: string | undefined
|
|
|
|
|
|
if (!options.background && !app.manifest.background?.scripts) {
|
|
|
|
|
|
const windowConfig = {
|
|
|
|
|
|
title: app.manifest.name,
|
|
|
|
|
|
width: options.windowConfig?.width || app.manifest.window?.width || 800,
|
|
|
|
|
|
height: options.windowConfig?.height || app.manifest.window?.height || 600,
|
|
|
|
|
|
x: options.windowConfig?.x,
|
|
|
|
|
|
y: options.windowConfig?.y,
|
|
|
|
|
|
resizable: app.manifest.window?.resizable !== false,
|
|
|
|
|
|
minWidth: app.manifest.window?.minWidth,
|
|
|
|
|
|
minHeight: app.manifest.window?.minHeight,
|
|
|
|
|
|
maxWidth: app.manifest.window?.maxWidth,
|
2025-10-10 10:08:05 +08:00
|
|
|
|
maxHeight: app.manifest.window?.maxHeight
|
2025-09-24 16:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const windowInstance = await this.windowService.createWindow(appId, windowConfig)
|
|
|
|
|
|
windowId = windowInstance.id
|
|
|
|
|
|
app.windowId = windowId
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 对于外置应用,需要创建沙箱;内置应用跳过沙箱
|
|
|
|
|
|
if (isExternalApp && !isBuiltInApp) {
|
|
|
|
|
|
// 为外置应用创建沙箱
|
|
|
|
|
|
const sandboxConfig = {
|
|
|
|
|
|
securityLevel: 2, // HIGH
|
|
|
|
|
|
allowScripts: true,
|
|
|
|
|
|
allowSameOrigin: false, // 安全考虑:不允许同源访问以防止沙箱逃逸
|
|
|
|
|
|
allowForms: true,
|
|
|
|
|
|
networkTimeout: 15000, // 增加超时时间到15秒
|
|
|
|
|
|
csp:
|
|
|
|
|
|
app.manifest.contentSecurity?.policy ||
|
2025-10-10 10:08:05 +08:00
|
|
|
|
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self';"
|
2025-09-24 16:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const sandbox = await this.sandboxEngine.createSandbox(
|
|
|
|
|
|
appId,
|
|
|
|
|
|
windowId || 'background',
|
2025-10-10 10:08:05 +08:00
|
|
|
|
sandboxConfig
|
2025-09-24 16:43:10 +08:00
|
|
|
|
)
|
|
|
|
|
|
app.sandboxId = sandbox.id
|
|
|
|
|
|
|
|
|
|
|
|
// 为外置应用加载代码
|
|
|
|
|
|
await this.loadExternalAppInSandbox(app, sandbox.id)
|
|
|
|
|
|
} else if (isBuiltInApp) {
|
|
|
|
|
|
console.log(`[LifecycleManager] 内置应用 ${appId} 跳过沙箱创建和代码加载`)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.warn(`[LifecycleManager] 未知应用类型: ${appId}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新状态
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
app.startedAt = now
|
|
|
|
|
|
app.lastActiveAt = now
|
|
|
|
|
|
this.updateAppState(app, AppLifecycleState.RUNNING)
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到运行进程列表
|
|
|
|
|
|
this.runningProcesses.set(processId, app)
|
|
|
|
|
|
|
|
|
|
|
|
// 注意:状态变更消息由updateAppState方法自动发送,不需要手动发送
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`应用 ${app.manifest.name} (${appId}) 启动成功,进程ID: ${processId}`)
|
|
|
|
|
|
return processId
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
this.updateAppState(app, AppLifecycleState.ERROR)
|
|
|
|
|
|
app.errorCount++
|
|
|
|
|
|
|
|
|
|
|
|
console.error('应用启动失败:', error)
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 停止应用
|
|
|
|
|
|
*/
|
|
|
|
|
|
async stopApp(appId: string): Promise<boolean> {
|
2025-09-25 15:31:11 +08:00
|
|
|
|
// 首先从已安装应用中查找
|
|
|
|
|
|
let app = this.installedApps.get(appId)
|
2025-10-10 10:08:05 +08:00
|
|
|
|
|
2025-09-25 15:31:11 +08:00
|
|
|
|
// 如果未找到,从运行进程列表中查找(可能是外部应用的临时实例)
|
2025-09-24 16:43:10 +08:00
|
|
|
|
if (!app) {
|
2025-09-25 15:31:11 +08:00
|
|
|
|
for (const runningApp of this.runningProcesses.values()) {
|
|
|
|
|
|
if (runningApp.id === appId) {
|
|
|
|
|
|
app = runningApp
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-10 10:08:05 +08:00
|
|
|
|
|
2025-09-25 15:31:11 +08:00
|
|
|
|
if (!app) {
|
|
|
|
|
|
throw new Error(`应用 ${appId} 未安装或未运行`)
|
2025-09-24 16:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (app.state !== AppLifecycleState.RUNNING && app.state !== AppLifecycleState.SUSPENDED) {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
this.updateAppState(app, AppLifecycleState.STOPPING)
|
|
|
|
|
|
|
|
|
|
|
|
// 销毁沙箱
|
|
|
|
|
|
if (app.sandboxId) {
|
|
|
|
|
|
this.sandboxEngine.destroySandbox(app.sandboxId)
|
|
|
|
|
|
app.sandboxId = undefined
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭窗体(如果还存在)
|
|
|
|
|
|
if (app.windowId) {
|
|
|
|
|
|
const window = this.windowService.getWindow(app.windowId)
|
|
|
|
|
|
if (window) {
|
|
|
|
|
|
await this.windowService.destroyWindow(app.windowId)
|
|
|
|
|
|
}
|
|
|
|
|
|
app.windowId = undefined
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新状态
|
|
|
|
|
|
app.stoppedAt = new Date()
|
|
|
|
|
|
this.updateAppState(app, AppLifecycleState.STOPPED)
|
|
|
|
|
|
|
|
|
|
|
|
// 从运行进程列表中移除
|
|
|
|
|
|
if (app.processId) {
|
|
|
|
|
|
this.runningProcesses.delete(app.processId)
|
|
|
|
|
|
app.processId = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 注意:状态变更消息由updateAppState方法自动发送,不需要手动发送
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`应用 ${appId} 停止成功`)
|
|
|
|
|
|
return true
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('应用停止失败:', error)
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取应用信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
getApp(appId: string): AppInstance | undefined {
|
|
|
|
|
|
return this.installedApps.get(appId)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取所有已安装应用
|
|
|
|
|
|
*/
|
|
|
|
|
|
getAllApps(): AppInstance[] {
|
|
|
|
|
|
return Array.from(this.installedApps.values())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取正在运行的应用
|
|
|
|
|
|
*/
|
|
|
|
|
|
getRunningApps(): AppInstance[] {
|
|
|
|
|
|
return Array.from(this.runningProcesses.values())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 检查应用是否正在运行
|
|
|
|
|
|
*/
|
|
|
|
|
|
isAppRunning(appId: string): boolean {
|
2025-09-25 15:31:11 +08:00
|
|
|
|
// 首先从已安装应用中查找
|
|
|
|
|
|
let app = this.installedApps.get(appId)
|
2025-10-10 10:08:05 +08:00
|
|
|
|
|
2025-09-25 15:31:11 +08:00
|
|
|
|
// 如果未找到,从运行进程列表中查找(可能是外部应用的临时实例)
|
|
|
|
|
|
if (!app) {
|
|
|
|
|
|
for (const runningApp of this.runningProcesses.values()) {
|
|
|
|
|
|
if (runningApp.id === appId) {
|
|
|
|
|
|
app = runningApp
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-10 10:08:05 +08:00
|
|
|
|
|
2025-09-24 16:43:10 +08:00
|
|
|
|
return app?.state === AppLifecycleState.RUNNING || app?.state === AppLifecycleState.SUSPENDED
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取应用统计信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
getAppStats(appId: string) {
|
|
|
|
|
|
const app = this.installedApps.get(appId)
|
|
|
|
|
|
if (!app) return null
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
state: app.state,
|
|
|
|
|
|
errorCount: app.errorCount,
|
|
|
|
|
|
crashCount: app.crashCount,
|
|
|
|
|
|
memoryUsage: app.memoryUsage,
|
|
|
|
|
|
cpuUsage: app.cpuUsage,
|
|
|
|
|
|
startedAt: app.startedAt,
|
|
|
|
|
|
lastActiveAt: app.lastActiveAt,
|
2025-10-10 10:08:05 +08:00
|
|
|
|
uptime: app.startedAt ? Date.now() - app.startedAt.getTime() : 0
|
2025-09-24 16:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 检查权限
|
|
|
|
|
|
*/
|
|
|
|
|
|
private async checkPermissions(permissions: string[]): Promise<void> {
|
|
|
|
|
|
for (const permission of permissions) {
|
|
|
|
|
|
// 这里可以添加权限检查逻辑
|
|
|
|
|
|
// 目前简单允许所有权限
|
|
|
|
|
|
console.log(`检查权限: ${permission}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 为外置应用加载代码到沙箱
|
|
|
|
|
|
*/
|
|
|
|
|
|
private async loadExternalAppInSandbox(app: AppInstance, sandboxId: string): Promise<void> {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const externalApp = externalAppDiscovery.getApp(app.id)
|
|
|
|
|
|
if (!externalApp) {
|
|
|
|
|
|
throw new Error('外置应用信息未找到')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 直接使用外置应用的入口URL
|
|
|
|
|
|
const entryUrl = externalApp.entryPath
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`[LifecycleManager] 加载外置应用: ${app.id} from ${entryUrl}`)
|
|
|
|
|
|
|
|
|
|
|
|
// 在沙箱中加载应用
|
|
|
|
|
|
await this.sandboxEngine.loadApplication(sandboxId, entryUrl)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error(`[LifecycleManager] 加载外置应用到沙箱失败:`, error)
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取所有可用应用(包括内置和外置)
|
|
|
|
|
|
*/
|
|
|
|
|
|
getAllAvailableApps(): (AppInstance & { isExternal?: boolean })[] {
|
|
|
|
|
|
const apps: (AppInstance & { isExternal?: boolean })[] = []
|
|
|
|
|
|
|
|
|
|
|
|
// 添加已安装的应用
|
|
|
|
|
|
for (const app of this.installedApps.values()) {
|
|
|
|
|
|
apps.push(app)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加未注册的外置应用
|
|
|
|
|
|
for (const externalApp of externalAppDiscovery.getDiscoveredApps()) {
|
|
|
|
|
|
if (!this.installedApps.has(externalApp.id)) {
|
|
|
|
|
|
const appInstance: AppInstance & { isExternal: boolean } = {
|
|
|
|
|
|
id: externalApp.manifest.id,
|
|
|
|
|
|
manifest: externalApp.manifest,
|
|
|
|
|
|
state: AppLifecycleState.AVAILABLE,
|
|
|
|
|
|
processId: '',
|
|
|
|
|
|
installedAt: externalApp.lastScanned,
|
|
|
|
|
|
errorCount: 0,
|
|
|
|
|
|
crashCount: 0,
|
|
|
|
|
|
memoryUsage: 0,
|
|
|
|
|
|
cpuUsage: 0,
|
|
|
|
|
|
version: externalApp.manifest.version,
|
|
|
|
|
|
autoStart: false,
|
|
|
|
|
|
persistent: false,
|
2025-10-10 10:08:05 +08:00
|
|
|
|
isExternal: true
|
2025-09-24 16:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
apps.push(appInstance)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return apps
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 刷新外置应用列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
async refreshExternalApps(): Promise<void> {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await externalAppDiscovery.refresh()
|
|
|
|
|
|
console.log('[LifecycleManager] 外置应用列表已刷新')
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[LifecycleManager] 刷新外置应用列表失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 处理应用错误
|
|
|
|
|
|
*/
|
|
|
|
|
|
private handleAppError(appId: string, error: Error): void {
|
|
|
|
|
|
const app = this.installedApps.get(appId)
|
|
|
|
|
|
if (!app) return
|
|
|
|
|
|
|
|
|
|
|
|
app.errorCount++
|
|
|
|
|
|
|
|
|
|
|
|
console.error(`应用 ${appId} 发生错误:`, error)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 处理应用崩溃
|
|
|
|
|
|
*/
|
|
|
|
|
|
private handleAppCrash(appId: string, reason: string): void {
|
|
|
|
|
|
const app = this.installedApps.get(appId)
|
|
|
|
|
|
if (!app) return
|
|
|
|
|
|
|
|
|
|
|
|
app.crashCount++
|
|
|
|
|
|
this.updateAppState(app, AppLifecycleState.CRASHED)
|
|
|
|
|
|
|
|
|
|
|
|
// 清理资源
|
|
|
|
|
|
if (app.processId) {
|
|
|
|
|
|
this.runningProcesses.delete(app.processId)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 注意:状态变更消息由updateAppState方法自动发送,不需要手动发送
|
|
|
|
|
|
|
|
|
|
|
|
console.error(`应用 ${appId} 崩溃: ${reason}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 更新应用状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
private updateAppState(app: AppInstance, newState: AppLifecycleState): void {
|
|
|
|
|
|
const oldState = app.state
|
|
|
|
|
|
app.state = newState
|
|
|
|
|
|
|
2025-10-10 10:28:36 +08:00
|
|
|
|
// 移除事件服务消息发送
|
|
|
|
|
|
// this.eventService.sendMessage('system', 'app-lifecycle', {
|
|
|
|
|
|
// type: 'stateChanged',
|
|
|
|
|
|
// appId: app.id,
|
|
|
|
|
|
// newState,
|
|
|
|
|
|
// oldState
|
|
|
|
|
|
// })
|
2025-09-24 16:43:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|