Files
SecScore/.copying/hosting/hostApplication.ts
T
Yukino_fox 18eada8ff3 feat: 实现依赖注入系统、插件架构和窗口管理
- 引入ExamAware的DI系统并适配SecScore项目
- 添加服务注册表和窗口管理器
- 实现基于Koishi的Disposable设计的插件系统
- 集成Winston日志服务
- 分离设置窗口为独立页面
- 将非核心功能改为内置插件
- 更新README文件
- 添加相关hooks和工具函数
2026-04-26 19:39:56 +08:00

185 lines
5.2 KiB
TypeScript

import type {
ConfigureHostDelegate,
HostBuilderContext,
HostExposure,
HostedService,
PluginHostApplicationContext,
PluginMiddleware,
ServiceToken,
} from "./types"
import { ServiceProvider } from "./serviceCollection"
// 插件Host应用类,管理应用的生命周期和托管服务
export class PluginHostApplication {
private hostedInstances: HostedService[] = [] // 已启动的托管服务实例
private hostDisposers: Array<() => void> = [] // 清理函数列表
private started = false // 是否已启动
constructor(
private readonly context: HostBuilderContext, // Host构建器上下文
private readonly provider: ServiceProvider, // 服务提供者
private readonly configureDelegates: ConfigureHostDelegate[], // 配置委托
private readonly middleware: PluginMiddleware[], // 中间件
private readonly hostedTokens: ServiceToken<HostedService>[] // 托管服务令牌
) {}
// 包装应用,添加服务暴露功能
withExposures(exposures: HostExposure[]): PluginHostApplicationWithExposures {
return new PluginHostApplicationWithExposures(this, exposures)
}
// 启动应用
async start(): Promise<void> {
if (this.started) return
const appCtx = this.createApplicationContext() // 创建应用上下文
// 执行所有配置委托
for (const configure of this.configureDelegates) {
await configure(this.context, appCtx)
}
// 通过中间件管道执行终端逻辑(启动托管服务)
await this.dispatch(0, appCtx, async () => {
await this.bootstrapHostedServices()
})
this.started = true
await this.context.lifetime.notifyStarted() // 通知生命周期已启动
}
// 停止应用
async stop(): Promise<void> {
if (!this.started) return
await this.context.lifetime.notifyStopping() // 通知正在停止
await this.disposeHostedServices() // 停止托管服务
await this.context.lifetime.notifyStopped() // 通知已停止
this.started = false
}
// 释放资源
async dispose(): Promise<void> {
await this.stop()
await this.provider.dispose() // 释放服务提供者
}
// 获取服务提供者
get services(): ServiceProvider {
return this.provider
}
// 获取Host上下文
get hostContext(): HostBuilderContext {
return this.context
}
// 创建应用上下文
private createApplicationContext(): PluginHostApplicationContext {
return {
ctx: this.context.ctx,
services: this.provider,
host: this.context,
}
}
// 启动所有托管服务
private async bootstrapHostedServices() {
for (const token of this.hostedTokens) {
const service = this.provider.get(token) // 从提供者获取服务实例
this.hostedInstances.push(service)
if (typeof service.start === "function") {
await service.start() // 调用启动方法
}
}
}
// 停止所有托管服务
private async disposeHostedServices() {
while (this.hostedInstances.length) {
const service = this.hostedInstances.pop()
if (!service) continue
if (typeof service.stop === "function") {
await service.stop() // 调用停止方法
}
}
}
// 执行中间件管道
private async dispatch(
index: number,
appCtx: PluginHostApplicationContext,
terminal: () => Promise<void>
) {
const middleware = this.middleware[index]
if (!middleware) {
await terminal() // 执行终端逻辑
return
}
// 调用中间件,传入下一个中间件的执行函数
await middleware(appCtx, () => this.dispatch(index + 1, appCtx, terminal))
}
}
// 带服务暴露的Host应用类
export class PluginHostApplicationWithExposures {
private readonly exposureDisposers: Array<() => void> = [] // 暴露服务的清理函数
constructor(
private readonly app: PluginHostApplication,
private readonly exposures: HostExposure[]
) {}
// 启动应用,包括注册暴露服务
async start(): Promise<void> {
try {
await this.registerExposures() // 先注册暴露服务
await this.app.start() // 再启动应用
} catch (error) {
await this.disposeExposures() // 出错时清理暴露服务
throw error
}
}
// 停止应用,包括清理暴露服务
async stop(): Promise<void> {
await this.app.stop()
await this.disposeExposures()
}
// 释放资源
async dispose(): Promise<void> {
await this.app.dispose()
await this.disposeExposures()
}
// 获取服务提供者
get services() {
return this.app.services
}
// 获取Host上下文
get hostContext() {
return this.app.hostContext
}
// 注册暴露的服务到插件上下文
private async registerExposures() {
const ctx = this.app.hostContext.ctx
if (!ctx.services) return
for (const exposure of this.exposures) {
const value = exposure.resolver(this.app.services) // 解析服务值
const disposer = ctx.services.provide(exposure.name, value) // 注册到服务API
this.exposureDisposers.push(disposer)
}
}
// 清理暴露的服务
private async disposeExposures() {
while (this.exposureDisposers.length) {
const dispose = this.exposureDisposers.pop()
if (!dispose) continue
await dispose() // 调用清理函数
}
}
}