UNPKG

filecoin-pin

Version:

Bridge IPFS content to Filecoin Onchain Cloud using familiar tools

121 lines 6.2 kB
/** * Helper: createStorageContextFromDataSetId * * Optimized helper to create a StorageContext for an existing dataset ID without * triggering the expensive "scan all client datasets" hotpath. * * This is a workaround for https://github.com/FilOzone/synapse-sdk/issues/435 * until https://github.com/FilOzone/synapse-sdk/pull/438 is merged and published. * * Benefits: * - Reuses Synapse's existing WarmStorageService (no extra initialization) * - Only fetches data for the single dataset needed (~5-6 RPC calls vs 1500+) * - Validates ownership, isLive, and isManaged * * TODO: Replace with synapse.storage.createContextFromDataSetId() once PR #438 is published */ import { StorageContext } from '@filoz/synapse-sdk'; import { SPRegistryService } from '@filoz/synapse-sdk/sp-registry'; import { DEFAULT_DATA_SET_METADATA, DEFAULT_STORAGE_CONTEXT_CONFIG } from './index.js'; /** * Create a StorageContext for an existing dataSetId without scanning all datasets. */ export async function createStorageContextFromDataSetId(synapse, dataSetId, options) { const { checkProviderApproval = false } = options ?? {}; // Access Synapse's internal WarmStorageService (avoids creating a new one) // @ts-expect-error - Accessing private _warmStorageService temporarily until SDK is updated const warmStorage = synapse.storage._warmStorageService; if (!warmStorage) { throw new Error('WarmStorageService not available on Synapse instance'); } // Get basic dataset info and validate in parallel const [dataSetInfo] = await Promise.all([warmStorage.getDataSet(dataSetId), warmStorage.validateDataSet(dataSetId)]); // Verify ownership const signerAddress = await synapse.getClient().getAddress(); if (dataSetInfo.payer.toLowerCase() !== signerAddress.toLowerCase()) { throw new Error(`Data set ${dataSetId} is not owned by ${signerAddress} (owned by ${dataSetInfo.payer})`); } const registryAddress = warmStorage.getServiceProviderRegistryAddress(); const spRegistry = new SPRegistryService(synapse.getProvider(), registryAddress); if (checkProviderApproval) { /** * If asked to check provider approval and it's not an approved provider, we're going to throw an error. */ const isProviderApproved = await warmStorage.isProviderIdApproved(dataSetInfo.providerId); if (!isProviderApproved) { throw new Error(`Data set ${dataSetId} is not owned by an approved provider`); } } // Get provider info and metadata in parallel const [providerInfo, dataSetMetadata] = await Promise.all([ spRegistry.getProvider(dataSetInfo.providerId), warmStorage.getDataSetMetadata(dataSetId), ]); if (providerInfo == null) { throw new Error(`Unable to resolve provider info for data set ${dataSetId} and provider ${dataSetInfo.providerId}`); } // Construct storage context directly const withCDN = dataSetInfo.cdnRailId > 0; const storageContext = new StorageContext(synapse, warmStorage, providerInfo, dataSetId, { withCDN }, dataSetMetadata); return { storage: storageContext, providerInfo, }; } /** * Create a StorageContext configured for creating a brand new dataset without scanning all * existing datasets. Provider selection favors explicit overrides and otherwise randomly selects * an active provider that exposes a PDP endpoint. */ export async function createStorageContextForNewDataSet(synapse, options = {}) { // @ts-expect-error - Accessing private _warmStorageService temporarily until SDK is updated const warmStorage = options.warmStorage ?? synapse.storage._warmStorageService; if (!warmStorage) { throw new Error('WarmStorageService not available on Synapse instance'); } const registryAddress = warmStorage.getServiceProviderRegistryAddress(); const spRegistry = options.spRegistry ?? new SPRegistryService(synapse.getProvider(), registryAddress); const providerInfo = await getApprovedProviderInfo(warmStorage, spRegistry, options.providerId, options.logger); const mergedMetadata = { ...DEFAULT_DATA_SET_METADATA }; const storageOptions = { ...DEFAULT_STORAGE_CONTEXT_CONFIG, metadata: mergedMetadata, }; const storageContext = new StorageContext(synapse, warmStorage, providerInfo, undefined, storageOptions, mergedMetadata); return { storage: storageContext, providerInfo, }; } /** * getApprovedProviderInfo should only be called from createStorageContextForNewDataSet, which is only called with a providerId if a user has explicitly provided one as a query parameter. */ async function getApprovedProviderInfo(warmStorage, spRegistry, providerId, logger) { let providerInfo = null; if (providerId != null) { // if given a providerId, check if it is approved and log a warning if it's not an approved provider. const isProviderApproved = await warmStorage.isProviderIdApproved(providerId); if (!isProviderApproved) { logger?.warn({ providerId }, `Presuming given providerId ${providerId} is a queryParam and allowing creation to continue with a non-approved provider`); } providerInfo = await spRegistry.getProvider(providerId); } else { // otherwise, get all approved provider ids and randomly select one. const approvedProviderIds = await warmStorage.getApprovedProviderIds(); // select a random approved provider id const randomApprovedProviderId = pickRandom(approvedProviderIds); providerInfo = await spRegistry.getProvider(randomApprovedProviderId); } if (providerInfo == null) { throw new Error(`Unable to resolve an approved storage provider for new data set creation`); } return providerInfo; } function pickRandom(providerIds) { if (providerIds.length === 0) throw new Error('No approved storage providers available for new data set creation'); return providerIds[Math.floor(Math.random() * providerIds.length)]; } export default createStorageContextFromDataSetId; //# sourceMappingURL=storage-context-helper.js.map