This commit is contained in:
2025-10-10 10:08:05 +08:00
parent ed0527bf27
commit 204dd4781b
6 changed files with 235 additions and 816 deletions

View File

@@ -20,7 +20,7 @@ export enum AppLifecycleState {
UNINSTALLING = 'uninstalling',
ERROR = 'error',
CRASHED = 'crashed',
AVAILABLE = 'available', // 外置应用可用但未注册状态
AVAILABLE = 'available' // 外置应用可用但未注册状态
}
/**
@@ -81,16 +81,6 @@ export interface AppInstance {
persistent: boolean
}
/**
* 应用安装包接口
*/
export interface AppPackage {
manifest: AppManifest
files: Map<string, Blob | string> // 文件路径到内容的映射
signature?: string // 数字签名
checksum: string // 校验和
}
/**
* 应用启动选项
*/
@@ -138,7 +128,7 @@ export class ApplicationLifecycleManager {
windowService: WindowService,
resourceService: ResourceService,
eventService: EventCommunicationService,
sandboxEngine: ApplicationSandboxEngine,
sandboxEngine: ApplicationSandboxEngine
) {
this.windowService = windowService
this.resourceService = resourceService
@@ -146,122 +136,6 @@ export class ApplicationLifecycleManager {
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
}
}
/**
@@ -270,6 +144,8 @@ export class ApplicationLifecycleManager {
async startApp(appId: string, options: AppStartOptions = {}): Promise<string> {
let app = this.installedApps.get(appId)
console.log('-----------------------------')
// 如果应用未安装,检查是否为外置应用
let isExternalApp = false
if (!app) {
@@ -277,7 +153,7 @@ export class ApplicationLifecycleManager {
if (externalApp) {
console.log(`[LifecycleManager] 发现外置应用 ${appId}`)
isExternalApp = true
// 为外部应用创建临时实例
const now = new Date()
app = {
@@ -292,7 +168,7 @@ export class ApplicationLifecycleManager {
cpuUsage: 0,
version: externalApp.manifest.version,
autoStart: false,
persistent: false,
persistent: false
}
}
}
@@ -312,21 +188,7 @@ export class ApplicationLifecycleManager {
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 isBuiltInApp = true
// 创建窗体(如果不是后台应用)
let windowId: string | undefined
@@ -341,23 +203,12 @@ export class ApplicationLifecycleManager {
minWidth: app.manifest.window?.minWidth,
minHeight: app.manifest.window?.minHeight,
maxWidth: app.manifest.window?.maxWidth,
maxHeight: app.manifest.window?.maxHeight,
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))
}
}
// 对于外置应用,需要创建沙箱;内置应用跳过沙箱
@@ -371,13 +222,13 @@ export class ApplicationLifecycleManager {
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';",
"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,
sandboxConfig
)
app.sandboxId = sandbox.id
@@ -417,7 +268,7 @@ export class ApplicationLifecycleManager {
async stopApp(appId: string): Promise<boolean> {
// 首先从已安装应用中查找
let app = this.installedApps.get(appId)
// 如果未找到,从运行进程列表中查找(可能是外部应用的临时实例)
if (!app) {
for (const runningApp of this.runningProcesses.values()) {
@@ -427,7 +278,7 @@ export class ApplicationLifecycleManager {
}
}
}
if (!app) {
throw new Error(`应用 ${appId} 未安装或未运行`)
}
@@ -474,105 +325,6 @@ export class ApplicationLifecycleManager {
}
}
/**
* 暂停应用
*/
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)
}
/**
* 获取应用信息
*/
@@ -600,7 +352,7 @@ export class ApplicationLifecycleManager {
isAppRunning(appId: string): boolean {
// 首先从已安装应用中查找
let app = this.installedApps.get(appId)
// 如果未找到,从运行进程列表中查找(可能是外部应用的临时实例)
if (!app) {
for (const runningApp of this.runningProcesses.values()) {
@@ -610,7 +362,7 @@ export class ApplicationLifecycleManager {
}
}
}
return app?.state === AppLifecycleState.RUNNING || app?.state === AppLifecycleState.SUSPENDED
}
@@ -629,7 +381,7 @@ export class ApplicationLifecycleManager {
cpuUsage: app.cpuUsage,
startedAt: app.startedAt,
lastActiveAt: app.lastActiveAt,
uptime: app.startedAt ? Date.now() - app.startedAt.getTime() : 0,
uptime: app.startedAt ? Date.now() - app.startedAt.getTime() : 0
}
}
@@ -646,9 +398,11 @@ export class ApplicationLifecycleManager {
console.log(`[LifecycleManager] 为内置应用 ${appId} 创建 AppRenderer 组件`)
console.log('----------------------------------')
const app = createApp({
components: { AppRenderer },
template: `<AppRenderer :app-id="'${appId}'" :window-id="'${windowInstance.id}'"/>`,
template: `<AppRenderer :app-id="'${appId}'" :window-id="'${windowInstance.id}'"/>`
})
// 提供系统服务(使用当前实例所在的系统服务)
@@ -657,7 +411,7 @@ export class ApplicationLifecycleManager {
getResourceService: () => this.resourceService,
getEventService: () => this.eventService,
getSandboxEngine: () => this.sandboxEngine,
getLifecycleManager: () => this,
getLifecycleManager: () => this
})
// 挂载到窗口内容区域
@@ -674,66 +428,6 @@ export class ApplicationLifecycleManager {
}
}
/**
* 验证应用清单文件
*/
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)
}
}
/**
* 检查权限
*/
@@ -745,115 +439,6 @@ export class ApplicationLifecycleManager {
}
}
/**
* 在沙箱中加载应用
*/
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 中
// 外部应用在启动时会创建临时实例
/**
* 为外置应用加载代码到沙箱
*/
@@ -904,7 +489,7 @@ export class ApplicationLifecycleManager {
version: externalApp.manifest.version,
autoStart: false,
persistent: false,
isExternal: true,
isExternal: true
}
apps.push(appInstance)
}
@@ -925,42 +510,6 @@ export class ApplicationLifecycleManager {
}
}
/**
* 加载已安装的应用
*/
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)
}
}
/**
* 设置事件监听器
*/
@@ -981,24 +530,6 @@ export class ApplicationLifecycleManager {
}
}
})
// 监听性能告警
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
}
}
})
}
/**
@@ -1013,7 +544,7 @@ export class ApplicationLifecycleManager {
this.eventService.sendMessage('system', 'app-lifecycle', {
type: 'error',
appId,
error: error.message,
error: error.message
})
console.error(`应用 ${appId} 发生错误:`, error)
@@ -1050,7 +581,7 @@ export class ApplicationLifecycleManager {
type: 'stateChanged',
appId: app.id,
newState,
oldState,
oldState
})
}
}