This commit is contained in:
2025-10-10 10:28:36 +08:00
parent 204dd4781b
commit 71d5aabb84
10 changed files with 323 additions and 1185 deletions

View File

@@ -1,185 +1,220 @@
# Vue Desktop - 系统与业务解耦架构 # Vue Desktop
基于设计文档实现的高性能类Windows桌面前端系统实现了系统框架与业务应用的完全解耦。 一个基于 Vue 3 + TypeScript + Vite 的现代化桌面环境模拟器
## 🎯 项目概述 ## 🎯 项目目标
本项目成功实现了设计文档中描述的**系统与业务解耦架构**构建一个完整的桌面环境模拟系统,包含 构建一个轻量级、模块化的桌面环境,支持
- **完全隔离**:系统与应用在运行时完全隔离,应用无法直接访问系统资源 - 内置应用(计算器、记事本、待办事项等)
- **标准化接口**通过统一的SDK提供标准化的系统服务接口 - 外置应用加载(通过 iframe 沙箱)
- **性能优先**:采用微前端沙箱、虚拟化渲染等技术确保高性能 - 窗口管理(创建、移动、缩放、最小化等)
- **框架无关**:支持任意前端框架开发的第三方应用 - 资源管理(存储、权限控制)
- **安全可控**:严格的权限控制和安全沙箱机制 - 应用生命周期管理
- 安全沙箱机制
## 🏗️ 架构实现 ## 🏗️ 架构实现
### 核心服务层 ### 核心服务层
- **[WindowService](./src/services/WindowService.ts)** - 窗体管理服务,支持完整的窗体生命周期 - **[WindowService](./src/services/WindowService.ts)** - 窗体管理服务,支持完整的窗体生命周期
- **[ResourceService](./src/services/ResourceService.ts)** - 资源管理服务,提供权限控制和资源访问 - **[ResourceService](./src/services/ResourceService.ts)** - 资源管理服务,提供权限控制和资源访问
- **[EventCommunicationService](./src/services/EventCommunicationService.ts)** - 事件通信服务,支持跨应用消息传递
- **[ApplicationSandboxEngine](./src/services/ApplicationSandboxEngine.ts)** - 应用沙箱引擎,多层安全隔离 - **[ApplicationSandboxEngine](./src/services/ApplicationSandboxEngine.ts)** - 应用沙箱引擎,多层安全隔离
- **[ApplicationLifecycleManager](./src/services/ApplicationLifecycleManager.ts)** - 应用生命周期管理 - **[ApplicationLifecycleManager](./src/services/ApplicationLifecycleManager.ts)** - 应用生命周期管理
- **[SystemServiceIntegration](./src/services/SystemServiceIntegration.ts)** - 系统服务集成层 - **[SystemServiceIntegration](./src/services/SystemServiceIntegration.ts)** - 系统服务集成层
### SDK接口层 ### SDK接口层
- **[SDK类型定义](./src/sdk/types.ts)** - 完整的TypeScript接口定义
- **[SDK实现](./src/sdk/index.ts)** - 统一的SDK实现提供标准化API
### 应用层 - **[SystemSDK](./src/sdk/index.ts)** - 统一SDK接口为应用提供系统能力访问
- **内置应用**:计算器、记事本、系统状态监控
- **第三方应用**[待办事项应用](./public/apps/todo/index.html)示例
## 🚀 快速开始 ### 事件系统
### 环境要求 - **[IEventBuilder](./src/events/IEventBuilder.ts)** - 事件总线接口
- Node.js >= 20.19.0 - **[EventBuilderImpl](./src/events/impl/EventBuilderImpl.ts)** - 事件总线实现
- pnpm
### 安装与运行 ### 应用管理
```bash
# 安装依赖
pnpm install
# 启动开发服务器 - **[AppRegistry](./src/apps/AppRegistry.ts)** - 应用注册中心
pnpm dev - **[ExternalAppDiscovery](./src/services/ExternalAppDiscovery.ts)** - 外置应用发现服务
# 构建生产版本
pnpm build
```
### 访问应用
- 开发环境http://localhost:5174/
- 生产环境:部署后的域名
## 🎮 使用说明
### 桌面交互
1. **双击图标**启动应用
2. **拖拽图标**重新排列桌面布局
3. **右键菜单**访问系统功能(计划中)
### 内置应用
- **🧮 计算器**:基础的数学计算功能
- **📝 记事本**:文本编辑和文件保存
- **⚙️ 系统状态**:实时系统性能监控
- **✓ 待办事项**:完整的任务管理应用
### 窗体操作
- **最小化/最大化/还原**:标准窗体控制
- **拖拽移动**:通过标题栏拖拽窗体
- **调整大小**:支持窗体尺寸调整(计划中)
## 🔧 技术特性
### 系统架构特性
- **微前端架构**:每个应用运行在独立的沙箱中
- **事件驱动**:基于发布订阅模式的事件通信
- **权限控制**:细粒度的资源访问权限管理
- **性能监控**:实时的系统和应用性能监控
- **错误隔离**:应用错误不会影响系统稳定性
### 开发特性
- **TypeScript**:完整的类型安全保障
- **Vue 3**:现代化的响应式框架
- **Vite**:快速的构建工具
- **UnoCSS**原子化CSS框架
- **Naive UI**优雅的UI组件库
## 📁 项目结构 ## 📁 项目结构
``` ```
vue-desktop/ .
├── src/ ├── public\apps
│ ├── services/ # 核心服务层 │ ├── music-player
│ │ ├── WindowService.ts │ │ ├── README.md
│ │ ├── ResourceService.ts │ │ ├── app.js
│ │ ├── EventCommunicationService.ts │ │ ├── index.html
│ │ ├── ApplicationSandboxEngine.ts │ │ ├── manifest.json
│ │ └── style.css
│ └── README.md
├── src
│ ├── apps
│ │ ├── calculator
│ │ │ └── Calculator.vue
│ │ ├── components
│ │ │ └── BuiltInApp.vue
│ │ ├── notepad
│ │ │ └── Notepad.vue
│ │ ├── todo
│ │ │ └── Todo.vue
│ │ ├── types
│ │ │ └── AppManifest.ts
│ │ ├── AppRegistry.ts
│ │ └── index.ts
│ ├── common
│ │ ├── hooks
│ │ │ ├── useClickFocus.ts
│ │ │ └── useObservableVue.ts
│ │ ├── naive-ui
│ │ │ ├── components.ts
│ │ │ ├── discrete-api.ts
│ │ │ └── theme.ts
│ │ └── types
│ │ ├── IDestroyable.ts
│ │ └── IVersion.ts
│ ├── css
│ │ └── basic.css
│ ├── events
│ │ ├── impl
│ │ │ └── EventBuilderImpl.ts
│ │ └── IEventBuilder.ts
│ ├── sdk
│ │ ├── index.ts
│ │ └── types.ts
│ ├── services
│ │ ├── ApplicationLifecycleManager.ts │ │ ├── ApplicationLifecycleManager.ts
│ │ ── SystemServiceIntegration.ts │ │ ── ApplicationSandboxEngine.ts
├── sdk/ # SDK接口层 │ ├── ExternalAppDiscovery.ts
│ │ ├── types.ts # 类型定义 │ │ ├── ResourceService.ts
│ │ ── index.ts # SDK实现 │ │ ── SystemServiceIntegration.ts
├── ui/ # 用户界面 │ └── WindowService.ts
│ ├── desktop-container/ │ ├── stores
│ │ └── counter.ts
│ ├── ui
│ │ ├── components
│ │ │ ├── AppRenderer.vue
│ │ │ └── WindowManager.vue
│ │ ├── desktop-container
│ │ │ ├── AppIcon.vue
│ │ │ ├── DesktopContainer.vue
│ │ │ ├── useDesktopContainerInit.ts
│ │ │ └── useDynamicAppIcons.ts
│ │ ├── types
│ │ │ ├── IDesktopAppIcon.ts
│ │ │ ├── IGridTemplateParams.ts
│ │ │ └── WindowFormTypes.ts
│ │ └── App.vue │ │ └── App.vue
── events/ # 事件系统 ── main.ts
│ ├── stores/ # 状态管理 ├── PRETTIER_CONFIG_GUIDE.md
│ └── main.ts # 应用入口 ├── PROJECT_SUMMARY.md
├── public/ ├── README.md
│ └── apps/ # 第三方应用 ├── env.d.ts
│ └── todo/ # 待办事项应用 ├── index.html
── README.md ── package.json
├── pnpm-lock.yaml
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
├── uno.config.ts
└── vite.config.ts
``` ```
## 🔒 安全机制 ## 🚀 快速开始
### 沙箱隔离 ### 环境要求
- **iframe隔离**每个应用运行在独立的iframe中
- **CSP策略**:严格的内容安全策略
- **权限控制**:基于白名单的权限管理
- **API代理**所有系统调用通过SDK代理
### 权限模型 - Node.js >= 16.0.0
- **存储权限**:应用独立的存储空间 - pnpm >= 7.0.0
- **网络权限**:基于域名白名单的网络访问
- **通知权限**:用户确认的通知功能
- **剪贴板权限**:受控的剪贴板访问
## 📊 性能优化 ### 安装依赖
### 渲染优化 ```bash
- **虚拟化布局**:高效的图标网格布局 pnpm install
- **按需加载**:应用按需动态加载 ```
- **内存管理**:智能的内存回收机制
- **性能监控**:实时的性能指标收集
### 系统优化 ### 开发模式
- **事件节流**:防止事件风暴
- **资源缓存**:智能的资源缓存策略
- **自动清理**:定期的系统资源清理
- **错误恢复**:优雅的错误处理和恢复
## 🔮 未来规划 ```bash
pnpm dev
```
### 短期计划 ### 构建生产版本
- [ ] 窗体拖拽和调整大小功能
- [ ] 右键菜单和快捷方式
- [ ] 更多内置应用(文件管理器、浏览器等)
- [ ] 应用商店和在线安装
### 长期计划 ```bash
- [ ] 多桌面和工作区 pnpm build
- [ ] 插件系统和扩展机制 ```
- [ ] 云同步和备份
- [ ] 移动端适配
## 🤝 贡献指南 ### 预览生产构建
欢迎贡献代码、报告bug或提出功能建议 ```bash
pnpm preview
```
### 开发流程 ## 🛠️ 开发指南
1. Fork项目
2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 创建Pull Request
### 代码规范 ### 添加内置应用
- 使用TypeScript进行类型安全
- 遵循Vue 3组合式API最佳实践
- 使用ESLint和Prettier保持代码风格一致
- 为新功能编写测试用例
## 📄 许可证 1.`src/apps/` 目录下创建应用文件夹
2. 创建 Vue 组件文件(如 `MyApp.vue`
3.`src/apps/AppRegistry.ts` 中注册应用
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。 ### 添加外置应用
## 🙏 致谢 1.`public/apps/` 目录下创建应用文件夹
2. 添加 `manifest.json` 应用清单文件
3. 添加应用的 HTML/CSS/JS 文件
4. 系统会自动发现并加载该应用
感谢所有参与项目开发和测试的贡献者,以及提供技术支持的开源社区。 ### 系统服务使用
--- 通过依赖注入获取系统服务:
**Vue Desktop** - 让Web应用拥有桌面应用的体验 🚀 ```typescript
import type { SystemServiceIntegration } from '@/services/SystemServiceIntegration'
const systemService = inject<SystemServiceIntegration>('systemService')
```
可用服务:
- `getWindowService()` - 窗体服务
- `getResourceService()` - 资源服务
- `getSandboxEngine()` - 沙箱引擎
- `getLifecycleManager()` - 生命周期管理器
## 📖 技术文档
### 窗体系统
窗体系统支持完整的生命周期管理,包括创建、移动、缩放、最小化、最大化等操作。
### 资源管理
资源服务提供安全的存储访问和权限控制机制。
### 沙箱安全
应用沙箱引擎提供多层安全隔离,防止恶意代码访问系统资源。
### 应用生命周期
应用生命周期管理器负责应用的安装、启动、停止、卸载等操作。
## 🧪 测试
### 单元测试
```bash
pnpm test
```
### 端到端测试
```bash
pnpm test:e2e
```
## 📦 部署
构建产物可直接部署到任何静态文件服务器上。

View File

@@ -2,40 +2,34 @@
<BuiltInApp app-id="calculator" title="计算器"> <BuiltInApp app-id="calculator" title="计算器">
<div class="calculator"> <div class="calculator">
<div class="display"> <div class="display">
<input <input v-model="displayValue" type="text" readonly class="display-input" :class="{ 'error': hasError }">
v-model="displayValue"
type="text"
readonly
class="display-input"
:class="{ 'error': hasError }"
>
</div> </div>
<div class="buttons"> <div class="buttons">
<!-- 第一行 --> <!-- 第一行 -->
<button @click="clear" class="btn btn-clear">C</button> <button @click="clear" class="btn btn-clear">C</button>
<button @click="deleteLast" class="btn btn-operation"></button> <button @click="deleteLast" class="btn btn-operation"></button>
<button @click="appendOperation('/')" class="btn btn-operation">÷</button> <button @click="appendOperation('/')" class="btn btn-operation">÷</button>
<button @click="appendOperation('*')" class="btn btn-operation">×</button> <button @click="appendOperation('*')" class="btn btn-operation">×</button>
<!-- 第二行 --> <!-- 第二行 -->
<button @click="appendNumber('7')" class="btn btn-number">7</button> <button @click="appendNumber('7')" class="btn btn-number">7</button>
<button @click="appendNumber('8')" class="btn btn-number">8</button> <button @click="appendNumber('8')" class="btn btn-number">8</button>
<button @click="appendNumber('9')" class="btn btn-number">9</button> <button @click="appendNumber('9')" class="btn btn-number">9</button>
<button @click="appendOperation('-')" class="btn btn-operation">-</button> <button @click="appendOperation('-')" class="btn btn-operation">-</button>
<!-- 第三行 --> <!-- 第三行 -->
<button @click="appendNumber('4')" class="btn btn-number">4</button> <button @click="appendNumber('4')" class="btn btn-number">4</button>
<button @click="appendNumber('5')" class="btn btn-number">5</button> <button @click="appendNumber('5')" class="btn btn-number">5</button>
<button @click="appendNumber('6')" class="btn btn-number">6</button> <button @click="appendNumber('6')" class="btn btn-number">6</button>
<button @click="appendOperation('+')" class="btn btn-operation">+</button> <button @click="appendOperation('+')" class="btn btn-operation">+</button>
<!-- 第四行 --> <!-- 第四行 -->
<button @click="appendNumber('1')" class="btn btn-number">1</button> <button @click="appendNumber('1')" class="btn btn-number">1</button>
<button @click="appendNumber('2')" class="btn btn-number">2</button> <button @click="appendNumber('2')" class="btn btn-number">2</button>
<button @click="appendNumber('3')" class="btn btn-number">3</button> <button @click="appendNumber('3')" class="btn btn-number">3</button>
<button @click="calculate" class="btn btn-equals" rowspan="2">=</button> <button @click="calculate" class="btn btn-equals" rowspan="2">=</button>
<!-- 第五行 --> <!-- 第五行 -->
<button @click="appendNumber('0')" class="btn btn-number btn-zero">0</button> <button @click="appendNumber('0')" class="btn btn-number btn-zero">0</button>
<button @click="appendNumber('.')" class="btn btn-number">.</button> <button @click="appendNumber('.')" class="btn btn-number">.</button>
@@ -79,27 +73,28 @@ const saveHistory = async (expression: string, result: string) => {
} }
} }
// 直接使用事件服务发送通知 // 移除事件服务相关代码
const showNotification = (message: string) => { // // 直接使用事件服务发送通知
if (systemService) { // const showNotification = (message: string) => {
const eventService = systemService.getEventService() // if (systemService) {
eventService.sendMessage('calculator', 'user-interaction', { // const eventService = systemService.getEventService()
type: 'notification', // eventService.sendMessage('calculator', 'user-interaction', {
message, // type: 'notification',
timestamp: new Date() // message,
}) // timestamp: new Date()
} // })
} // }
// }
// 添加数字 // 添加数字
const appendNumber = (num: string) => { const appendNumber = (num: string) => {
hasError.value = false hasError.value = false
if (shouldResetDisplay.value) { if (shouldResetDisplay.value) {
displayValue.value = '0' displayValue.value = '0'
shouldResetDisplay.value = false shouldResetDisplay.value = false
} }
if (num === '.') { if (num === '.') {
if (!displayValue.value.includes('.')) { if (!displayValue.value.includes('.')) {
displayValue.value += num displayValue.value += num
@@ -117,10 +112,10 @@ const appendNumber = (num: string) => {
const appendOperation = (op: string) => { const appendOperation = (op: string) => {
hasError.value = false hasError.value = false
shouldResetDisplay.value = false shouldResetDisplay.value = false
const lastChar = displayValue.value.slice(-1) const lastChar = displayValue.value.slice(-1)
const operations = ['+', '-', '*', '/'] const operations = ['+', '-', '*', '/']
// 如果最后一个字符是运算符,替换它 // 如果最后一个字符是运算符,替换它
if (operations.includes(lastChar)) { if (operations.includes(lastChar)) {
displayValue.value = displayValue.value.slice(0, -1) + op displayValue.value = displayValue.value.slice(0, -1) + op
@@ -136,29 +131,30 @@ const calculate = async () => {
let expression = displayValue.value let expression = displayValue.value
.replace(/×/g, '*') .replace(/×/g, '*')
.replace(/÷/g, '/') .replace(/÷/g, '/')
// 简单的表达式验证 // 简单的表达式验证
if (/[+\-*/]$/.test(expression)) { if (/[+\-*/]$/.test(expression)) {
return // 以运算符结尾,不计算 return // 以运算符结尾,不计算
} }
const originalExpression = displayValue.value const originalExpression = displayValue.value
const result = eval(expression) const result = eval(expression)
if (!isFinite(result)) { if (!isFinite(result)) {
throw new Error('除零错误') throw new Error('除零错误')
} }
displayValue.value = result.toString() displayValue.value = result.toString()
lastResult.value = result lastResult.value = result
shouldResetDisplay.value = true shouldResetDisplay.value = true
// 保存历史记录 // 保存历史记录
await saveHistory(originalExpression, result.toString()) await saveHistory(originalExpression, result.toString())
// 发送通知 // 移除事件服务相关代码
showNotification(`计算结果: ${result}`) // // 发送通知
// showNotification(`计算结果: ${result}`)
} catch (error) { } catch (error) {
hasError.value = true hasError.value = true
displayValue.value = '错误' displayValue.value = '错误'
@@ -179,12 +175,12 @@ const clear = () => {
// 删除最后一个字符 // 删除最后一个字符
const deleteLast = () => { const deleteLast = () => {
hasError.value = false hasError.value = false
if (shouldResetDisplay.value) { if (shouldResetDisplay.value) {
clear() clear()
return return
} }
if (displayValue.value.length > 1) { if (displayValue.value.length > 1) {
displayValue.value = displayValue.value.slice(0, -1) displayValue.value = displayValue.value.slice(0, -1)
} else { } else {
@@ -195,9 +191,9 @@ const deleteLast = () => {
// 键盘事件处理 // 键盘事件处理
const handleKeyboard = (event: KeyboardEvent) => { const handleKeyboard = (event: KeyboardEvent) => {
event.preventDefault() event.preventDefault()
const key = event.key const key = event.key
if (/[0-9.]/.test(key)) { if (/[0-9.]/.test(key)) {
appendNumber(key) appendNumber(key)
} else if (['+', '-', '*', '/'].includes(key)) { } else if (['+', '-', '*', '/'].includes(key)) {
@@ -330,17 +326,17 @@ onMounted(() => {
margin: 10px; margin: 10px;
padding: 15px; padding: 15px;
} }
.display-input { .display-input {
height: 60px; height: 60px;
font-size: 24px; font-size: 24px;
} }
.buttons { .buttons {
height: 280px; height: 280px;
gap: 8px; gap: 8px;
} }
.btn { .btn {
font-size: 16px; font-size: 16px;
} }

View File

@@ -25,7 +25,7 @@ const appContext = {
systemService, systemService,
// 直接暴露系统服务的方法,简化调用 // 直接暴露系统服务的方法,简化调用
storage: systemService?.getResourceService(), storage: systemService?.getResourceService(),
events: systemService?.getEventService(), // 移除 events: systemService?.getEventService(),
lifecycle: systemService?.getLifecycleManager(), lifecycle: systemService?.getLifecycleManager(),
window: { window: {
setTitle: (title: string) => { setTitle: (title: string) => {
@@ -52,11 +52,11 @@ onMounted(async () => {
version: '1.0.0', version: '1.0.0',
permissions: ['storage', 'notification'] permissions: ['storage', 'notification']
}) })
if (props.title) { if (props.title) {
await window.SystemSDK.window.setTitle(props.title) await window.SystemSDK.window.setTitle(props.title)
} }
console.log(`内置应用 ${props.appId} 初始化成功`) console.log(`内置应用 ${props.appId} 初始化成功`)
} }
} catch (error) { } catch (error) {

View File

@@ -1,10 +1,48 @@
import type { IDestroyable } from '@/common/types/IDestroyable' import type { IDestroyable } from '@/common/types/IDestroyable'
import type { WindowState } from '@/services/WindowService'
import type { ResourceType } from '@/services/ResourceService'
/**
* 窗体数据更新参数
*/
export interface WindowFormDataUpdateParams {
/** 窗口id */
id: string
/** 窗口状态 */
state: WindowState
/** 窗口宽度 */
width: number
/** 窗口高度 */
height: number
/** 窗口x坐标(左上角) */
x: number
/** 窗口y坐标(左上角) */
y: number
}
/** /**
* 事件定义 * 事件定义
* @interface IEventMap 事件定义 键是事件名称,值是事件处理函数 * @interface IEventMap 事件定义 键是事件名称,值是事件处理函数
*/ */
export interface IEventMap { export interface IEventMap {
// 系统就绪事件
onSystemReady: (data: { timestamp: Date; services: string[] }) => void
// 窗体相关事件
onWindowStateChanged: (windowId: string, newState: string, oldState: string) => void
onWindowFormDataUpdate: (data: WindowFormDataUpdateParams) => void
onWindowFormResizeStart: (windowId: string) => void
onWindowFormResizing: (windowId: string, width: number, height: number) => void
onWindowFormResizeEnd: (windowId: string) => void
onWindowClose: (windowId: string) => void
// 应用生命周期事件
onAppLifecycle: (data: { appId: string; event: string; timestamp: Date }) => void
// 资源相关事件
onResourceQuotaExceeded: (appId: string, resourceType: ResourceType) => void
onPerformanceAlert: (data: { type: 'memory' | 'cpu'; usage: number; limit: number }) => void
/** /**
* 事件处理函数映射 * 事件处理函数映射
*/ */
@@ -29,7 +67,7 @@ export interface IEventBuilder<Events extends IEventMap> extends IDestroyable {
immediate?: boolean immediate?: boolean
immediateArgs?: Parameters<F> immediateArgs?: Parameters<F>
once?: boolean once?: boolean
}, }
): void ): void
/** /**
@@ -46,5 +84,8 @@ export interface IEventBuilder<Events extends IEventMap> extends IDestroyable {
* @param args 参数 * @param args 参数
* @returns void * @returns void
*/ */
notifyEvent<E extends keyof Events, F extends Events[E]>(eventName: E, ...args: Parameters<F>): void notifyEvent<E extends keyof Events, F extends Events[E]>(
} eventName: E,
...args: Parameters<F>
): void
}

View File

@@ -1,7 +1,6 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import type { WindowService } from './WindowService' import type { WindowService } from './WindowService'
import type { ResourceService } from './ResourceService' import type { ResourceService } from './ResourceService'
import type { EventCommunicationService } from './EventCommunicationService'
import type { ApplicationSandboxEngine } from './ApplicationSandboxEngine' import type { ApplicationSandboxEngine } from './ApplicationSandboxEngine'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { externalAppDiscovery } from './ExternalAppDiscovery' import { externalAppDiscovery } from './ExternalAppDiscovery'
@@ -121,21 +120,16 @@ export class ApplicationLifecycleManager {
private windowService: WindowService private windowService: WindowService
private resourceService: ResourceService private resourceService: ResourceService
private eventService: EventCommunicationService
private sandboxEngine: ApplicationSandboxEngine private sandboxEngine: ApplicationSandboxEngine
constructor( constructor(
windowService: WindowService, windowService: WindowService,
resourceService: ResourceService, resourceService: ResourceService,
eventService: EventCommunicationService,
sandboxEngine: ApplicationSandboxEngine sandboxEngine: ApplicationSandboxEngine
) { ) {
this.windowService = windowService this.windowService = windowService
this.resourceService = resourceService this.resourceService = resourceService
this.eventService = eventService
this.sandboxEngine = sandboxEngine this.sandboxEngine = sandboxEngine
this.setupEventListeners()
} }
/** /**
@@ -385,49 +379,6 @@ export class ApplicationLifecycleManager {
} }
} }
// 私有方法
/**
* 为内置应用挂载 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 组件`)
console.log('----------------------------------')
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
}
}
/** /**
* 检查权限 * 检查权限
*/ */
@@ -510,28 +461,6 @@ export class ApplicationLifecycleManager {
} }
} }
/**
* 设置事件监听器
*/
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
}
}
})
}
/** /**
* 处理应用错误 * 处理应用错误
*/ */
@@ -541,12 +470,6 @@ export class ApplicationLifecycleManager {
app.errorCount++ app.errorCount++
this.eventService.sendMessage('system', 'app-lifecycle', {
type: 'error',
appId,
error: error.message
})
console.error(`应用 ${appId} 发生错误:`, error) console.error(`应用 ${appId} 发生错误:`, error)
} }
@@ -577,11 +500,12 @@ export class ApplicationLifecycleManager {
const oldState = app.state const oldState = app.state
app.state = newState app.state = newState
this.eventService.sendMessage('system', 'app-lifecycle', { // 移除事件服务消息发送
type: 'stateChanged', // this.eventService.sendMessage('system', 'app-lifecycle', {
appId: app.id, // type: 'stateChanged',
newState, // appId: app.id,
oldState // newState,
}) // oldState
// })
} }
} }

View File

@@ -1,6 +1,5 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import type { ResourceService } from './ResourceService' import type { ResourceService } from './ResourceService'
import type { EventCommunicationService } from './EventCommunicationService'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
/** /**
@@ -107,11 +106,9 @@ export class ApplicationSandboxEngine {
private performanceData = reactive(new Map<string, SandboxPerformance[]>()) private performanceData = reactive(new Map<string, SandboxPerformance[]>())
private monitoringInterval: number | null = null private monitoringInterval: number | null = null
private resourceService: ResourceService private resourceService: ResourceService
private eventService: EventCommunicationService
constructor(resourceService: ResourceService, eventService: EventCommunicationService) { constructor(resourceService: ResourceService) {
this.resourceService = resourceService this.resourceService = resourceService
this.eventService = eventService
this.startPerformanceMonitoring() this.startPerformanceMonitoring()
} }
@@ -1163,27 +1160,7 @@ export class ApplicationSandboxEngine {
/** /**
* 检查性能阈值 * 检查性能阈值
*/ */
private checkPerformanceThresholds(sandbox: SandboxInstance, metrics: SandboxPerformance): void { 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
})
}
}
/** /**
* 开始性能监控 * 开始性能监控
@@ -1220,11 +1197,11 @@ export class ApplicationSandboxEngine {
const oldState = sandbox.state const oldState = sandbox.state
sandbox.state = newState sandbox.state = newState
// 触发状态变化事件 // 移除事件服务消息发送
this.eventService.sendMessage('system', 'sandbox-state-change', { // this.eventService.sendMessage('system', 'sandbox-state-change', {
sandboxId: sandbox.id, // sandboxId: sandbox.id,
newState, // newState,
oldState // oldState
}) // })
} }
} }

View File

@@ -1,748 +0,0 @@
import { reactive } from 'vue'
import type { IEventBuilder, IEventMap } from '@/events/IEventBuilder'
import { v4 as uuidv4 } from 'uuid'
import type { WindowState } from './WindowService'
import type { ResourceType } from './ResourceService'
/**
* 消息类型枚举
*/
export enum MessageType {
/** 系统事件 */
SYSTEM = 'system',
/** 应用事件 */
APPLICATION = 'application',
/** 用户交互事件 */
USER_INTERACTION = 'user_interaction',
/** 跨应用事件 */
CROSS_APP = 'cross_app',
/** 广播事件 */
BROADCAST = 'broadcast'
}
/**
* 消息优先级枚举
*/
export enum MessagePriority {
/** 低优先级 */
LOW = 0,
/** 正常优先级 */
NORMAL = 1,
/** 高优先级 */
HIGH = 2,
/** 紧急优先级 */
CRITICAL = 3
}
/**
* 消息状态枚举
*/
export enum MessageStatus {
/** 等待发送 */
PENDING = 'pending',
/** 已发送 */
SENT = 'sent',
/** 已送达 */
DELIVERED = 'delivered',
/** 发送失败 */
FAILED = 'failed',
/** 已取消 */
EXPIRED = 'expired'
}
/**
* 事件消息接口
*/
export interface EventMessage {
/** 消息ID */
id: string
/** 消息类型 */
type: MessageType
/** 消息优先级 */
priority: MessagePriority
/** 发送者ID */
senderId: string
/** 接收者ID, undefined表示广播消息 */
receiverId?: string
/** 消息频道 */
channel: string
/** 消息内容 */
payload: any
/** 消息发送时间 */
timestamp: Date
/** 消息过期时间 */
expiresAt?: Date
/** 消息状态 */
status: MessageStatus
/** 重试次数 */
retryCount: number
/** 最大重试次数 */
maxRetries: number
}
/**
* 事件订阅者接口
*/
export interface EventSubscriber {
/** 订阅者ID */
id: string
/** 应用ID */
appId: string
/** 消息频道 */
channel: string
/** 订阅者处理函数 */
handler: (message: EventMessage) => void | Promise<void>
/** 消息过滤器 */
filter?: (message: EventMessage) => boolean
/** 订阅者优先级 */
priority: MessagePriority
/** 创建时间 */
createdAt: Date
/** 是否启用 */
active: boolean
}
/**
* 通信通道接口
*/
export interface CommunicationChannel {
/** 通道名称 */
name: string
/** 通道描述 */
description: string
/** 是否需要权限 */
restricted: boolean
/** 允许的源应用ID列表 */
/** 允许访问的应用ID列表 */
allowedApps: string[]
/** 最大消息大小(字节) */
maxMessageSize: number
/** 消息保留时间(毫秒) */
messageRetention: number
}
/**
* 事件统计信息
*/
export interface EventStatistics {
/** 总发送消息数 */
totalMessagesSent: number
/** 总接收消息数 */
totalMessagesReceived: number
/** 总广播数 */
totalBroadcasts: number
/** 失败消息数 */
failedMessages: number
/** 激活的订阅者数 */
activeSubscribers: number
/** 通道使用情况 */
channelUsage: Map<string, number>
}
/**
* 窗体数据更新参数
*/
export interface WindowFormDataUpdateParams {
/** 窗口id */
id: string
/** 窗口状态 */
state: WindowState
/** 窗口宽度 */
width: number
/** 窗口高度 */
height: number
/** 窗口x坐标(左上角) */
x: number
/** 窗口y坐标(左上角) */
y: number
}
/**
* 事件通信服务事件接口
*/
export interface EventCommunicationEvents extends IEventMap {
// 系统就绪事件
onSystemReady: (data: { timestamp: Date; services: string[] }) => void
// 窗体相关事件
onWindowStateChanged: (windowId: string, newState: string, oldState: string) => void
onWindowFormDataUpdate: (data: WindowFormDataUpdateParams) => void
onWindowFormResizeStart: (windowId: string) => void
onWindowFormResizing: (windowId: string, width: number, height: number) => void
onWindowFormResizeEnd: (windowId: string) => void
onWindowClose: (windowId: string) => void
// 应用生命周期事件
onAppLifecycle: (data: { appId: string; event: string; timestamp: Date }) => void
// 资源相关事件
onResourceQuotaExceeded: (appId: string, resourceType: ResourceType) => void
onPerformanceAlert: (data: { type: 'memory' | 'cpu'; usage: number; limit: number }) => void
// 消息处理事件
onMessageProcessed: (message: EventMessage) => void
onMessageFailed: (message: EventMessage, error: any) => void
}
/**
* 事件通信服务类
*/
export class EventCommunicationService {
private subscribers = reactive(new Map<string, EventSubscriber>())
private messageQueue = reactive(new Map<string, EventMessage[]>()) // 按应用分组的消息队列
private messageHistory = reactive(new Map<string, EventMessage[]>()) // 消息历史记录
private channels = reactive(new Map<string, CommunicationChannel>())
private statistics = reactive<EventStatistics>({
totalMessagesSent: 0,
totalMessagesReceived: 0,
totalBroadcasts: 0,
failedMessages: 0,
activeSubscribers: 0,
channelUsage: new Map()
})
private processingInterval: number | null = null
private lastProcessTime: number = 0
private processInterval: number = 100 // 处理间隔(毫秒)
private eventBus: IEventBuilder<EventCommunicationEvents>
constructor(eventBus: IEventBuilder<EventCommunicationEvents>) {
this.eventBus = eventBus
this.initializeDefaultChannels()
this.startMessageProcessing()
}
/**
* 订阅事件频道
*/
subscribe(
appId: string,
channel: string,
handler: (message: EventMessage) => void | Promise<void>,
options: {
filter?: (message: EventMessage) => boolean
priority?: MessagePriority
} = {}
): string {
// 检查通道权限
if (!this.canAccessChannel(appId, channel)) {
throw new Error(`应用 ${appId} 无权访问频道 ${channel}`)
}
const subscriberId = uuidv4()
const subscriber: EventSubscriber = {
id: subscriberId,
appId,
channel,
handler,
filter: options.filter,
priority: options.priority || MessagePriority.NORMAL,
createdAt: new Date(),
active: true
}
this.subscribers.set(subscriberId, subscriber)
this.updateActiveSubscribersCount()
console.log(`应用 ${appId} 订阅了频道 ${channel}`)
return subscriberId
}
/**
* 取消订阅
*/
unsubscribe(subscriberId: string): boolean {
const result = this.subscribers.delete(subscriberId)
if (result) {
this.updateActiveSubscribersCount()
console.log(`取消订阅: ${subscriberId}`)
}
return result
}
/**
* 发送消息
*/
async sendMessage(
senderId: string,
channel: string,
payload: any,
options: {
receiverId?: string
priority?: MessagePriority
type?: MessageType
expiresIn?: number // 过期时间(毫秒)
maxRetries?: number
} = {}
): Promise<string> {
if (this.getChannelSubscriberCount(channel) === 0) {
throw new Error(`频道 ${channel} 无订阅者`)
}
// 检查发送者权限
if (!this.canAccessChannel(senderId, channel)) {
throw new Error(`应用 ${senderId} 无权向频道 ${channel} 发送消息`)
}
// 检查消息大小
const messageSize = JSON.stringify(payload).length
const channelConfig = this.channels.get(channel)
if (channelConfig && messageSize > channelConfig.maxMessageSize) {
throw new Error(`消息大小超出限制: ${messageSize} > ${channelConfig.maxMessageSize}`)
}
const messageId = uuidv4()
const now = new Date()
const message: EventMessage = {
id: messageId,
type: options.type || MessageType.APPLICATION,
priority: options.priority || MessagePriority.NORMAL,
senderId,
receiverId: options.receiverId,
channel,
payload,
timestamp: now,
expiresAt: options.expiresIn ? new Date(now.getTime() + options.expiresIn) : undefined,
status: MessageStatus.PENDING,
retryCount: 0,
maxRetries: options.maxRetries || 3
}
// 如果是点对点消息,直接发送
if (options.receiverId) {
await this.deliverMessage(message)
} else {
// 广播消息,加入队列处理
this.addToQueue(message)
}
// 更新统计信息
this.statistics.totalMessagesSent++
if (!options.receiverId) {
this.statistics.totalBroadcasts++
}
const channelUsage = this.statistics.channelUsage.get(channel) || 0
this.statistics.channelUsage.set(channel, channelUsage + 1)
// 记录消息历史
this.recordMessage(message)
console.log(
`[EventCommunication] 消息 ${messageId} 已发送到频道 ${channel}[发送者: ${senderId}]`
)
return messageId
}
/**
* 广播消息到所有订阅者
*/
async broadcast(
senderId: string,
channel: string,
payload: any,
options: {
priority?: MessagePriority
expiresIn?: number
} = {}
): Promise<string> {
return this.sendMessage(senderId, channel, payload, {
...options,
type: MessageType.BROADCAST
})
}
/**
* 发送跨应用消息
*/
async sendCrossAppMessage(
senderId: string,
receiverId: string,
payload: any,
options: {
priority?: MessagePriority
expiresIn?: number
} = {}
): Promise<string> {
const channel = 'cross-app'
return this.sendMessage(senderId, channel, payload, {
...options,
receiverId,
type: MessageType.CROSS_APP
})
}
/**
* 获取消息历史
*/
getMessageHistory(
appId: string,
options: {
channel?: string
limit?: number
since?: Date
} = {}
): EventMessage[] {
const history = this.messageHistory.get(appId) || []
let filtered = history.filter((msg) => msg.senderId === appId || msg.receiverId === appId)
if (options.channel) {
filtered = filtered.filter((msg) => msg.channel === options.channel)
}
if (options.since) {
filtered = filtered.filter((msg) => msg.timestamp >= options.since!)
}
if (options.limit) {
filtered = filtered.slice(-options.limit)
}
return filtered.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())
}
/**
* 获取应用的订阅列表
*/
getAppSubscriptions(appId: string): EventSubscriber[] {
return Array.from(this.subscribers.values()).filter((sub) => sub.appId === appId)
}
/**
* 获取频道订阅者数量
*/
getChannelSubscriberCount(channel: string): number {
return Array.from(this.subscribers.values()).filter(
(sub) => sub.channel === channel && sub.active
).length
}
/**
* 创建通信频道
*/
createChannel(channel: string, config: Omit<CommunicationChannel, 'name'>): boolean {
if (this.channels.has(channel)) {
return false
}
this.channels.set(channel, {
name: channel,
...config
})
console.log(`创建通信频道: ${channel}`)
return true
}
/**
* 删除通信频道
*/
deleteChannel(channel: string): boolean {
// 移除所有相关订阅
const subscribersToRemove = Array.from(this.subscribers.entries())
.filter(([, sub]) => sub.channel === channel)
.map(([id]) => id)
subscribersToRemove.forEach((id) => this.unsubscribe(id))
// 删除频道
const result = this.channels.delete(channel)
if (result) {
console.log(`删除通信频道: ${channel}`)
}
return result
}
/**
* 获取统计信息
*/
getStatistics(): EventStatistics {
return { ...this.statistics }
}
/**
* 清理过期消息和订阅
*/
cleanup(): void {
const now = new Date()
// 清理过期消息
for (const [appId, messages] of this.messageQueue.entries()) {
const validMessages = messages.filter((msg) => !msg.expiresAt || msg.expiresAt > now)
if (validMessages.length !== messages.length) {
this.messageQueue.set(appId, validMessages)
}
}
// 清理消息历史(保留最近7天)
const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)
for (const [appId, history] of this.messageHistory.entries()) {
const recentHistory = history.filter((msg) => msg.timestamp > sevenDaysAgo)
this.messageHistory.set(appId, recentHistory)
}
console.log('事件通信服务清理完成')
}
/**
* 销毁服务
*/
destroy(): void {
if (this.processingInterval) {
cancelAnimationFrame(this.processingInterval)
this.processingInterval = null
}
this.subscribers.clear()
this.messageQueue.clear()
this.messageHistory.clear()
this.channels.clear()
console.log('事件通信服务已销毁')
}
// 私有方法
/**
* 初始化默认频道
*/
private initializeDefaultChannels(): void {
// 系统事件频道
this.createChannel('system', {
description: '系统级事件通信',
restricted: true,
allowedApps: ['system'],
maxMessageSize: 1024 * 10, // 10KB
messageRetention: 24 * 60 * 60 * 1000 // 24小时
})
// 应用间通信频道
this.createChannel('cross-app', {
description: '应用间通信',
restricted: false,
allowedApps: [],
maxMessageSize: 1024 * 100, // 100KB
messageRetention: 7 * 24 * 60 * 60 * 1000 // 7天
})
// 用户交互频道
this.createChannel('user-interaction', {
description: '用户交互事件',
restricted: false,
allowedApps: [],
maxMessageSize: 1024 * 5, // 5KB
messageRetention: 60 * 60 * 1000 // 1小时
})
// 广播频道
this.createChannel('broadcast', {
description: '系统广播',
restricted: true,
allowedApps: ['system'],
maxMessageSize: 1024 * 50, // 50KB
messageRetention: 24 * 60 * 60 * 1000 // 24小时
})
}
/**
* 检查应用是否可以访问频道
*/
private canAccessChannel(appId: string, channel: string): boolean {
const channelConfig = this.channels.get(channel)
if (!channelConfig) {
// 频道不存在,默认允许
return true
}
if (!channelConfig.restricted) {
return true
}
// 系统应用总是有权限
if (appId === 'system') {
return true
}
return channelConfig.allowedApps.includes(appId)
}
/**
* 添加消息到队列
*/
private addToQueue(message: EventMessage): void {
const queueKey = message.receiverId || 'broadcast'
if (!this.messageQueue.has(queueKey)) {
this.messageQueue.set(queueKey, [])
}
const queue = this.messageQueue.get(queueKey)!
// 按优先级插入
const insertIndex = queue.findIndex((msg) => msg.priority < message.priority)
if (insertIndex === -1) {
queue.push(message)
} else {
queue.splice(insertIndex, 0, message)
}
}
/**
* 直接投递消息
*/
private async deliverMessage(message: EventMessage): Promise<void> {
try {
const subscribers = this.getRelevantSubscribers(message)
if (subscribers.length === 0) {
message.status = MessageStatus.FAILED
// 只对非系统频道显示警告信息
if (message.channel !== 'system') {
console.warn(
`[EventCommunication] 没有找到频道 ${message.channel} 的订阅者[消息 ID: ${message.id}]`
)
}
return
}
// 并行发送给所有订阅者
const deliveryPromises = subscribers.map(async (subscriber) => {
try {
// 应用过滤器
if (subscriber.filter && !subscriber.filter(message)) {
return
}
await subscriber.handler(message)
this.statistics.totalMessagesReceived++
console.log(
`[EventCommunication] 消息 ${message.id} 已投递给订阅者 ${subscriber.id}[频道: ${message.channel}]`
)
} catch (error) {
console.error(`向订阅者 ${subscriber.id} 发送消息失败:`, error)
throw error
}
})
await Promise.allSettled(deliveryPromises)
message.status = MessageStatus.DELIVERED
} catch (error) {
message.status = MessageStatus.FAILED
this.statistics.failedMessages++
console.error('消息投递失败:', error)
// 重试机制
if (message.retryCount < message.maxRetries) {
message.retryCount++
message.status = MessageStatus.PENDING
setTimeout(() => this.deliverMessage(message), 1000 * message.retryCount)
}
}
}
/**
* 获取相关订阅者
*/
private getRelevantSubscribers(message: EventMessage): EventSubscriber[] {
return Array.from(this.subscribers.values()).filter((subscriber) => {
if (!subscriber.active) return false
if (subscriber.channel !== message.channel) return false
// 点对点消息检查接收者
if (message.receiverId && subscriber.appId !== message.receiverId) {
return false
}
return true
})
}
/**
* 开始消息处理循环
*/
private startMessageProcessing(): void {
const processFrame = (timestamp: number) => {
// 如果距离上次处理时间超过设定间隔,则处理消息
if (timestamp - this.lastProcessTime >= this.processInterval) {
this.processMessageQueue()
this.cleanupExpiredMessages()
this.lastProcessTime = timestamp
}
// 继续下一帧
this.processingInterval = requestAnimationFrame(processFrame)
}
// 启动处理循环
this.processingInterval = requestAnimationFrame(processFrame)
}
/**
* 处理消息队列
*/
private processMessageQueue(): void {
for (const [queueKey, messages] of this.messageQueue.entries()) {
if (messages.length === 0) continue
// 处理优先级最高的消息
const message = messages.shift()!
// 检查消息是否过期
if (message.expiresAt && message.expiresAt <= new Date()) {
message.status = MessageStatus.EXPIRED
continue
}
this.deliverMessage(message)
}
}
/**
* 清理过期消息
*/
private cleanupExpiredMessages(): void {
const now = new Date()
for (const [queueKey, messages] of this.messageQueue.entries()) {
const validMessages = messages.filter((msg) => !msg.expiresAt || msg.expiresAt > now)
if (validMessages.length !== messages.length) {
this.messageQueue.set(queueKey, validMessages)
}
}
}
/**
* 记录消息历史
*/
private recordMessage(message: EventMessage): void {
// 记录发送者历史
if (!this.messageHistory.has(message.senderId)) {
this.messageHistory.set(message.senderId, [])
}
this.messageHistory.get(message.senderId)!.push(message)
// 记录接收者历史
if (message.receiverId && message.receiverId !== message.senderId) {
if (!this.messageHistory.has(message.receiverId)) {
this.messageHistory.set(message.receiverId, [])
}
this.messageHistory.get(message.receiverId)!.push(message)
}
}
/**
* 更新活跃订阅者数量
*/
private updateActiveSubscribersCount(): void {
this.statistics.activeSubscribers = Array.from(this.subscribers.values()).filter(
(sub) => sub.active
).length
}
}

View File

@@ -1,16 +1,11 @@
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { EventBuilderImpl } from '@/events/impl/EventBuilderImpl' import { EventBuilderImpl } from '@/events/impl/EventBuilderImpl'
import type { IEventBuilder } from '@/events/IEventBuilder' import type { IEventBuilder, IEventMap, WindowFormDataUpdateParams } from '@/events/IEventBuilder'
import type {
EventCommunicationEvents,
WindowFormDataUpdateParams
} from './EventCommunicationService'
import type { ResourceType } from './ResourceService' import type { ResourceType } from './ResourceService'
// 导入所有服务 // 导入所有服务
import { WindowService } from './WindowService' import { WindowService } from './WindowService'
import { ResourceService } from './ResourceService' import { ResourceService } from './ResourceService'
import { EventCommunicationService } from './EventCommunicationService'
import { ApplicationSandboxEngine } from './ApplicationSandboxEngine' import { ApplicationSandboxEngine } from './ApplicationSandboxEngine'
import { ApplicationLifecycleManager } from './ApplicationLifecycleManager' import { ApplicationLifecycleManager } from './ApplicationLifecycleManager'
import { externalAppDiscovery } from './ExternalAppDiscovery' import { externalAppDiscovery } from './ExternalAppDiscovery'
@@ -33,7 +28,6 @@ export interface SystemStatus {
servicesStatus: { servicesStatus: {
windowService: boolean // 窗体服务是否启动 windowService: boolean // 窗体服务是否启动
resourceService: boolean // 资源服务是否启动 resourceService: boolean // 资源服务是否启动
eventService: boolean // 事件服务是否启动
sandboxEngine: boolean // 沙箱引擎是否启动 sandboxEngine: boolean // 沙箱引擎是否启动
lifecycleManager: boolean // 生命周期管理器是否启动 lifecycleManager: boolean // 生命周期管理器是否启动
} }
@@ -62,10 +56,9 @@ export class SystemServiceIntegration {
private startTime: Date private startTime: Date
// 核心服务实例 // 核心服务实例
private eventBus: IEventBuilder<EventCommunicationEvents> private eventBus: IEventBuilder<any>
private windowService!: WindowService private windowService!: WindowService
private resourceService!: ResourceService private resourceService!: ResourceService
private eventService!: EventCommunicationService
private sandboxEngine!: ApplicationSandboxEngine private sandboxEngine!: ApplicationSandboxEngine
private lifecycleManager!: ApplicationLifecycleManager private lifecycleManager!: ApplicationLifecycleManager
@@ -76,7 +69,6 @@ export class SystemServiceIntegration {
servicesStatus: { servicesStatus: {
windowService: false, windowService: false,
resourceService: false, resourceService: false,
eventService: false,
sandboxEngine: false, sandboxEngine: false,
lifecycleManager: false lifecycleManager: false
}, },
@@ -96,7 +88,7 @@ export class SystemServiceIntegration {
} }
this.startTime = new Date() this.startTime = new Date()
this.eventBus = new EventBuilderImpl<EventCommunicationEvents>() this.eventBus = new EventBuilderImpl<any>()
this.setupGlobalErrorHandling() this.setupGlobalErrorHandling()
} }
@@ -104,7 +96,7 @@ export class SystemServiceIntegration {
/** /**
* 初始化系统服务 * 初始化系统服务
*/ */
async initialize(): Promise<void> { private async initialize(): Promise<void> {
if (this.initialized.value) { if (this.initialized.value) {
throw new Error('系统服务已初始化') throw new Error('系统服务已初始化')
} }
@@ -138,12 +130,6 @@ export class SystemServiceIntegration {
this.systemStatus.running = true this.systemStatus.running = true
console.log('系统服务初始化完成') console.log('系统服务初始化完成')
// 发送系统就绪事件
this.eventService.sendMessage('system', 'system-ready', {
timestamp: new Date(),
services: Object.keys(this.systemStatus.servicesStatus)
})
} catch (error) { } catch (error) {
console.error('系统服务初始化失败:', error) console.error('系统服务初始化失败:', error)
this.systemStatus.lastError = error instanceof Error ? error.message : String(error) this.systemStatus.lastError = error instanceof Error ? error.message : String(error)
@@ -174,14 +160,6 @@ export class SystemServiceIntegration {
return this.resourceService return this.resourceService
} }
/**
* 获取事件服务
*/
getEventService(): EventCommunicationService {
this.checkInitialized()
return this.eventService
}
/** /**
* 获取沙箱引擎 * 获取沙箱引擎
*/ */
@@ -243,7 +221,7 @@ export class SystemServiceIntegration {
/** /**
* 关闭系统服务 * 关闭系统服务
*/ */
async shutdown(): Promise<void> { private async shutdown(): Promise<void> {
console.log('关闭系统服务...') console.log('关闭系统服务...')
this.running.value = false this.running.value = false
@@ -277,10 +255,6 @@ export class SystemServiceIntegration {
this.sandboxEngine.destroy() this.sandboxEngine.destroy()
} }
if (this.eventService) {
this.eventService.destroy()
}
if (this.windowService) { if (this.windowService) {
// 关闭所有窗体 // 关闭所有窗体
const windows = this.windowService.getAllWindows() const windows = this.windowService.getAllWindows()
@@ -307,11 +281,6 @@ export class SystemServiceIntegration {
this.resourceService = new ResourceService(this.eventBus) this.resourceService = new ResourceService(this.eventBus)
this.systemStatus.servicesStatus.resourceService = true this.systemStatus.servicesStatus.resourceService = true
// 2. 初始化事件通信服务
console.log('初始化事件通信服务...')
this.eventService = new EventCommunicationService(this.eventBus)
this.systemStatus.servicesStatus.eventService = true
// 3. 初始化窗体服务 // 3. 初始化窗体服务
console.log('初始化窗体服务...') console.log('初始化窗体服务...')
this.windowService = new WindowService(this.eventBus) this.windowService = new WindowService(this.eventBus)
@@ -319,7 +288,7 @@ export class SystemServiceIntegration {
// 4. 初始化沙箱引擎 // 4. 初始化沙箱引擎
console.log('初始化沙箱引擎...') console.log('初始化沙箱引擎...')
this.sandboxEngine = new ApplicationSandboxEngine(this.resourceService, this.eventService) this.sandboxEngine = new ApplicationSandboxEngine(this.resourceService)
this.systemStatus.servicesStatus.sandboxEngine = true this.systemStatus.servicesStatus.sandboxEngine = true
// 5. 初始化生命周期管理器 // 5. 初始化生命周期管理器
@@ -327,7 +296,6 @@ export class SystemServiceIntegration {
this.lifecycleManager = new ApplicationLifecycleManager( this.lifecycleManager = new ApplicationLifecycleManager(
this.windowService, this.windowService,
this.resourceService, this.resourceService,
this.eventService,
this.sandboxEngine this.sandboxEngine
) )
this.systemStatus.servicesStatus.lifecycleManager = true this.systemStatus.servicesStatus.lifecycleManager = true
@@ -337,16 +305,6 @@ export class SystemServiceIntegration {
* 设置服务间通信 * 设置服务间通信
*/ */
private setupServiceCommunication(): void { private setupServiceCommunication(): void {
// 监听应用生命周期事件
this.eventService.subscribe('system', 'app-lifecycle', (message) => {
this.debugLog('[AppLifecycle] 应用生命周期事件:', message.payload)
})
// 监听窗口状态变化事件
this.eventService.subscribe('system', 'window-state-change', (message) => {
this.debugLog('[WindowState] 窗口状态变化消息已处理:', message.payload)
})
// 监听窗体状态变化(来自 WindowService 的 onStateChange 事件) // 监听窗体状态变化(来自 WindowService 的 onStateChange 事件)
this.eventBus.addEventListener( this.eventBus.addEventListener(
'onWindowStateChanged', 'onWindowStateChanged',
@@ -354,12 +312,6 @@ export class SystemServiceIntegration {
console.log( console.log(
`[SystemIntegration] 接收到窗体状态变化事件: ${windowId} ${oldState} -> ${newState}` `[SystemIntegration] 接收到窗体状态变化事件: ${windowId} ${oldState} -> ${newState}`
) )
this.eventService.sendMessage('system', 'window-state-change', {
windowId,
newState,
oldState
})
console.log(`[SystemIntegration] 已发送 window-state-change 消息到事件通信服务`)
} }
) )
@@ -384,13 +336,11 @@ export class SystemServiceIntegration {
// 监听窗体数据更新事件 // 监听窗体数据更新事件
this.eventBus.addEventListener('onWindowFormDataUpdate', (data: WindowFormDataUpdateParams) => { this.eventBus.addEventListener('onWindowFormDataUpdate', (data: WindowFormDataUpdateParams) => {
console.log(`[SystemIntegration] 接收到窗体数据更新事件:`, data) console.log(`[SystemIntegration] 接收到窗体数据更新事件:`, data)
this.eventService.sendMessage('system', 'window-form-data-update', data)
}) })
// 监听窗体调整尺寸开始事件 // 监听窗体调整尺寸开始事件
this.eventBus.addEventListener('onWindowFormResizeStart', (windowId: string) => { this.eventBus.addEventListener('onWindowFormResizeStart', (windowId: string) => {
console.log(`[SystemIntegration] 接收到窗体调整尺寸开始事件: ${windowId}`) console.log(`[SystemIntegration] 接收到窗体调整尺寸开始事件: ${windowId}`)
this.eventService.sendMessage('system', 'window-form-resize-start', { windowId })
}) })
// 监听窗体调整尺寸过程中事件 // 监听窗体调整尺寸过程中事件
@@ -401,18 +351,12 @@ export class SystemServiceIntegration {
width, width,
height height
}) })
this.eventService.sendMessage('system', 'window-form-resizing', {
windowId,
width,
height
})
} }
) )
// 监听窗体调整尺寸结束事件 // 监听窗体调整尺寸结束事件
this.eventBus.addEventListener('onWindowFormResizeEnd', (windowId: string) => { this.eventBus.addEventListener('onWindowFormResizeEnd', (windowId: string) => {
console.log(`[SystemIntegration] 接收到窗体调整尺寸结束事件: ${windowId}`) console.log(`[SystemIntegration] 接收到窗体调整尺寸结束事件: ${windowId}`)
this.eventService.sendMessage('system', 'window-form-resize-end', { windowId })
}) })
} }
@@ -677,35 +621,7 @@ export class SystemServiceIntegration {
* 执行事件相关方法 * 执行事件相关方法
*/ */
private async executeEventMethod(action: string, data: any, appId: string): Promise<any> { private async executeEventMethod(action: string, data: any, appId: string): Promise<any> {
switch (action) { throw new Error('事件服务已被移除')
case 'emit':
return this.eventService.sendMessage(appId, data.channel, data.data)
case 'on':
return this.eventService.subscribe(appId, data.channel, (message) => {
// 发送事件到应用
const app = this.lifecycleManager.getApp(appId)
if (app?.sandboxId) {
this.sandboxEngine.sendMessage(app.sandboxId, {
type: 'system:event',
subscriptionId: data.subscriptionId,
message
})
}
})
case 'off':
return this.eventService.unsubscribe(data.subscriptionId)
case 'broadcast':
return this.eventService.broadcast(appId, data.channel, data.data)
case 'sendTo':
return this.eventService.sendCrossAppMessage(appId, data.targetAppId, data.data)
default:
throw new Error(`未知的事件操作: ${action}`)
}
} }
/** /**
@@ -794,11 +710,16 @@ export class SystemServiceIntegration {
* 开始自动清理 * 开始自动清理
*/ */
private startAutoCleanup(): void { private startAutoCleanup(): void {
if (!this.config.cleanupInterval) return
this.cleanupInterval = setInterval(() => { this.cleanupInterval = setInterval(() => {
this.debugLog('执行自动清理...') this.debugLog('执行自动清理...')
// 清理事件服务 // 移除资源服务清理(方法不存在)
this.eventService.cleanup() // this.resourceService.cleanup()
// 移除事件服务清理
// this.eventService.cleanup()
// 清理沙箱引擎缓存 // 清理沙箱引擎缓存
// this.sandboxEngine.cleanup() // this.sandboxEngine.cleanup()

View File

@@ -1,17 +1,8 @@
<template> <template>
<div class="window-manager"> <div class="window-manager">
<!-- 所有已打开的内置应用窗口 --> <!-- 所有已打开的内置应用窗口 -->
<teleport <teleport v-for="window in builtInWindows" :key="window.id" :to="`#app-container-${window.appId}`">
v-for="window in builtInWindows" <component :is="window.component" :key="window.id" v-bind="window.props" @close="closeWindow(window.id)" />
:key="window.id"
:to="`#app-container-${window.appId}`"
>
<component
:is="window.component"
:key="window.id"
v-bind="window.props"
@close="closeWindow(window.id)"
/>
</teleport> </teleport>
</div> </div>
</template> </template>
@@ -84,7 +75,7 @@ const closeWindow = (windowId: string) => {
const window = builtInWindows.value[index] const window = builtInWindows.value[index]
builtInWindows.value.splice(index, 1) builtInWindows.value.splice(index, 1)
console.log(`[WindowManager] 关闭内置应用窗口: ${window.appId} (${windowId})`) console.log(`[WindowManager] 关闭内置应用窗口: ${window.appId} (${windowId})`)
// 通知系统服务关闭窗口 // 通知系统服务关闭窗口
if (systemService) { if (systemService) {
const windowService = systemService.getWindowService() const windowService = systemService.getWindowService()
@@ -103,37 +94,39 @@ const removeBuiltInWindow = (windowId: string) => {
} }
} }
// 监听窗口事件 // 移除事件监听相关代码
let eventUnsubscriber: (() => void) | null = null // let eventUnsubscriber: (() => void) | null = null
onMounted(() => { // onMounted(() => {
if (systemService) { // 移除事件服务相关代码
const eventService = systemService.getEventService() // if (systemService) {
// const eventService = systemService.getEventService()
// 监听内置应用窗口创建事件
const subscriberId = eventService.subscribe('system', 'built-in-window-created', async (message) => {
const { windowId, appId } = message.payload
await addBuiltInWindow(windowId, appId)
})
// 监听内置应用窗口关闭事件
const closeSubscriberId = eventService.subscribe('system', 'built-in-window-closed', (message) => {
const { windowId } = message.payload
removeBuiltInWindow(windowId)
})
eventUnsubscriber = () => {
eventService.unsubscribe(subscriberId)
eventService.unsubscribe(closeSubscriberId)
}
}
})
onUnmounted(() => { // // 监听内置应用窗口创建事件
if (eventUnsubscriber) { // const subscriberId = eventService.subscribe('system', 'built-in-window-created', async (message) => {
eventUnsubscriber() // const { windowId, appId } = message.payload
} // await addBuiltInWindow(windowId, appId)
}) // })
// // 监听内置应用窗口关闭事件
// const closeSubscriberId = eventService.subscribe('system', 'built-in-window-closed', (message) => {
// const { windowId } = message.payload
// removeBuiltInWindow(windowId)
// })
// eventUnsubscriber = () => {
// eventService.unsubscribe(subscriberId)
// eventService.unsubscribe(closeSubscriberId)
// }
// }
// })
// onUnmounted(() => {
// 移除事件服务相关代码
// if (eventUnsubscriber) {
// eventUnsubscriber()
// }
// })
// 暴露给全局使用 // 暴露给全局使用
defineExpose({ defineExpose({

View File

@@ -52,7 +52,6 @@ const systemStatus = ref<SystemStatus>({
servicesStatus: { servicesStatus: {
windowService: false, windowService: false,
resourceService: false, resourceService: false,
eventService: false,
sandboxEngine: false, sandboxEngine: false,
lifecycleManager: false lifecycleManager: false
}, },