From a23386456c96f9ff1d3fb71c73a532356ce54c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Vi=C3=A9not?= Date: Mon, 25 Nov 2024 16:14:53 +0100 Subject: [PATCH] chore: refactor ipfs config and metadata retrieval (#1517) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Viénot --- CONFIGURATION.md | 6 +- public/core-config.json | 2 +- src/components/token/NftCell.vue | 2 +- src/components/token/TokenMetadataAnalyzer.ts | 54 ++++-------- src/components/values/BlobValue.vue | 56 ++---------- src/config/CoreConfig.ts | 6 +- src/pages/NftDetails.vue | 2 +- src/pages/TokenDetails.vue | 2 +- src/utils/URLUtils.ts | 86 +++++++++++++++++++ tests/unit/values/BlobValue.spec.ts | 7 +- 10 files changed, 122 insertions(+), 101 deletions(-) create mode 100644 src/utils/URLUtils.ts diff --git a/CONFIGURATION.md b/CONFIGURATION.md index ccabea6bd..2bdb88901 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -31,7 +31,7 @@ The following configuration parameters can be set in `core-config.json`: | `estimatorNotice` | `string` | No estimator notice is displayed | | | `walletChooserDisclaimerPopup` | `string` | No wallet chooser disclaimer popup is displayed | | | `googleTagID` | `string` | Google Tag is disabled | | -| `ipfsGatewayUrlPrefix` | `string` | Gateway `https://gateway.pinata.cloud/ipfs/` is used | | +| `ipfsGatewayURL` | `string` | Gateway `https://gateway.pinata.cloud/ipfs/` is used | | | `cryptoName` | `string` | `HBAR` is displayed | | | `cryptoSymbol` | `string` | `` is displayed | | @@ -100,8 +100,8 @@ This provides the global site tag ID to be used by Google Analytics. When specif dialog asking the user to agree to the use of cookies before proceeding with the application. The google tag ID will be actually used only if the user has agreed. -### `ipfsGatewayUrlPrefix` -This provides the URL prefix of the public IPFS gateway to use to resolve the IPFS URLs used in the token metadata. +### `ipfsGatewayURL` +This provides the URL of the public IPFS gateway to use to resolve the IPFS URIs (or CIDs) used in the token metadata. By default the Pinata public IPFS gateway is used. ### `cryptoName` diff --git a/public/core-config.json b/public/core-config.json index aafc91a77..2f4f70cab 100644 --- a/public/core-config.json +++ b/public/core-config.json @@ -13,7 +13,7 @@ "estimatorNotice": null, "walletChooserDisclaimerPopup": null, "googleTagID": null, - "ipfsGatewayUrlPrefix": null, + "ipfsGatewayURL": null, "cryptoName": null, "cryptoSymbol": null } diff --git a/src/components/token/NftCell.vue b/src/components/token/NftCell.vue index a855a43f5..3ff6b8a62 100644 --- a/src/components/token/NftCell.vue +++ b/src/components/token/NftCell.vue @@ -91,7 +91,7 @@ export default defineComponent({ onMounted(() => nftLookup.mount()) onBeforeUnmount(() => nftLookup.unmount()) - const ipfsGatewayPrefix = CoreConfig.inject().ipfsGatewayUrlPrefix + const ipfsGatewayPrefix = CoreConfig.inject().ipfsGatewayURL const metadata = computed(() => nftLookup.entity.value?.metadata ?? '') const metadataAnalyzer = new TokenMetadataAnalyzer(metadata, ipfsGatewayPrefix) onMounted(() => metadataAnalyzer.mount()) diff --git a/src/components/token/TokenMetadataAnalyzer.ts b/src/components/token/TokenMetadataAnalyzer.ts index 9a3a3a9d7..1db259301 100644 --- a/src/components/token/TokenMetadataAnalyzer.ts +++ b/src/components/token/TokenMetadataAnalyzer.ts @@ -19,13 +19,12 @@ */ import {computed, ref, Ref, watch, WatchStopHandle} from "vue"; -import {EntityID} from "@/utils/EntityID"; import axios from "axios"; import {Timestamp} from "@/utils/Timestamp"; import {TopicMessageCache} from "@/utils/cache/TopicMessageCache"; -import {CID} from "multiformats"; import {AssetCache} from "@/utils/cache/AssetCache.ts"; import {LastTopicMessageByIdCache} from "@/utils/cache/LastTopicMessageByIdCache.ts"; +import {blob2Topic, blob2URL} from "@/utils/URLUtils.ts"; export interface NftAttribute { trait_type: string @@ -54,9 +53,9 @@ export class TokenMetadataAnalyzer { // public readonly rawMetadata: Ref - public readonly ipfsGatewayPrefix: string + public readonly ipfsGatewayPrefix: string | null - public constructor(rawMetadata: Ref, ipfsGatewayPrefix: string) { + public constructor(rawMetadata: Ref, ipfsGatewayPrefix: string | null) { this.rawMetadata = rawMetadata this.ipfsGatewayPrefix = ipfsGatewayPrefix } @@ -153,14 +152,8 @@ export class TokenMetadataAnalyzer { const files = this.getProperty('files') if (Array.isArray(files)) { for (const file of files) { - if (file.uri != undefined && file.type != undefined) { - let url - if (file.uri.startsWith("ipfs://") && file.uri.length > 7) { - url = `${this.ipfsGatewayPrefix}${file.uri.substring(7)}` - } else { - url = file.uri - } - + if (file.uri && file.type) { // both required by HIP-412 + const url = blob2URL(file.uri, this.ipfsGatewayPrefix) ?? file.uri result.push({ uri: file.uri, url: url, @@ -196,12 +189,8 @@ export class TokenMetadataAnalyzer { public imageUrl = computed( () => { - let result = this.getProperty('image') ?? this.getProperty(('picture')) - - if (result != null && result.startsWith("ipfs://") && result.length > 7) { - result = `${this.ipfsGatewayPrefix}${result.substring(7)}` - } - return result + const uri = this.getProperty('image') ?? this.getProperty(('picture')) + return blob2URL(uri, this.ipfsGatewayPrefix) ?? uri }) // @@ -245,27 +234,16 @@ export class TokenMetadataAnalyzer { } if (metadata.value !== null) { - if (metadata.value.startsWith('ipfs://')) { - content.value = await this.readMetadataFromUrl(`${this.ipfsGatewayPrefix}${metadata.value.substring(7)}`) - } else if (metadata.value.startsWith('hcs://')) { - const i = metadata.value.lastIndexOf('/'); - const id = metadata.value.substring(i + 1); - if (EntityID.parse(id) !== null) { - content.value = await this.readMetadataFromTopic(id) - } else { - content.value = null - } - } else if (metadata.value.startsWith('https://')) { - content.value = await this.readMetadataFromUrl(metadata.value) - } else if (EntityID.parse(metadata.value) !== null) { - content.value = await this.readMetadataFromTopic(metadata.value) - } else if (Timestamp.parse(metadata.value) !== null) { - content.value = await this.readMetadataFromTimestamp(metadata.value) + const url = blob2URL(metadata.value, this.ipfsGatewayPrefix) + if (url !== null) { + content.value = await this.readMetadataFromUrl(url) } else { - try { - CID.parse(metadata.value) - content.value = await this.readMetadataFromUrl(`${this.ipfsGatewayPrefix}${metadata.value}`) - } catch { + const topic = blob2Topic(metadata.value) + if (topic !== null) { + content.value = await this.readMetadataFromTopic(topic) + } else if (Timestamp.parse(metadata.value) !== null) { + content.value = await this.readMetadataFromTimestamp(metadata.value) + } else { content.value = null } } diff --git a/src/components/values/BlobValue.vue b/src/components/values/BlobValue.vue index 18aaea569..67350e59e 100644 --- a/src/components/values/BlobValue.vue +++ b/src/components/values/BlobValue.vue @@ -25,21 +25,11 @@