Skip to content

Commit 8665596

Browse files
committed
feat: add getIpfsUri function
1 parent aae0ad8 commit 8665596

File tree

2 files changed

+152
-2
lines changed

2 files changed

+152
-2
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
interface IIpfsLink {
2+
Hash: string
3+
Name: string
4+
Size: number
5+
Target: string
6+
Type: number
7+
Mode?: string
8+
Mtime?: number
9+
MtimeNsecs?: number
10+
}
11+
12+
interface IIPfsEntry {
13+
readonly type: 'dir' | 'file'
14+
readonly cid: string
15+
readonly name: string
16+
readonly path: string
17+
mode?: number
18+
mtime?: {
19+
secs: number
20+
nsecs?: number
21+
}
22+
size: number
23+
}
24+
25+
interface IIpfsObject {
26+
Hash: string
27+
Links: IIpfsLink[]
28+
}
29+
30+
enum typeOfLink {
31+
Dir = 'dir',
32+
File = 'file',
33+
}
34+
35+
const IPFS_ENDPOINT = 'https://ipfs.io'
36+
const IPFS_PATH = '/api/v0/ls'
37+
const IPFS_PREFIX = '/ipfs/'
38+
39+
export async function getIpfsUri(link: { path?: string; hash: string }): Promise<string | undefined> {
40+
try {
41+
const slicedLink = link.hash.slice('https://ipfs.io/'.length)
42+
const ipfsEntry = await ls(slicedLink)
43+
if (ipfsEntry) {
44+
if (ipfsEntry.type === 'dir') {
45+
const path = `${link.path ?? ''}/${ipfsEntry.name}`
46+
return await getIpfsUri({ hash: link.hash, path })
47+
}
48+
return `${link.hash}/${encodeURIComponent(ipfsEntry.name)}`
49+
}
50+
} catch (error) {
51+
console.error('error', error)
52+
}
53+
}
54+
55+
async function ls(path: string): Promise<IIPfsEntry | undefined> {
56+
let ipfsEntry: IIPfsEntry | undefined
57+
58+
try {
59+
const baseUrl = IPFS_ENDPOINT
60+
const method = 'get'
61+
const payload = undefined
62+
let headers = {}
63+
const timeout = undefined
64+
65+
headers ??= {}
66+
67+
let controller: AbortController | undefined
68+
let timerId: NodeJS.Timeout | undefined
69+
70+
if (timeout !== undefined) {
71+
controller = new AbortController()
72+
timerId = setTimeout(() => {
73+
if (controller) {
74+
controller.abort()
75+
}
76+
}, timeout)
77+
}
78+
79+
try {
80+
if (path.includes('ipfs')) {
81+
const response = await fetch(`${baseUrl}${IPFS_PATH}?arg=/${path}`, {
82+
method,
83+
headers,
84+
body: payload ? JSON.stringify(payload) : undefined,
85+
signal: controller ? controller.signal : undefined,
86+
})
87+
const lsResponse = (await response.json()) as { Objects: IIpfsObject[] }
88+
const result = lsResponse.Objects[0]
89+
if (result) {
90+
const links = result.Links
91+
if (links.length > 0) {
92+
ipfsEntry = mapLinkToIpfsEntry(links[0], path)
93+
}
94+
}
95+
}
96+
} catch (error) {
97+
console.error('error', error)
98+
} finally {
99+
if (timerId) {
100+
clearTimeout(timerId)
101+
}
102+
}
103+
} catch (error) {
104+
console.error('error', error)
105+
}
106+
107+
return ipfsEntry
108+
}
109+
110+
function mapLinkToIpfsEntry(link: IIpfsLink, path: string): IIPfsEntry {
111+
const hash = link.Hash.startsWith(IPFS_PREFIX) ? link.Hash.slice(IPFS_PREFIX.length) : link.Hash
112+
const entry: IIPfsEntry = {
113+
name: link.Name,
114+
path: path + (link.Name ? `/${link.Name}` : ''),
115+
size: link.Size,
116+
cid: hash,
117+
type: typeOf(link),
118+
}
119+
if (link.Mode) {
120+
entry.mode = Number.parseInt(link.Mode, 8)
121+
}
122+
123+
if (link.Mtime !== undefined && link.Mtime !== null) {
124+
entry.mtime = {
125+
secs: link.Mtime,
126+
}
127+
128+
if (link.MtimeNsecs !== undefined && link.MtimeNsecs !== null) {
129+
entry.mtime.nsecs = link.MtimeNsecs
130+
}
131+
}
132+
133+
return entry
134+
}
135+
136+
function typeOf(link: IIpfsLink): typeOfLink {
137+
switch (link.Type) {
138+
case 1:
139+
case 5: {
140+
return typeOfLink.Dir
141+
}
142+
case 2: {
143+
return typeOfLink.File
144+
}
145+
default: {
146+
return typeOfLink.File
147+
}
148+
}
149+
}

packages/shared/lib/core/nfts/utils/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ export * from './buildNftFromNftOutput'
22
export * from './checkIfNftShouldBeDownloaded'
33
export * from './composeUrlFromNftUri'
44
export * from './convertAndFormatNftMetadata'
5-
export * from './getSpendableStatusFromUnspentNftOutput'
65
export * from './fetchWithTimeout'
6+
export * from './getIpfsUri'
7+
export * from './getParentMimeType'
8+
export * from './getSpendableStatusFromUnspentNftOutput'
79
export * from './isNftOwnedByAnyAccount'
810
export * from './parseNftMetadata'
911
export * from './rewriteIpfsUri'
10-
export * from './getParentMimeType'

0 commit comments

Comments
 (0)