Files
vue-desktop/src/services/ApplicationSandboxEngine.ts
2025-09-24 16:43:10 +08:00

1273 lines
36 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, ref, nextTick } from 'vue'
import type { ResourceService } from './ResourceService'
import type { EventCommunicationService } from './EventCommunicationService'
import { v4 as uuidv4 } from 'uuid'
/**
* 沙箱状态枚举
*/
export enum SandboxState {
INITIALIZING = 'initializing',
READY = 'ready',
RUNNING = 'running',
SUSPENDED = 'suspended',
ERROR = 'error',
DESTROYED = 'destroyed'
}
/**
* 沙箱类型枚举
*/
export enum SandboxType {
IFRAME = 'iframe',
WEBWORKER = 'webworker',
SHADOW_DOM = 'shadowdom'
}
/**
* 沙箱安全级别
*/
export enum SecurityLevel {
LOW = 0,
MEDIUM = 1,
HIGH = 2,
STRICT = 3
}
/**
* 沙箱配置接口
*/
export interface SandboxConfig {
type: SandboxType
securityLevel: SecurityLevel
allowScripts: boolean
allowSameOrigin: boolean
allowForms: boolean
allowPopups: boolean
allowModals: boolean
allowPointerLock: boolean
allowPresentation: boolean
allowTopNavigation: boolean
maxMemoryUsage: number // MB
maxCpuUsage: number // 百分比
networkTimeout: number // 网络请求超时时间(ms)
csp: string // 内容安全策略
}
/**
* 沙箱实例接口
*/
export interface SandboxInstance {
id: string
appId: string
windowId: string
config: SandboxConfig
state: SandboxState
container: HTMLElement | null
iframe?: HTMLIFrameElement
worker?: Worker
shadowRoot?: ShadowRoot
createdAt: Date
lastActiveAt: Date
memoryUsage: number
cpuUsage: number
networkRequests: number
errors: string[]
}
/**
* 沙箱性能监控数据
*/
export interface SandboxPerformance {
sandboxId: string
timestamp: Date
memoryUsage: number
cpuUsage: number
networkRequests: number
renderTime: number
jsExecutionTime: number
}
/**
* 沙箱事件接口
*/
export interface SandboxEvents {
onStateChange: (sandboxId: string, newState: SandboxState, oldState: SandboxState) => void
onError: (sandboxId: string, error: Error) => void
onPerformanceAlert: (sandboxId: string, metrics: SandboxPerformance) => void
onResourceLimit: (sandboxId: string, resourceType: string, usage: number, limit: number) => void
}
/**
* 应用沙箱引擎类
*/
export class ApplicationSandboxEngine {
private sandboxes = reactive(new Map<string, SandboxInstance>())
private performanceData = reactive(new Map<string, SandboxPerformance[]>())
private monitoringInterval: number | null = null
private resourceService: ResourceService
private eventService: EventCommunicationService
constructor(
resourceService: ResourceService,
eventService: EventCommunicationService
) {
this.resourceService = resourceService
this.eventService = eventService
this.startPerformanceMonitoring()
}
/**
* 创建沙箱实例
*/
async createSandbox(
appId: string,
windowId: string,
config: Partial<SandboxConfig> = {}
): Promise<SandboxInstance> {
const sandboxId = uuidv4()
const defaultConfig: SandboxConfig = {
type: SandboxType.IFRAME,
securityLevel: SecurityLevel.HIGH,
allowScripts: true,
allowSameOrigin: false,
allowForms: true,
allowPopups: false,
allowModals: false,
allowPointerLock: false,
allowPresentation: false,
allowTopNavigation: false,
maxMemoryUsage: 100, // 100MB
maxCpuUsage: 30, // 30%
networkTimeout: 10000, // 10秒
csp: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self';"
}
const finalConfig = { ...defaultConfig, ...config }
const now = new Date()
const sandbox: SandboxInstance = {
id: sandboxId,
appId,
windowId,
config: finalConfig,
state: SandboxState.INITIALIZING,
container: null,
createdAt: now,
lastActiveAt: now,
memoryUsage: 0,
cpuUsage: 0,
networkRequests: 0,
errors: []
}
try {
// 根据类型创建沙箱容器
await this.createSandboxContainer(sandbox)
// 设置安全策略
this.applySecurity(sandbox)
// 设置性能监控
this.setupPerformanceMonitoring(sandbox)
// 更新状态
this.updateSandboxState(sandbox, SandboxState.READY)
this.sandboxes.set(sandboxId, sandbox)
console.log(`沙箱 ${sandboxId} 创建成功`)
return sandbox
} catch (error) {
this.updateSandboxState(sandbox, SandboxState.ERROR)
sandbox.errors.push(error instanceof Error ? error.message : String(error))
throw error
}
}
/**
* 加载应用到沙箱
*/
async loadApplication(sandboxId: string, applicationUrl: string): Promise<boolean> {
const sandbox = this.sandboxes.get(sandboxId)
if (!sandbox) {
throw new Error(`沙箱 ${sandboxId} 不存在`)
}
try {
console.log(`开始加载应用: ${sandbox.appId}, 沙箱ID: ${sandboxId}`)
this.updateSandboxState(sandbox, SandboxState.RUNNING)
if (sandbox.config.type === SandboxType.IFRAME && sandbox.iframe) {
console.log(`使用iframe加载应用: ${applicationUrl}`)
// 检查iframe是否已挂载到DOM
if (!document.contains(sandbox.iframe)) {
console.warn('检测到iframe未挂载到DOM尝试重新挂载')
await this.mountIframeToWindow(sandbox)
}
// 设置iframe源
sandbox.iframe.src = applicationUrl
// 等待加载完成
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
console.error(`应用加载超时: ${sandbox.appId}, URL: ${applicationUrl}, 超时时间: ${sandbox.config.networkTimeout}ms`)
reject(new Error('应用加载超时'))
}, sandbox.config.networkTimeout)
sandbox.iframe!.onload = () => {
console.log(`应用加载成功: ${sandbox.appId}`)
clearTimeout(timeoutId)
this.injectSDK(sandbox)
resolve(true)
}
sandbox.iframe!.onerror = (error) => {
console.error(`应用加载失败: ${sandbox.appId}`, error)
clearTimeout(timeoutId)
reject(new Error('应用加载失败'))
}
})
} else if (sandbox.config.type === SandboxType.WEBWORKER && sandbox.worker) {
// WebWorker方式加载
sandbox.worker.postMessage({
type: 'load',
url: applicationUrl
})
return true
}
return false
} catch (error) {
console.error(`加载应用失败: ${sandbox.appId}`, error)
this.updateSandboxState(sandbox, SandboxState.ERROR)
sandbox.errors.push(error instanceof Error ? error.message : String(error))
throw error
}
}
/**
* 暂停沙箱
*/
suspendSandbox(sandboxId: string): boolean {
const sandbox = this.sandboxes.get(sandboxId)
if (!sandbox || sandbox.state !== SandboxState.RUNNING) {
return false
}
try {
this.updateSandboxState(sandbox, SandboxState.SUSPENDED)
if (sandbox.iframe) {
// 暂停iframe中的脚本执行
const iframeWindow = sandbox.iframe.contentWindow
if (iframeWindow) {
// 发送暂停事件到应用
iframeWindow.postMessage({ type: 'system:suspend' }, '*')
}
}
console.log(`沙箱 ${sandboxId} 已暂停`)
return true
} catch (error) {
console.error('暂停沙箱失败:', error)
return false
}
}
/**
* 恢复沙箱
*/
resumeSandbox(sandboxId: string): boolean {
const sandbox = this.sandboxes.get(sandboxId)
if (!sandbox || sandbox.state !== SandboxState.SUSPENDED) {
return false
}
try {
this.updateSandboxState(sandbox, SandboxState.RUNNING)
sandbox.lastActiveAt = new Date()
if (sandbox.iframe) {
const iframeWindow = sandbox.iframe.contentWindow
if (iframeWindow) {
// 发送恢复事件到应用
iframeWindow.postMessage({ type: 'system:resume' }, '*')
}
}
console.log(`沙箱 ${sandboxId} 已恢复`)
return true
} catch (error) {
console.error('恢复沙箱失败:', error)
return false
}
}
/**
* 销毁沙箱
*/
destroySandbox(sandboxId: string): boolean {
const sandbox = this.sandboxes.get(sandboxId)
if (!sandbox) {
return false
}
try {
this.updateSandboxState(sandbox, SandboxState.DESTROYED)
// 清理DOM元素
if (sandbox.iframe) {
sandbox.iframe.remove()
}
if (sandbox.container) {
sandbox.container.remove()
}
// 终止WebWorker
if (sandbox.worker) {
sandbox.worker.terminate()
}
// 清理性能数据
this.performanceData.delete(sandboxId)
// 从集合中移除
this.sandboxes.delete(sandboxId)
console.log(`沙箱 ${sandboxId} 已销毁`)
return true
} catch (error) {
console.error('销毁沙箱失败:', error)
return false
}
}
/**
* 获取沙箱实例
*/
getSandbox(sandboxId: string): SandboxInstance | undefined {
return this.sandboxes.get(sandboxId)
}
/**
* 获取应用的所有沙箱
*/
getAppSandboxes(appId: string): SandboxInstance[] {
return Array.from(this.sandboxes.values()).filter(sandbox => sandbox.appId === appId)
}
/**
* 获取沙箱性能数据
*/
getPerformanceData(sandboxId: string): SandboxPerformance[] {
return this.performanceData.get(sandboxId) || []
}
/**
* 发送消息到沙箱
*/
sendMessage(sandboxId: string, message: any): boolean {
const sandbox = this.sandboxes.get(sandboxId)
if (!sandbox || sandbox.state !== SandboxState.RUNNING) {
return false
}
try {
if (sandbox.iframe) {
const iframeWindow = sandbox.iframe.contentWindow
if (iframeWindow) {
iframeWindow.postMessage(message, '*')
return true
}
} else if (sandbox.worker) {
sandbox.worker.postMessage(message)
return true
}
return false
} catch (error) {
console.error('发送消息到沙箱失败:', error)
return false
}
}
/**
* 清理所有沙箱
*/
cleanup(): void {
for (const sandboxId of this.sandboxes.keys()) {
this.destroySandbox(sandboxId)
}
}
/**
* 销毁引擎
*/
destroy(): void {
if (this.monitoringInterval) {
clearInterval(this.monitoringInterval)
this.monitoringInterval = null
}
this.cleanup()
console.log('沙箱引擎已销毁')
}
// 私有方法
/**
* 创建沙箱容器
*/
private async createSandboxContainer(sandbox: SandboxInstance): Promise<void> {
switch (sandbox.config.type) {
case SandboxType.IFRAME:
await this.createIframeSandbox(sandbox)
break
case SandboxType.WEBWORKER:
await this.createWorkerSandbox(sandbox)
break
case SandboxType.SHADOW_DOM:
await this.createShadowDOMSandbox(sandbox)
break
default:
throw new Error(`不支持的沙箱类型: ${sandbox.config.type}`)
}
}
/**
* 创建iframe沙箱
*/
private async createIframeSandbox(sandbox: SandboxInstance): Promise<void> {
const iframe = document.createElement('iframe')
iframe.id = `sandbox-${sandbox.id}`
// 设置sandbox属性
const sandboxAttributes: string[] = []
if (sandbox.config.allowScripts) sandboxAttributes.push('allow-scripts')
if (sandbox.config.allowSameOrigin) sandboxAttributes.push('allow-same-origin')
if (sandbox.config.allowForms) sandboxAttributes.push('allow-forms')
if (sandbox.config.allowPopups) sandboxAttributes.push('allow-popups')
if (sandbox.config.allowModals) sandboxAttributes.push('allow-modals')
if (sandbox.config.allowPointerLock) sandboxAttributes.push('allow-pointer-lock')
if (sandbox.config.allowPresentation) sandboxAttributes.push('allow-presentation')
if (sandbox.config.allowTopNavigation) sandboxAttributes.push('allow-top-navigation')
iframe.sandbox = sandboxAttributes.join(' ')
// 设置样式
iframe.style.cssText = `
width: 100%;
height: 100%;
border: none;
background: #fff;
`
// 设置CSP - 不使用iframe的csp属性而是在内容中设置
// if (sandbox.config.csp) {
// iframe.setAttribute('csp', sandbox.config.csp)
// }
sandbox.iframe = iframe
sandbox.container = iframe
// 将iframe挂载到对应的窗口内容区域
await this.mountIframeToWindow(sandbox)
}
/**
* 将iframe挂载到窗口内容区域
*/
private async mountIframeToWindow(sandbox: SandboxInstance): Promise<void> {
const windowElement = document.getElementById(`window-${sandbox.windowId}`)
if (!windowElement) {
// 如果是后台应用,创建隐藏容器
if (sandbox.windowId === 'background') {
const hiddenContainer = document.createElement('div')
hiddenContainer.id = 'background-apps-container'
hiddenContainer.style.cssText = `
position: fixed;
top: -9999px;
left: -9999px;
width: 1px;
height: 1px;
visibility: hidden;
`
document.body.appendChild(hiddenContainer)
hiddenContainer.appendChild(sandbox.iframe!)
return
}
throw new Error(`找不到窗口元素: window-${sandbox.windowId}`)
}
const contentArea = windowElement.querySelector('.window-content')
if (!contentArea) {
throw new Error(`找不到窗口内容区域: window-${sandbox.windowId}`)
}
// 替换窗口中的默认iframe
const existingIframe = contentArea.querySelector('iframe')
if (existingIframe) {
contentArea.removeChild(existingIframe)
}
contentArea.appendChild(sandbox.iframe!)
}
/**
* 创建WebWorker沙箱
*/
private async createWorkerSandbox(sandbox: SandboxInstance): Promise<void> {
// 创建Worker脚本
const workerScript = `
let appCode = null;
self.onmessage = function(e) {
const { type, data } = e.data;
switch (type) {
case 'load':
fetch(data.url)
.then(response => response.text())
.then(code => {
appCode = code;
self.postMessage({ type: 'loaded' });
})
.catch(error => {
self.postMessage({ type: 'error', error: error.message });
});
break;
case 'execute':
if (appCode) {
try {
eval(appCode);
self.postMessage({ type: 'executed' });
} catch (error) {
self.postMessage({ type: 'error', error: error.message });
}
}
break;
}
};
`
const blob = new Blob([workerScript], { type: 'application/javascript' })
const workerUrl = URL.createObjectURL(blob)
const worker = new Worker(workerUrl)
worker.onmessage = (e) => {
const { type, error } = e.data
if (type === 'error') {
sandbox.errors.push(error)
this.updateSandboxState(sandbox, SandboxState.ERROR)
}
}
worker.onerror = (error) => {
sandbox.errors.push(error.message)
this.updateSandboxState(sandbox, SandboxState.ERROR)
}
sandbox.worker = worker
URL.revokeObjectURL(workerUrl)
}
/**
* 创建Shadow DOM沙箱
*/
private async createShadowDOMSandbox(sandbox: SandboxInstance): Promise<void> {
const container = document.createElement('div')
container.id = `sandbox-${sandbox.id}`
const shadowRoot = container.attachShadow({ mode: 'closed' })
// 添加样式隔离
const style = document.createElement('style')
style.textContent = `
:host {
width: 100%;
height: 100%;
display: block;
overflow: hidden;
}
`
shadowRoot.appendChild(style)
sandbox.container = container
sandbox.shadowRoot = shadowRoot
}
/**
* 应用安全策略
*/
private applySecurity(sandbox: SandboxInstance): void {
if (sandbox.iframe) {
// 设置安全头
const securityHeaders = {
'X-Frame-Options': 'DENY',
'X-Content-Type-Options': 'nosniff',
'X-XSS-Protection': '1; mode=block',
'Referrer-Policy': 'no-referrer'
}
// 这些头部主要用于服务器端设置,在客户端我们通过其他方式实现
// 监听iframe的消息事件
window.addEventListener('message', (event) => {
if (event.source === sandbox.iframe!.contentWindow) {
this.handleSandboxMessage(sandbox, event.data)
}
})
// 简化安全限制主要依赖iframe的sandbox属性
sandbox.iframe.addEventListener('load', () => {
const iframeDoc = sandbox.iframe!.contentDocument
if (iframeDoc) {
// 添加基本的安全提示脚本
const script = iframeDoc.createElement('script')
script.textContent = `
// 标记应用在沙箱中运行
window.__SANDBOXED__ = true;
// 禁用一些显而易见的危险API
if (typeof window.open !== 'undefined') {
window.open = function() {
console.warn('沙箱应用不允许打开新窗口');
return null;
};
}
console.log('应用已在安全沙箱中加载');
`
iframeDoc.head.appendChild(script)
}
})
}
}
/**
* 处理沙箱消息
*/
private handleSandboxMessage(sandbox: SandboxInstance, message: any): void {
if (typeof message !== 'object' || !message.type) {
return
}
switch (message.type) {
case 'app:ready':
sandbox.lastActiveAt = new Date()
break
case 'app:error':
sandbox.errors.push(message.error || '未知错误')
break
case 'app:resource-request':
this.handleResourceRequest(sandbox, message.data)
break
case 'app:performance':
this.recordPerformance(sandbox, message.data)
break
}
}
/**
* 处理资源请求
*/
private async handleResourceRequest(sandbox: SandboxInstance, request: any): Promise<void> {
const { type, data } = request
try {
let result = null
switch (type) {
case 'storage':
if (data.action === 'get') {
result = await this.resourceService.getStorage(sandbox.appId, data.key)
} else if (data.action === 'set') {
result = await this.resourceService.setStorage(sandbox.appId, data.key, data.value)
}
break
case 'network':
result = await this.resourceService.makeNetworkRequest(sandbox.appId, data.url, data.options)
break
}
// 发送结果回沙箱
this.sendMessage(sandbox.id, {
type: 'system:resource-response',
requestId: request.id,
result
})
} catch (error) {
this.sendMessage(sandbox.id, {
type: 'system:resource-error',
requestId: request.id,
error: error instanceof Error ? error.message : String(error)
})
}
}
/**
* 注入SDK
*/
private injectSDK(sandbox: SandboxInstance): void {
if (!sandbox.iframe) return
const iframeDoc = sandbox.iframe.contentDocument
if (!iframeDoc) return
// 确保正确的字符编码
const existingCharset = iframeDoc.querySelector('meta[charset]')
if (!existingCharset) {
const charsetMeta = iframeDoc.createElement('meta')
charsetMeta.setAttribute('charset', 'UTF-8')
iframeDoc.head.insertBefore(charsetMeta, iframeDoc.head.firstChild)
}
// 添加正确的CSP meta标签
const existingCSP = iframeDoc.querySelector('meta[http-equiv="Content-Security-Policy"]')
if (!existingCSP && sandbox.config.csp) {
const cspMeta = iframeDoc.createElement('meta')
cspMeta.setAttribute('http-equiv', 'Content-Security-Policy')
cspMeta.setAttribute('content', sandbox.config.csp)
iframeDoc.head.appendChild(cspMeta)
}
const script = iframeDoc.createElement('script')
script.textContent = `
// 系统SDK注入 - 完整版本
(function() {
console.log('[SystemSDK] 开始注入SDK到iframe');
// SDK基础类
class SDKBase {
constructor() {
this._appId = '';
this._initialized = false;
}
get appId() {
return this._appId;
}
get initialized() {
return this._initialized;
}
// 发送消息到系统
sendToSystem(method, data) {
return new Promise((resolve, reject) => {
const requestId = Date.now().toString() + '_' + Math.random().toString(36).substr(2, 9);
const handler = (event) => {
if (event.data?.type === 'system:response' && event.data?.requestId === requestId) {
window.removeEventListener('message', handler);
if (event.data.success) {
resolve(event.data.data);
} else {
reject(new Error(event.data.error || '系统调用失败'));
}
}
};
window.addEventListener('message', handler);
// 发送消息到父窗口(系统)
window.parent.postMessage({
type: 'sdk:call',
requestId,
method,
data,
appId: this._appId,
}, '*');
// 设置超时
setTimeout(() => {
window.removeEventListener('message', handler);
reject(new Error('系统调用超时'));
}, 10000);
});
}
// 包装API响应
wrapResponse(promise) {
return promise
.then((data) => ({ success: true, data }))
.catch((error) => ({
success: false,
error: error.message || '未知错误',
code: error.code || -1,
}));
}
}
// 窗体SDK实现
class WindowSDKImpl extends SDKBase {
constructor(appId) {
super();
this._appId = appId;
}
async setTitle(title) {
return this.wrapResponse(this.sendToSystem('window.setTitle', { title }));
}
async resize(width, height) {
return this.wrapResponse(this.sendToSystem('window.resize', { width, height }));
}
async move(x, y) {
return this.wrapResponse(this.sendToSystem('window.move', { x, y }));
}
async minimize() {
return this.wrapResponse(this.sendToSystem('window.minimize'));
}
async maximize() {
return this.wrapResponse(this.sendToSystem('window.maximize'));
}
async restore() {
return this.wrapResponse(this.sendToSystem('window.restore'));
}
async close() {
return this.wrapResponse(this.sendToSystem('window.close'));
}
async getState() {
return this.wrapResponse(this.sendToSystem('window.getState'));
}
async getSize() {
return this.wrapResponse(this.sendToSystem('window.getSize'));
}
}
// 存储SDK实现
class StorageSDKImpl extends SDKBase {
constructor(appId) {
super();
this._appId = appId;
}
async set(key, value) {
return this.wrapResponse(this.sendToSystem('storage.set', { key, value }));
}
async get(key) {
return this.wrapResponse(this.sendToSystem('storage.get', { key }));
}
async remove(key) {
return this.wrapResponse(this.sendToSystem('storage.remove', { key }));
}
async clear() {
return this.wrapResponse(this.sendToSystem('storage.clear'));
}
async keys() {
return this.wrapResponse(this.sendToSystem('storage.keys'));
}
async has(key) {
return this.wrapResponse(this.sendToSystem('storage.has', { key }));
}
async getStats() {
return this.wrapResponse(this.sendToSystem('storage.getStats'));
}
}
// 网络SDK实现
class NetworkSDKImpl extends SDKBase {
constructor(appId) {
super();
this._appId = appId;
}
async request(url, config) {
return this.wrapResponse(this.sendToSystem('network.request', { url, config }));
}
async get(url, config) {
return this.request(url, { ...config, method: 'GET' });
}
async post(url, data, config) {
return this.request(url, { ...config, method: 'POST', body: data });
}
async put(url, data, config) {
return this.request(url, { ...config, method: 'PUT', body: data });
}
async delete(url, config) {
return this.request(url, { ...config, method: 'DELETE' });
}
}
// 事件SDK实现
class EventSDKImpl extends SDKBase {
constructor(appId) {
super();
this._appId = appId;
}
async emit(channel, data) {
return this.wrapResponse(this.sendToSystem('events.emit', { channel, data }));
}
async on(channel, callback, config) {
const result = await this.wrapResponse(this.sendToSystem('events.on', { channel, config }));
if (result.success && result.data) {
// 注册事件监听器
window.addEventListener('message', (event) => {
if (event.data?.type === 'system:event' && event.data?.subscriptionId === result.data) {
try {
callback(event.data.message);
} catch (error) {
console.error('事件回调处理错误:', error);
}
}
});
}
return result;
}
async off(subscriptionId) {
return this.wrapResponse(this.sendToSystem('events.off', { subscriptionId }));
}
async broadcast(channel, data) {
return this.wrapResponse(this.sendToSystem('events.broadcast', { channel, data }));
}
async sendTo(targetAppId, data) {
return this.wrapResponse(this.sendToSystem('events.sendTo', { targetAppId, data }));
}
}
// UI SDK实现
class UISDKImpl extends SDKBase {
constructor(appId) {
super();
this._appId = appId;
}
async showDialog(options) {
return this.wrapResponse(this.sendToSystem('ui.showDialog', options));
}
async showNotification(options) {
return this.wrapResponse(this.sendToSystem('ui.showNotification', options));
}
async showToast(message, type, duration) {
return this.wrapResponse(this.sendToSystem('ui.showToast', { message, type, duration }));
}
}
// 系统SDK实现
class SystemSDKImpl extends SDKBase {
constructor(appId) {
super();
this._appId = appId;
}
async getSystemInfo() {
return this.wrapResponse(this.sendToSystem('system.getSystemInfo'));
}
async getAppInfo() {
return this.wrapResponse(this.sendToSystem('system.getAppInfo'));
}
async getClipboard() {
return this.wrapResponse(this.sendToSystem('system.getClipboard'));
}
async setClipboard(text) {
return this.wrapResponse(this.sendToSystem('system.setClipboard', { text }));
}
async getCurrentTime() {
const result = await this.wrapResponse(this.sendToSystem('system.getCurrentTime'));
if (result.success && result.data) {
result.data = new Date(result.data);
}
return result;
}
async generateUUID() {
return this.wrapResponse(this.sendToSystem('system.generateUUID'));
}
}
// 主SDK实现类
class SystemDesktopSDKImpl {
constructor() {
this.version = '1.0.0';
this._appId = '';
this._initialized = false;
// 初始化各个子模块为null
this._window = null;
this._storage = null;
this._network = null;
this._events = null;
this._ui = null;
this._system = null;
}
get appId() {
return this._appId;
}
get initialized() {
return this._initialized;
}
get window() {
if (!this._initialized) {
console.warn('[SystemSDK] window模块未初始化');
throw new Error('SDK未初始化');
}
return this._window;
}
get storage() {
if (!this._initialized) {
console.warn('[SystemSDK] storage模块未初始化');
throw new Error('SDK未初始化');
}
return this._storage;
}
get network() {
if (!this._initialized) {
console.warn('[SystemSDK] network模块未初始化');
throw new Error('SDK未初始化');
}
return this._network;
}
get events() {
if (!this._initialized) {
console.warn('[SystemSDK] events模块未初始化');
throw new Error('SDK未初始化');
}
return this._events;
}
get ui() {
if (!this._initialized) {
console.warn('[SystemSDK] ui模块未初始化');
throw new Error('SDK未初始化');
}
return this._ui;
}
get system() {
if (!this._initialized) {
console.warn('[SystemSDK] system模块未初始化');
throw new Error('SDK未初始化');
}
return this._system;
}
async init(config) {
try {
console.log('[SystemSDK] 开始初始化SDK配置:', config);
if (this._initialized) {
console.warn('[SystemSDK] SDK已初始化');
return { success: false, error: 'SDK已初始化' };
}
this._appId = config.appId;
// 初始化各个子模块
this._window = new WindowSDKImpl(this._appId);
this._storage = new StorageSDKImpl(this._appId);
this._network = new NetworkSDKImpl(this._appId);
this._events = new EventSDKImpl(this._appId);
this._ui = new UISDKImpl(this._appId);
this._system = new SystemSDKImpl(this._appId);
this._initialized = true;
console.log('[SystemSDK] SDK初始化完成应用ID:', this._appId);
// 通知父窗口SDK已初始化
window.parent.postMessage({
type: 'sdk:initialized',
appId: this._appId
}, '*');
return { success: true, data: true };
} catch (error) {
console.error('[SystemSDK] 初始化失败:', error);
return {
success: false,
error: error instanceof Error ? error.message : '初始化失败',
};
}
}
async destroy() {
try {
if (!this._initialized) {
return { success: false, error: 'SDK未初始化' };
}
this._initialized = false;
this._appId = '';
console.log('[SystemSDK] SDK已销毁');
return { success: true, data: true };
} catch (error) {
console.error('[SystemSDK] 销毁失败:', error);
return {
success: false,
error: error instanceof Error ? error.message : '销毁失败',
};
}
}
}
// 创建全局SDK实例
const SystemSDK = new SystemDesktopSDKImpl();
// 在window对象上挂载SDK
window.SystemSDK = SystemSDK;
console.log('[SystemSDK] SDK已在iframe中注入并挂载到window对象');
// 通知系统应用已准备就绪
window.parent.postMessage({ type: 'app:ready' }, '*');
})();
`;
iframeDoc.head.appendChild(script)
}
/**
* 设置性能监控
*/
private setupPerformanceMonitoring(sandbox: SandboxInstance): void {
if (!this.performanceData.has(sandbox.id)) {
this.performanceData.set(sandbox.id, [])
}
}
/**
* 记录性能数据
*/
private recordPerformance(sandbox: SandboxInstance, data: any): void {
const performanceRecord: SandboxPerformance = {
sandboxId: sandbox.id,
timestamp: new Date(),
memoryUsage: data.memoryUsage || 0,
cpuUsage: data.cpuUsage || 0,
networkRequests: data.networkRequests || 0,
renderTime: data.renderTime || 0,
jsExecutionTime: data.jsExecutionTime || 0
}
const records = this.performanceData.get(sandbox.id)!
records.push(performanceRecord)
// 保留最近1000条记录
if (records.length > 1000) {
records.splice(0, records.length - 1000)
}
// 更新沙箱性能指标
sandbox.memoryUsage = performanceRecord.memoryUsage
sandbox.cpuUsage = performanceRecord.cpuUsage
sandbox.networkRequests = performanceRecord.networkRequests
// 检查性能阈值
this.checkPerformanceThresholds(sandbox, performanceRecord)
}
/**
* 检查性能阈值
*/
private checkPerformanceThresholds(sandbox: SandboxInstance, metrics: SandboxPerformance): void {
// 内存使用检查
if (metrics.memoryUsage > sandbox.config.maxMemoryUsage) {
this.eventService.sendMessage('system', 'performance-alert', {
sandboxId: sandbox.id,
type: 'memory',
usage: metrics.memoryUsage,
limit: sandbox.config.maxMemoryUsage
})
}
// CPU使用检查
if (metrics.cpuUsage > sandbox.config.maxCpuUsage) {
this.eventService.sendMessage('system', 'performance-alert', {
sandboxId: sandbox.id,
type: 'cpu',
usage: metrics.cpuUsage,
limit: sandbox.config.maxCpuUsage
})
}
}
/**
* 开始性能监控
*/
private startPerformanceMonitoring(): void {
this.monitoringInterval = setInterval(() => {
for (const sandbox of this.sandboxes.values()) {
if (sandbox.state === SandboxState.RUNNING) {
this.collectPerformanceMetrics(sandbox)
}
}
}, 5000) // 每5秒收集一次性能数据
}
/**
* 收集性能指标
*/
private collectPerformanceMetrics(sandbox: SandboxInstance): void {
if (sandbox.iframe && sandbox.iframe.contentWindow) {
// 请求性能数据
sandbox.iframe.contentWindow.postMessage({
type: 'system:performance-request'
}, '*')
}
}
/**
* 更新沙箱状态
*/
private updateSandboxState(sandbox: SandboxInstance, newState: SandboxState): void {
const oldState = sandbox.state
sandbox.state = newState
// 触发状态变化事件
this.eventService.sendMessage('system', 'sandbox-state-change', {
sandboxId: sandbox.id,
newState,
oldState
})
}
}