Files
vue-desktop/src/services/ApplicationLifecycleManager.ts
2025-09-25 15:31:11 +08:00

1057 lines
29 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { reactive } from 'vue'
import type { WindowService } from './WindowService'
import type { ResourceService } from './ResourceService'
import type { EventCommunicationService } from './EventCommunicationService'
import type { ApplicationSandboxEngine } from './ApplicationSandboxEngine'
import { v4 as uuidv4 } from 'uuid'
import { externalAppDiscovery } from './ExternalAppDiscovery'
/**
* 应用状态枚举
*/
export enum AppLifecycleState {
INSTALLING = 'installing',
INSTALLED = 'installed',
STARTING = 'starting',
RUNNING = 'running',
SUSPENDED = 'suspended',
STOPPING = 'stopping',
STOPPED = 'stopped',
UNINSTALLING = 'uninstalling',
ERROR = 'error',
CRASHED = 'crashed',
AVAILABLE = 'available', // 外置应用可用但未注册状态
}
/**
* 应用清单文件接口
*/
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 AppPackage {
manifest: AppManifest
files: Map<string, Blob | string> // 文件路径到内容的映射
signature?: string // 数字签名
checksum: string // 校验和
}
/**
* 应用启动选项
*/
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 eventService: EventCommunicationService
private sandboxEngine: ApplicationSandboxEngine
constructor(
windowService: WindowService,
resourceService: ResourceService,
eventService: EventCommunicationService,
sandboxEngine: ApplicationSandboxEngine,
) {
this.windowService = windowService
this.resourceService = resourceService
this.eventService = eventService
this.sandboxEngine = sandboxEngine
this.setupEventListeners()
this.loadInstalledApps()
// 外部应用发现已由 SystemServiceIntegration 统一管理,无需重复初始化
}
/**
* 安装应用
*/
async installApp(appPackage: AppPackage): Promise<string> {
const { manifest, files, checksum } = appPackage
const appId = manifest.id
try {
// 检查应用是否已安装
if (this.installedApps.has(appId)) {
throw new Error(`应用 ${appId} 已安装`)
}
// 验证清单文件
this.validateManifest(manifest)
// 验证校验和
if (!this.verifyChecksum(files, checksum)) {
throw new Error('应用包校验失败')
}
// 检查权限
await this.checkPermissions(manifest.permissions)
const now = new Date()
const appInstance: AppInstance = {
id: appId,
manifest,
state: AppLifecycleState.INSTALLING,
processId: '',
installedAt: now,
errorCount: 0,
crashCount: 0,
memoryUsage: 0,
cpuUsage: 0,
version: manifest.version,
autoStart: false,
persistent: manifest.background?.persistent || false,
}
// 更新状态
this.updateAppState(appInstance, AppLifecycleState.INSTALLING)
this.installedApps.set(appId, appInstance)
// 存储应用文件
this.appFiles.set(appId, files)
// 保存到本地存储
await this.saveAppToStorage(appInstance)
// 更新状态为已安装
this.updateAppState(appInstance, AppLifecycleState.INSTALLED)
this.eventService.sendMessage('system', 'app-lifecycle', {
type: 'installed',
appId,
manifest,
})
console.log(`应用 ${manifest.name} (${appId}) 安装成功`)
return appId
} catch (error) {
// 清理安装失败的应用
this.installedApps.delete(appId)
this.appFiles.delete(appId)
console.error('应用安装失败:', error)
throw error
}
}
/**
* 卸载应用
*/
async uninstallApp(appId: string): Promise<boolean> {
const app = this.installedApps.get(appId)
if (!app) {
throw new Error(`应用 ${appId} 未安装`)
}
try {
// 如果应用正在运行,先停止
if (app.state === AppLifecycleState.RUNNING || app.state === AppLifecycleState.SUSPENDED) {
await this.stopApp(appId)
}
this.updateAppState(app, AppLifecycleState.UNINSTALLING)
// 清理应用数据
await this.resourceService.clearStorage(appId)
await this.resourceService.revokeAllPermissions(appId)
// 删除应用文件
this.appFiles.delete(appId)
// 从存储中删除
await this.removeAppFromStorage(appId)
// 从已安装列表中移除
this.installedApps.delete(appId)
this.eventService.sendMessage('system', 'app-lifecycle', {
type: 'uninstalled',
appId,
})
console.log(`应用 ${appId} 卸载成功`)
return true
} catch (error) {
console.error('应用卸载失败:', error)
throw error
}
}
/**
* 启动应用
*/
async startApp(appId: string, options: AppStartOptions = {}): Promise<string> {
let app = this.installedApps.get(appId)
// 如果应用未安装,检查是否为外置应用
let isExternalApp = false
if (!app) {
const externalApp = externalAppDiscovery.getApp(appId)
if (externalApp) {
console.log(`[LifecycleManager] 发现外置应用 ${appId}`)
isExternalApp = true
// 为外部应用创建临时实例
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,
persistent: false,
}
}
}
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)
// 检查是否为内置应用
let isBuiltInApp = false
try {
const { AppRegistry } = await import('../apps/AppRegistry')
const appRegistry = AppRegistry.getInstance()
isBuiltInApp = appRegistry.hasApp(appId)
} catch (error) {
console.warn('无法导入 AppRegistry')
}
// 检查是否为外置应用(仅当不是内置应用时)
// 修复移除重复的变量声明使用已声明的isExternalApp变量
if (!isBuiltInApp && !isExternalApp) {
isExternalApp = externalAppDiscovery.hasApp(appId)
}
// 创建窗体(如果不是后台应用)
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,
maxHeight: app.manifest.window?.maxHeight,
}
const windowInstance = await this.windowService.createWindow(appId, windowConfig)
windowId = windowInstance.id
app.windowId = windowId
// 对于内置应用,需要在窗口内容区域挂载 AppRenderer 组件
if (isBuiltInApp) {
await this.mountBuiltInApp(appId, windowInstance)
}
// 对于内置应用不需要等待窗口DOM元素渲染
if (!isBuiltInApp) {
// 稍等片刻确保窗口DOM元素已经渲染完成
await new Promise((resolve) => setTimeout(resolve, 100))
}
}
// 对于外置应用,需要创建沙箱;内置应用跳过沙箱
if (isExternalApp && !isBuiltInApp) {
// 为外置应用创建沙箱
const sandboxConfig = {
securityLevel: 2, // HIGH
allowScripts: true,
allowSameOrigin: false, // 安全考虑:不允许同源访问以防止沙箱逃逸
allowForms: true,
networkTimeout: 15000, // 增加超时时间到15秒
csp:
app.manifest.contentSecurity?.policy ||
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self';",
}
const sandbox = await this.sandboxEngine.createSandbox(
appId,
windowId || 'background',
sandboxConfig,
)
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> {
// 首先从已安装应用中查找
let app = this.installedApps.get(appId)
// 如果未找到,从运行进程列表中查找(可能是外部应用的临时实例)
if (!app) {
for (const runningApp of this.runningProcesses.values()) {
if (runningApp.id === appId) {
app = runningApp
break
}
}
}
if (!app) {
throw new Error(`应用 ${appId} 未安装或未运行`)
}
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
}
}
/**
* 暂停应用
*/
async suspendApp(appId: string): Promise<boolean> {
// 首先从已安装应用中查找
let app = this.installedApps.get(appId)
// 如果未找到,从运行进程列表中查找(可能是外部应用的临时实例)
if (!app) {
for (const runningApp of this.runningProcesses.values()) {
if (runningApp.id === appId) {
app = runningApp
break
}
}
}
if (!app || app.state !== AppLifecycleState.RUNNING) {
return false
}
try {
// 暂停沙箱
if (app.sandboxId) {
this.sandboxEngine.suspendSandbox(app.sandboxId)
}
// 最小化窗体
if (app.windowId) {
this.windowService.minimizeWindow(app.windowId)
}
this.updateAppState(app, AppLifecycleState.SUSPENDED)
// 注意状态变更消息由updateAppState方法自动发送不需要手动发送
console.log(`应用 ${appId} 已暂停`)
return true
} catch (error) {
console.error('应用暂停失败:', error)
return false
}
}
/**
* 恢复应用
*/
async resumeApp(appId: string): Promise<boolean> {
// 首先从已安装应用中查找
let app = this.installedApps.get(appId)
// 如果未找到,从运行进程列表中查找(可能是外部应用的临时实例)
if (!app) {
for (const runningApp of this.runningProcesses.values()) {
if (runningApp.id === appId) {
app = runningApp
break
}
}
}
if (!app || app.state !== AppLifecycleState.SUSPENDED) {
return false
}
try {
// 恢复沙箱
if (app.sandboxId) {
this.sandboxEngine.resumeSandbox(app.sandboxId)
}
// 恢复窗体
if (app.windowId) {
this.windowService.restoreWindow(app.windowId)
}
app.lastActiveAt = new Date()
this.updateAppState(app, AppLifecycleState.RUNNING)
// 注意状态变更消息由updateAppState方法自动发送不需要手动发送
console.log(`应用 ${appId} 已恢复`)
return true
} catch (error) {
console.error('应用恢复失败:', error)
return false
}
}
/**
* 重启应用
*/
async restartApp(appId: string, options?: AppStartOptions): Promise<string> {
await this.stopApp(appId)
// 等待一小段时间确保完全停止
await new Promise((resolve) => setTimeout(resolve, 1000))
return this.startApp(appId, options)
}
/**
* 获取应用信息
*/
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 {
// 首先从已安装应用中查找
let app = this.installedApps.get(appId)
// 如果未找到,从运行进程列表中查找(可能是外部应用的临时实例)
if (!app) {
for (const runningApp of this.runningProcesses.values()) {
if (runningApp.id === appId) {
app = runningApp
break
}
}
}
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,
uptime: app.startedAt ? Date.now() - app.startedAt.getTime() : 0,
}
}
// 私有方法
/**
* 为内置应用挂载 AppRenderer 组件
*/
private async mountBuiltInApp(appId: string, windowInstance: any): Promise<void> {
try {
// 动态导入 Vue 和 AppRenderer
const { createApp } = await import('vue')
const AppRenderer = (await import('../ui/components/AppRenderer.vue')).default
console.log(`[LifecycleManager] 为内置应用 ${appId} 创建 AppRenderer 组件`)
const app = createApp({
components: { AppRenderer },
template: `<AppRenderer :app-id="'${appId}'" :window-id="'${windowInstance.id}'"/>`,
})
// 提供系统服务(使用当前实例所在的系统服务)
app.provide('systemService', {
getWindowService: () => this.windowService,
getResourceService: () => this.resourceService,
getEventService: () => this.eventService,
getSandboxEngine: () => this.sandboxEngine,
getLifecycleManager: () => this,
})
// 挂载到窗口内容区域
const contentArea = windowInstance.element?.querySelector('.window-content')
if (contentArea) {
app.mount(contentArea)
console.log(`[LifecycleManager] AppRenderer 组件已挂载到窗口 ${windowInstance.id}`)
} else {
throw new Error('未找到窗口内容区域')
}
} catch (error) {
console.error(`内置应用 ${appId} 挂载失败:`, error)
throw error
}
}
/**
* 验证应用清单文件
*/
private validateManifest(manifest: AppManifest): void {
const required = ['id', 'name', 'version', 'entryPoint']
for (const field of required) {
if (!manifest[field as keyof AppManifest]) {
throw new Error(`清单文件缺少必需字段: ${field}`)
}
}
// 验证版本格式
if (!/^\d+\.\d+\.\d+/.test(manifest.version)) {
throw new Error('版本号格式不正确,应为 x.y.z 格式')
}
// 验证应用ID格式
if (!/^[a-zA-Z0-9._-]+$/.test(manifest.id)) {
throw new Error('应用ID格式不正确')
}
}
/**
* 验证校验和
*/
private verifyChecksum(files: Map<string, Blob | string>, expectedChecksum: string): boolean {
// 简化实现,实际应用中应使用更强的哈希算法
let content = ''
for (const [path, data] of files.entries()) {
content += path + (typeof data === 'string' ? data : data.size)
}
const actualChecksum = this.safeBase64Encode(content).slice(0, 32)
return actualChecksum === expectedChecksum
}
/**
* 安全的 Base64 编码,支持 Unicode 字符
*/
private safeBase64Encode(str: string): string {
try {
// 使用 encodeURIComponent + atob 来处理 Unicode 字符
return btoa(
encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function toSolidBytes(match, p1) {
return String.fromCharCode(parseInt(p1, 16))
}),
)
} catch (error) {
// 如果还是失败,使用简单的哈希算法
let hash = 0
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i)
hash = (hash << 5) - hash + char
hash = hash & hash // 转换为32位整数
}
return Math.abs(hash).toString(36)
}
}
/**
* 检查权限
*/
private async checkPermissions(permissions: string[]): Promise<void> {
for (const permission of permissions) {
// 这里可以添加权限检查逻辑
// 目前简单允许所有权限
console.log(`检查权限: ${permission}`)
}
}
/**
* 在沙箱中加载应用
*/
private async loadAppInSandbox(app: AppInstance, sandboxId: string): Promise<void> {
const appFiles = this.appFiles.get(app.id)
if (!appFiles) {
throw new Error('应用文件不存在')
}
const entryFile = appFiles.get(app.manifest.entryPoint)
if (!entryFile) {
throw new Error('入口文件不存在')
}
// 创建应用URL
const entryUrl = this.createAppUrl(app.id, app.manifest.entryPoint, entryFile)
// 在沙箱中加载应用
await this.sandboxEngine.loadApplication(sandboxId, entryUrl)
}
/**
* 创建应用文件URL
*/
private createAppUrl(appId: string, filePath: string, content: Blob | string): string {
let blob: Blob
if (typeof content === 'string') {
// 确保使用UTF-8编码创建Blob
const contentType = this.getContentType(filePath)
const utf8ContentType = contentType.includes('charset')
? contentType
: `${contentType}; charset=utf-8`
blob = new Blob([content], { type: utf8ContentType })
} else {
blob = content
}
return URL.createObjectURL(blob)
}
/**
* 获取文件内容类型
*/
private getContentType(filePath: string): string {
const ext = filePath.split('.').pop()?.toLowerCase()
switch (ext) {
case 'html':
return 'text/html; charset=utf-8'
case 'js':
return 'application/javascript; charset=utf-8'
case 'css':
return 'text/css; charset=utf-8'
case 'json':
return 'application/json; charset=utf-8'
case 'png':
return 'image/png'
case 'jpg':
case 'jpeg':
return 'image/jpeg'
case 'svg':
return 'image/svg+xml; charset=utf-8'
default:
return 'text/plain; charset=utf-8'
}
}
/**
* 保存应用到存储
*/
private async saveAppToStorage(app: AppInstance): Promise<void> {
const appData = {
id: app.id,
manifest: app.manifest,
installedAt: app.installedAt.toISOString(),
version: app.version,
autoStart: app.autoStart,
persistent: app.persistent,
}
await this.resourceService.setStorage('system', `apps.${app.id}`, appData)
}
/**
* 从存储中删除应用
*/
private async removeAppFromStorage(appId: string): Promise<void> {
await this.resourceService.removeStorage('system', `apps.${appId}`)
}
/**
* 初始化外置应用发现(已由 SystemServiceIntegration 统一管理)
* 这个方法保留用于未来可能的扩展,但不再重复启动发现服务
*/
private async initializeExternalAppDiscovery(): Promise<void> {
try {
console.log('[LifecycleManager] 外置应用发现服务已由系统服务集成统一管理')
// 可以在这里添加应用生命周期管理器特有的外置应用监听逻辑
// 例如监听外置应用的注册/卸载事件
} catch (error) {
console.error('[LifecycleManager] 初始化外置应用监听失败:', error)
}
}
// 已移除:外部应用不再需要注册到 installedApps 中
// 外部应用在启动时会创建临时实例
/**
* 为外置应用加载代码到沙箱
*/
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,
isExternal: true,
}
apps.push(appInstance)
}
}
return apps
}
/**
* 刷新外置应用列表
*/
async refreshExternalApps(): Promise<void> {
try {
await externalAppDiscovery.refresh()
console.log('[LifecycleManager] 外置应用列表已刷新')
} catch (error) {
console.error('[LifecycleManager] 刷新外置应用列表失败:', error)
}
}
/**
* 加载已安装的应用
*/
private async loadInstalledApps(): Promise<void> {
try {
// 从存储中加载应用列表
const appsData = (await this.resourceService.getStorage('system', 'apps')) || {}
for (const [appId, appData] of Object.entries(appsData as Record<string, any>)) {
if (appData && typeof appData === 'object') {
const app: AppInstance = {
id: appId,
manifest: appData.manifest,
state: AppLifecycleState.STOPPED,
processId: '',
installedAt: new Date(appData.installedAt),
errorCount: 0,
crashCount: 0,
memoryUsage: 0,
cpuUsage: 0,
version: appData.version,
autoStart: appData.autoStart || false,
persistent: appData.persistent || false,
}
this.updateAppState(app, AppLifecycleState.INSTALLED)
this.installedApps.set(appId, app)
}
}
console.log(`已加载 ${this.installedApps.size} 个已安装应用`)
} catch (error) {
console.error('加载已安装应用失败:', error)
}
}
/**
* 设置事件监听器
*/
private setupEventListeners(): void {
// 监听沙箱状态变化
this.eventService.subscribe('system', 'sandbox-state-change', (message) => {
const { sandboxId, newState } = message.payload
// 查找对应的应用
for (const app of this.installedApps.values()) {
if (app.sandboxId === sandboxId) {
if (newState === 'error') {
this.handleAppError(app.id, new Error('沙箱错误'))
} else if (newState === 'destroyed') {
this.handleAppCrash(app.id, '沙箱被销毁')
}
break
}
}
})
// 监听性能告警
this.eventService.subscribe('system', 'performance-alert', (message) => {
const { sandboxId, type, usage, limit } = message.payload
for (const app of this.installedApps.values()) {
if (app.sandboxId === sandboxId) {
if (type === 'memory') {
app.memoryUsage = usage
} else if (type === 'cpu') {
app.cpuUsage = usage
}
console.warn(`应用 ${app.id} ${type} 使用量 ${usage} 超过限制 ${limit}`)
break
}
}
})
}
/**
* 处理应用错误
*/
private handleAppError(appId: string, error: Error): void {
const app = this.installedApps.get(appId)
if (!app) return
app.errorCount++
this.eventService.sendMessage('system', 'app-lifecycle', {
type: 'error',
appId,
error: error.message,
})
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
this.eventService.sendMessage('system', 'app-lifecycle', {
type: 'stateChanged',
appId: app.id,
newState,
oldState,
})
}
}