Files
PromptX/src/lib/core/resource/discovery/DiscoveryManager.js
2025-06-12 16:33:50 +08:00

259 lines
7.6 KiB
JavaScript
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.

const PackageDiscovery = require('./PackageDiscovery')
const ProjectDiscovery = require('./ProjectDiscovery')
/**
* DiscoveryManager - 资源发现管理器
*
* 统一管理多个资源发现器,按照文档架构设计:
* 1. 按优先级排序发现器 (数字越小优先级越高)
* 2. 并行执行资源发现
* 3. 收集并合并所有发现的资源
* 4. 提供容错机制,单个发现器失败不影响整体
*/
class DiscoveryManager {
/**
* 构造函数
* @param {Array} discoveries - 自定义发现器列表,如果不提供则使用默认配置
*/
constructor(discoveries = null) {
if (discoveries) {
this.discoveries = [...discoveries]
} else {
// 默认发现器配置:只包含包级和项目级发现
this.discoveries = [
new PackageDiscovery(), // 优先级: 1
new ProjectDiscovery() // 优先级: 2
]
}
// 按优先级排序
this._sortDiscoveriesByPriority()
}
/**
* 添加发现器
* @param {Object} discovery - 实现了发现器接口的对象
*/
addDiscovery(discovery) {
if (!discovery || typeof discovery.discover !== 'function') {
throw new Error('Discovery must implement discover method')
}
this.discoveries.push(discovery)
this._sortDiscoveriesByPriority()
}
/**
* 移除发现器
* @param {string} source - 发现器源类型
*/
removeDiscovery(source) {
this.discoveries = this.discoveries.filter(discovery => discovery.source !== source)
}
/**
* 发现所有资源(并行模式)
* @returns {Promise<Array>} 所有发现的资源列表
*/
async discoverAll() {
const discoveryPromises = this.discoveries.map(async (discovery) => {
try {
const resources = await discovery.discover()
return Array.isArray(resources) ? resources : []
} catch (error) {
console.warn(`[DiscoveryManager] ${discovery.source} discovery failed: ${error.message}`)
return []
}
})
// 并行执行所有发现器
const discoveryResults = await Promise.allSettled(discoveryPromises)
// 收集所有成功的结果
const allResources = []
discoveryResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
allResources.push(...result.value)
} else {
console.warn(`[DiscoveryManager] ${this.discoveries[index].source} discovery rejected: ${result.reason}`)
}
})
return allResources
}
/**
* 发现并合并所有注册表(新架构方法)
* @returns {Promise<Map>} 合并后的资源注册表 Map<resourceId, reference>
*/
async discoverRegistries() {
const registryPromises = this.discoveries.map(async (discovery) => {
try {
// 优先使用新的discoverRegistry方法
if (typeof discovery.discoverRegistry === 'function') {
const registry = await discovery.discoverRegistry()
return registry instanceof Map ? registry : new Map()
} else {
// 向后兼容将discover()结果转换为注册表格式
const resources = await discovery.discover()
const registry = new Map()
if (Array.isArray(resources)) {
resources.forEach(resource => {
if (resource.id && resource.reference) {
registry.set(resource.id, resource.reference)
}
})
}
return registry
}
} catch (error) {
console.warn(`[DiscoveryManager] ${discovery.source} registry discovery failed: ${error.message}`)
return new Map()
}
})
// 并行执行所有发现器
const registryResults = await Promise.allSettled(registryPromises)
// 收集所有成功的注册表
const registries = []
registryResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
registries.push(result.value)
} else {
console.warn(`[DiscoveryManager] ${this.discoveries[index].source} registry discovery rejected: ${result.reason}`)
registries.push(new Map())
}
})
// 按发现器优先级合并注册表
return this._mergeRegistries(registries)
}
/**
* 按源类型发现注册表
* @param {string} source - 发现器源类型
* @returns {Promise<Map>} 指定源的资源注册表
*/
async discoverRegistryBySource(source) {
const discovery = this._findDiscoveryBySource(source)
if (!discovery) {
throw new Error(`Discovery source ${source} not found`)
}
if (typeof discovery.discoverRegistry === 'function') {
return await discovery.discoverRegistry()
} else {
// 向后兼容将discover()结果转换为注册表格式
const resources = await discovery.discover()
const registry = new Map()
if (Array.isArray(resources)) {
resources.forEach(resource => {
if (resource.id && resource.reference) {
registry.set(resource.id, resource.reference)
}
})
}
return registry
}
}
/**
* 按源类型发现资源
* @param {string} source - 发现器源类型
* @returns {Promise<Array>} 指定源的资源列表
*/
async discoverBySource(source) {
const discovery = this._findDiscoveryBySource(source)
if (!discovery) {
throw new Error(`Discovery source ${source} not found`)
}
return await discovery.discover()
}
/**
* 获取所有发现器信息
* @returns {Array} 发现器信息列表
*/
getDiscoveryInfo() {
return this.discoveries.map(discovery => {
if (typeof discovery.getDiscoveryInfo === 'function') {
return discovery.getDiscoveryInfo()
} else {
return {
source: discovery.source || 'UNKNOWN',
priority: discovery.priority || 0,
description: 'No description available'
}
}
})
}
/**
* 清理所有发现器缓存
*/
clearCache() {
this.discoveries.forEach(discovery => {
if (typeof discovery.clearCache === 'function') {
discovery.clearCache()
}
})
}
/**
* 获取发现器数量
* @returns {number} 注册的发现器数量
*/
getDiscoveryCount() {
return this.discoveries.length
}
/**
* 合并多个注册表
* @param {Array<Map>} registries - 注册表数组,按优先级排序(数字越小优先级越高)
* @returns {Map} 合并后的注册表
* @private
*/
_mergeRegistries(registries) {
const mergedRegistry = new Map()
// 从后往前合并:先添加低优先级的,再让高优先级的覆盖
// registries按优先级升序排列 [high(0), med(1), low(2)]
// 我们从低优先级开始,让高优先级的覆盖
for (let i = registries.length - 1; i >= 0; i--) {
const registry = registries[i]
if (registry instanceof Map) {
for (const [key, value] of registry) {
mergedRegistry.set(key, value) // 直接设置,让高优先级的最终覆盖
}
}
}
return mergedRegistry
}
/**
* 按优先级排序发现器
* @private
*/
_sortDiscoveriesByPriority() {
this.discoveries.sort((a, b) => {
const priorityA = a.priority || 0
const priorityB = b.priority || 0
return priorityA - priorityB // 升序排序,数字越小优先级越高
})
}
/**
* 根据源类型查找发现器
* @param {string} source - 发现器源类型
* @returns {Object|undefined} 找到的发现器或undefined
* @private
*/
_findDiscoveryBySource(source) {
return this.discoveries.find(discovery => discovery.source === source)
}
}
module.exports = DiscoveryManager