From aff42a9e47edb4149fa50ff575cb648b79bb233f Mon Sep 17 00:00:00 2001 From: Jin Yi Date: Sun, 27 Jul 2025 08:06:09 +0900 Subject: [PATCH] [Manager] Optimize conflict detection with bulk API and version support (#4538) --- src/composables/nodePack/useInstalledPacks.ts | 18 +++++ src/composables/useConflictDetection.ts | 76 +++++++++++-------- src/services/comfyRegistryService.ts | 52 ++++++++++++- 3 files changed, 112 insertions(+), 34 deletions(-) diff --git a/src/composables/nodePack/useInstalledPacks.ts b/src/composables/nodePack/useInstalledPacks.ts index 60e6f5fdd..87d9972d0 100644 --- a/src/composables/nodePack/useInstalledPacks.ts +++ b/src/composables/nodePack/useInstalledPacks.ts @@ -36,11 +36,29 @@ export const useInstalledPacks = (options: UseNodePacksOptions = {}) => { cleanup() }) + // Create a computed property that provides installed pack info with versions + const installedPacksWithVersions = computed(() => { + const result: Array<{ id: string; version: string }> = [] + + for (const pack of Object.values(comfyManagerStore.installedPacks)) { + const id = pack.cnr_id || pack.aux_id + if (id) { + result.push({ + id, + version: pack.ver + }) + } + } + + return result + }) + return { error, isLoading, isReady, installedPacks: nodePacks, + installedPacksWithVersions, startFetchInstalled, filterInstalledPack } diff --git a/src/composables/useConflictDetection.ts b/src/composables/useConflictDetection.ts index e0ac41207..e94c384ed 100644 --- a/src/composables/useConflictDetection.ts +++ b/src/composables/useConflictDetection.ts @@ -40,6 +40,7 @@ export function useConflictDetection() { const { startFetchInstalled, installedPacks, + installedPacksWithVersions, isReady: installedPacksReady } = useInstalledPacks() @@ -203,58 +204,67 @@ export function useConflictDetection() { return [] } - // Step 2: Get Registry service for individual API calls + // Step 2: Get Registry service for bulk API calls const registryService = useComfyRegistryService() // Step 3: Setup abort controller for request cancellation abortController.value = new AbortController() - // Step 4: Fetch version-specific data in chunks to avoid overwhelming the Registry API - // - Each chunk processes up to 30 packages concurrently - // - Results are stored in versionDataMap for later use - // - Use installedPacks from useInstalledPacks composable - const chunkSize = 30 + // Step 4: Use bulk API to fetch all version data in a single request const versionDataMap = new Map< string, components['schemas']['NodeVersion'] >() - for (let i = 0; i < installedPacks.value.length; i += chunkSize) { - const chunk = installedPacks.value.slice(i, i + chunkSize) + // Prepare bulk request with actual installed versions from Manager API + const nodeVersions = installedPacksWithVersions.value.map((pack) => ({ + node_id: pack.id, + version: pack.version + })) - const fetchTasks = chunk.map(async (pack) => { - // Use pack.id which should be the normalized ID from Registry - const packageId = pack.id || '' - const version = pack.latest_version?.version || 'latest' + if (nodeVersions.length > 0) { + try { + const bulkResponse = await registryService.getBulkNodeVersions( + nodeVersions, + abortController.value?.signal + ) - try { - const versionData = await registryService.getPackByVersion( - packageId, - version, - abortController.value?.signal - ) - - if (versionData) { - versionDataMap.set(packageId, versionData) - } - } catch (error) { - console.warn( - `[ConflictDetection] Failed to fetch version data for ${packageId}@${version}:`, - error - ) + if (bulkResponse && bulkResponse.node_versions) { + // Process bulk response + bulkResponse.node_versions.forEach((result) => { + if (result.status === 'success' && result.node_version) { + versionDataMap.set( + result.identifier.node_id, + result.node_version + ) + } else if (result.status === 'error') { + console.warn( + `[ConflictDetection] Failed to fetch version data for ${result.identifier.node_id}@${result.identifier.version}:`, + result.error_message + ) + } + }) } - }) - - await Promise.allSettled(fetchTasks) + } catch (error) { + console.warn( + '[ConflictDetection] Failed to fetch bulk version data:', + error + ) + } } // Step 5: Combine local installation data with Registry version data - // Use installedPacks from useInstalledPacks composable const requirements: NodePackRequirements[] = [] + // Create a map for quick access to version info + const versionInfoMap = new Map( + installedPacksWithVersions.value.map((pack) => [pack.id, pack.version]) + ) + for (const pack of installedPacks.value) { const packageId = pack.id || '' const versionData = versionDataMap.get(packageId) + const installedVersion = versionInfoMap.get(packageId) || 'unknown' // Check if package is enabled using store method const isEnabled = managerStore.isPackEnabled(packageId) @@ -265,7 +275,7 @@ export function useConflictDetection() { // Basic package info package_id: packageId, package_name: pack.name || packageId, - installed_version: pack.latest_version?.version || 'unknown', + installed_version: installedVersion, is_enabled: isEnabled, // Version-specific compatibility data @@ -297,7 +307,7 @@ export function useConflictDetection() { const fallbackRequirement: NodePackRequirements = { package_id: packageId, package_name: pack.name || packageId, - installed_version: pack.latest_version?.version || 'unknown', + installed_version: installedVersion, is_enabled: isEnabled, is_banned: false, registry_fetch_time: new Date().toISOString(), diff --git a/src/services/comfyRegistryService.ts b/src/services/comfyRegistryService.ts index 20b418cfa..0221bd00c 100644 --- a/src/services/comfyRegistryService.ts +++ b/src/services/comfyRegistryService.ts @@ -359,6 +359,55 @@ export const useComfyRegistryService = () => { ) } + /** + * Get multiple pack versions in a single bulk request. + * This is more efficient than making individual requests for each pack version. + * + * @param nodeVersions - Array of node ID and version pairs to retrieve + * @param signal - Optional AbortSignal for request cancellation + * @returns Bulk response containing the requested node versions or null on error + * + * @example + * ```typescript + * const versions = await getBulkNodeVersions([ + * { node_id: 'ComfyUI-Manager', version: '1.0.0' }, + * { node_id: 'ComfyUI-Impact-Pack', version: '2.0.0' } + * ]) + * if (versions) { + * versions.node_versions.forEach(result => { + * if (result.status === 'success' && result.node_version) { + * console.log(`Retrieved ${result.identifier.node_id}@${result.identifier.version}`) + * } + * }) + * } + * ``` + */ + const getBulkNodeVersions = async ( + nodeVersions: components['schemas']['NodeVersionIdentifier'][], + signal?: AbortSignal + ) => { + const endpoint = '/bulk/nodes/versions' + const errorContext = 'Failed to get bulk node versions' + const routeSpecificErrors = { + 400: 'Bad request: Invalid node version identifiers provided' + } + + const requestBody: components['schemas']['BulkNodeVersionsRequest'] = { + node_versions: nodeVersions + } + + return executeApiRequest( + () => + registryApiClient.post< + components['schemas']['BulkNodeVersionsResponse'] + >(endpoint, requestBody, { + signal + }), + errorContext, + routeSpecificErrors + ) + } + return { isLoading, error, @@ -372,6 +421,7 @@ export const useComfyRegistryService = () => { listPacksForPublisher, getNodeDefs, postPackReview, - inferPackFromNodeName + inferPackFromNodeName, + getBulkNodeVersions } }