Files
vue-desktop/src/services/ApplicationSandboxEngine.ts

1208 lines
34 KiB
TypeScript
Raw Normal View History

2025-09-25 15:31:11 +08:00
import { reactive } from 'vue'
2025-09-24 16:43:10 +08:00
import type { ResourceService } from './ResourceService'
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[]
2025-09-25 15:31:11 +08:00
messageHandler?: (event: MessageEvent) => void
2025-09-24 16:43:10 +08:00
}
/**
*
*/
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
2025-10-11 12:10:35 +08:00
constructor(resourceService: ResourceService) {
2025-09-24 16:43:10 +08:00
this.resourceService = resourceService
this.startPerformanceMonitoring()
}
/**
*
*/
async createSandbox(
appId: string,
windowId: string,
config: Partial<SandboxConfig> = {}
): Promise<SandboxInstance> {
const sandboxId = uuidv4()
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 设置安全策略
this.applySecurity(sandbox)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 设置性能监控
this.setupPerformanceMonitoring(sandbox)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 更新状态
this.updateSandboxState(sandbox, SandboxState.READY)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
this.sandboxes.set(sandboxId, sandbox)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
if (sandbox.config.type === SandboxType.IFRAME && sandbox.iframe) {
console.log(`使用iframe加载应用: ${applicationUrl}`)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 检查iframe是否已挂载到DOM
if (!document.contains(sandbox.iframe)) {
console.warn('检测到iframe未挂载到DOM尝试重新挂载')
await this.mountIframeToWindow(sandbox)
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 设置iframe源
sandbox.iframe.src = applicationUrl
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 等待加载完成
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
2025-10-10 10:08:05 +08:00
console.error(
`应用加载超时: ${sandbox.appId}, URL: ${applicationUrl}, 超时时间: ${sandbox.config.networkTimeout}ms`
)
2025-09-24 16:43:10 +08:00
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
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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
}
}
/**
*
*/
destroySandbox(sandboxId: string): boolean {
const sandbox = this.sandboxes.get(sandboxId)
if (!sandbox) {
return false
}
try {
this.updateSandboxState(sandbox, SandboxState.DESTROYED)
2025-10-10 10:08:05 +08:00
2025-09-25 15:31:11 +08:00
// 移除消息事件监听器
if (sandbox.messageHandler) {
2025-10-10 10:08:05 +08:00
window.removeEventListener('message', sandbox.messageHandler)
sandbox.messageHandler = undefined
2025-09-25 15:31:11 +08:00
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 清理DOM元素
if (sandbox.iframe) {
sandbox.iframe.remove()
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
if (sandbox.container) {
sandbox.container.remove()
}
// 终止WebWorker
if (sandbox.worker) {
sandbox.worker.terminate()
}
// 清理性能数据
this.performanceData.delete(sandboxId)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 从集合中移除
this.sandboxes.delete(sandboxId)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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[] {
2025-10-10 10:08:05 +08:00
return Array.from(this.sandboxes.values()).filter((sandbox) => sandbox.appId === appId)
2025-09-24 16:43:10 +08:00
}
/**
*
*/
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
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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}`
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 设置sandbox属性
const sandboxAttributes: string[] = []
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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')
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
iframe.sandbox = sandboxAttributes.join(' ')
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 设置样式
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
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 将iframe挂载到对应的窗口内容区域
await this.mountIframeToWindow(sandbox)
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
/**
* 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}`)
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
const contentArea = windowElement.querySelector('.window-content')
if (!contentArea) {
throw new Error(`找不到窗口内容区域: window-${sandbox.windowId}`)
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 替换窗口中的默认iframe
const existingIframe = contentArea.querySelector('iframe')
if (existingIframe) {
contentArea.removeChild(existingIframe)
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
const worker = new Worker(workerUrl)
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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}`
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
const shadowRoot = container.attachShadow({ mode: 'closed' })
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 添加样式隔离
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'
}
// 这些头部主要用于服务器端设置,在客户端我们通过其他方式实现
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 监听iframe的消息事件
2025-09-25 15:31:11 +08:00
const messageHandler = (event: MessageEvent) => {
2025-09-24 16:43:10 +08:00
if (event.source === sandbox.iframe!.contentWindow) {
this.handleSandboxMessage(sandbox, event.data)
}
2025-10-10 10:08:05 +08:00
}
window.addEventListener('message', messageHandler)
2025-09-25 15:31:11 +08:00
// 存储事件监听器引用,以便在销毁时移除
2025-10-10 10:08:05 +08:00
sandbox.messageHandler = messageHandler
2025-09-24 16:43:10 +08:00
// 简化安全限制主要依赖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
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
case 'app:error':
sandbox.errors.push(message.error || '未知错误')
break
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
case 'app:resource-request':
this.handleResourceRequest(sandbox, message.data)
break
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
case 'app:performance':
this.recordPerformance(sandbox, message.data)
break
}
}
/**
*
*/
private async handleResourceRequest(sandbox: SandboxInstance, request: any): Promise<void> {
const { type, data } = request
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
try {
let result = null
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
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
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
case 'network':
2025-10-10 10:08:05 +08:00
result = await this.resourceService.makeNetworkRequest(
sandbox.appId,
data.url,
data.options
)
2025-09-24 16:43:10 +08:00
break
}
2025-10-10 10:08:05 +08:00
2025-09-24 16:43:10 +08:00
// 发送结果回沙箱
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'));
}
}
2025-09-25 15:31:11 +08:00
// 存储SDK实现
class StorageSDKImpl extends SDKBase {
constructor(appId) {
super();
this._appId = appId;
}
2025-09-24 16:43:10 +08:00
2025-09-25 15:31:11 +08:00
async set(key, value) {
return this.wrapResponse(this.sendToSystem('storage.set', { key, value }));
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
async get(key) {
return this.wrapResponse(this.sendToSystem('storage.get', { key }));
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
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 }));
2025-09-24 16:43:10 +08:00
2025-09-25 15:31:11 +08:00
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);
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
}
});
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
return result;
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
async off(subscriptionId) {
return this.wrapResponse(this.sendToSystem('events.off', { subscriptionId }));
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
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);
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
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;
2025-09-24 16:43:10 +08:00
2025-09-25 15:31:11 +08:00
// 初始化各个子模块为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未初始化');
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
return this._window;
}
get storage() {
if (!this._initialized) {
console.warn('[SystemSDK] storage模块未初始化');
throw new Error('SDK未初始化');
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
return this._storage;
}
get network() {
if (!this._initialized) {
console.warn('[SystemSDK] network模块未初始化');
throw new Error('SDK未初始化');
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
return this._network;
}
get events() {
if (!this._initialized) {
console.warn('[SystemSDK] events模块未初始化');
throw new Error('SDK未初始化');
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
return this._events;
}
get ui() {
if (!this._initialized) {
console.warn('[SystemSDK] ui模块未初始化');
throw new Error('SDK未初始化');
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
return this._ui;
}
get system() {
if (!this._initialized) {
console.warn('[SystemSDK] system模块未初始化');
throw new Error('SDK未初始化');
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
return this._system;
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
async init(config) {
try {
console.log('[SystemSDK] 开始初始化SDK配置:', config);
2025-09-24 16:43:10 +08:00
2025-09-25 15:31:11 +08:00
if (this._initialized) {
console.warn('[SystemSDK] SDK已初始化');
return { success: false, error: 'SDK已初始化' };
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
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 : '初始化失败',
};
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
}
async destroy() {
try {
2025-09-24 16:43:10 +08:00
if (!this._initialized) {
2025-09-25 15:31:11 +08:00
return { success: false, error: 'SDK未初始化' };
2025-09-24 16:43:10 +08:00
}
2025-09-25 15:31:11 +08:00
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 : '销毁失败',
};
2025-09-24 16:43:10 +08:00
}
}
2025-09-25 15:31:11 +08:00
}
// 创建全局SDK实例
const SystemSDK = new SystemDesktopSDKImpl();
// 在window对象上挂载SDK
window.SystemSDK = SystemSDK;
console.log('[SystemSDK] SDK已在iframe中注入并挂载到window对象');
// 通知系统应用已准备就绪
window.parent.postMessage({ type: 'app:ready' }, '*');
})();
2025-10-10 10:08:05 +08:00
`
iframeDoc.head.appendChild(script)
}
2025-09-24 16:43:10 +08:00
/**
*
*/
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)
}
/**
*
*/
2025-10-10 10:28:36 +08:00
private checkPerformanceThresholds(sandbox: SandboxInstance, metrics: SandboxPerformance): void {}
2025-09-24 16:43:10 +08:00
/**
*
*/
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) {
// 请求性能数据
2025-10-10 10:08:05 +08:00
sandbox.iframe.contentWindow.postMessage(
{
type: 'system:performance-request'
},
'*'
)
2025-09-24 16:43:10 +08:00
}
}
/**
*
*/
private updateSandboxState(sandbox: SandboxInstance, newState: SandboxState): void {
const oldState = sandbox.state
sandbox.state = newState
2025-10-10 10:08:05 +08:00
2025-10-10 10:28:36 +08:00
// 移除事件服务消息发送
// this.eventService.sendMessage('system', 'sandbox-state-change', {
// sandboxId: sandbox.id,
// newState,
// oldState
// })
2025-09-24 16:43:10 +08:00
}
2025-10-10 10:08:05 +08:00
}