Skip to content

Commit 2d070b9

Browse files
authored
feat: add static http gateway routing (#515)
Adds a routing implementation that returns a static list of gateways as providers for CIDs. It's expected that these gateways are able to fetch content on our behalf.
1 parent 361fbd3 commit 2d070b9

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

packages/routers/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"@helia/delegated-routing-v1-http-api-client": "^3.0.0",
5757
"@helia/interface": "^4.2.0",
5858
"@libp2p/interface": "^1.1.4",
59+
"@multiformats/uri-to-multiaddr": "^8.0.0",
5960
"ipns": "^9.0.0",
6061
"it-first": "^3.0.4",
6162
"it-map": "^3.0.5",
@@ -66,6 +67,7 @@
6667
"@libp2p/peer-id": "^4.0.7",
6768
"@libp2p/peer-id-factory": "^4.0.7",
6869
"aegir": "^42.2.5",
70+
"it-all": "^3.0.4",
6971
"it-drain": "^3.0.5",
7072
"sinon-ts": "^2.0.0"
7173
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { peerIdSymbol } from '@libp2p/interface'
2+
import { uriToMultiaddr } from '@multiformats/uri-to-multiaddr'
3+
import { CID } from 'multiformats/cid'
4+
import { identity } from 'multiformats/hashes/identity'
5+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
6+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
7+
import type { Provider, Routing, RoutingOptions } from '@helia/interface'
8+
import type { PeerId, PeerInfo } from '@libp2p/interface'
9+
import type { MultihashDigest, Version } from 'multiformats'
10+
11+
export interface HTTPGatwayRouterInit {
12+
gateways?: Array<URL | string>
13+
}
14+
15+
// these values are from https://github.com/multiformats/multicodec/blob/master/table.csv
16+
const TRANSPORT_IPFS_GATEWAY_HTTP_CODE = 0x0920
17+
const inspect = Symbol.for('nodejs.util.inspect.custom')
18+
19+
class URLPeerId implements PeerId {
20+
readonly type = 'url'
21+
readonly multihash: MultihashDigest
22+
readonly privateKey?: Uint8Array
23+
readonly publicKey?: Uint8Array
24+
readonly url: string
25+
26+
constructor (url: URL) {
27+
this.url = url.toString()
28+
this.multihash = identity.digest(uint8ArrayFromString(this.url))
29+
}
30+
31+
[inspect] (): string {
32+
return `PeerId(${this.url})`
33+
}
34+
35+
readonly [peerIdSymbol] = true
36+
37+
toString (): string {
38+
return this.toCID().toString()
39+
}
40+
41+
toCID (): CID {
42+
return CID.createV1(TRANSPORT_IPFS_GATEWAY_HTTP_CODE, this.multihash)
43+
}
44+
45+
toBytes (): Uint8Array {
46+
return this.toCID().bytes
47+
}
48+
49+
equals (other?: PeerId | Uint8Array | string): boolean {
50+
if (other == null) {
51+
return false
52+
}
53+
54+
if (other instanceof Uint8Array) {
55+
other = uint8ArrayToString(other)
56+
}
57+
58+
return other.toString() === this.toString()
59+
}
60+
}
61+
62+
function toPeerInfo (url: string | URL): PeerInfo {
63+
url = url.toString()
64+
65+
return {
66+
id: new URLPeerId(new URL(url)),
67+
multiaddrs: [
68+
uriToMultiaddr(url)
69+
]
70+
}
71+
}
72+
73+
class HTTPGatwayRouter implements Partial<Routing> {
74+
private readonly gateways: PeerInfo[]
75+
76+
constructor (init: HTTPGatwayRouterInit = {}) {
77+
this.gateways = (init.gateways ?? []).map(url => toPeerInfo(url))
78+
}
79+
80+
async * findProviders (cid: CID<unknown, number, number, Version>, options?: RoutingOptions | undefined): AsyncIterable<Provider> {
81+
yield * this.gateways.map(info => ({
82+
...info,
83+
protocols: ['transport-ipfs-gateway-http']
84+
}))
85+
}
86+
}
87+
88+
/**
89+
* Returns a static list of HTTP Gateways as providers
90+
*/
91+
export function httpGatewayRouting (init: HTTPGatwayRouterInit = {}): Partial<Routing> {
92+
return new HTTPGatwayRouter(init)
93+
}

packages/routers/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
* Abstraction layer over different content and peer routing mechanisms.
55
*/
66
export { delegatedHTTPRouting } from './delegated-http-routing.js'
7+
export { httpGatewayRouting } from './http-gateway-routing.js'
78
export { libp2pRouting } from './libp2p-routing.js'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { expect } from 'aegir/chai'
2+
import all from 'it-all'
3+
import { CID } from 'multiformats'
4+
import { httpGatewayRouting } from '../src/http-gateway-routing.js'
5+
6+
describe('http-gateway-routing', () => {
7+
it('should find providers', async () => {
8+
const gateway = 'https://example.com'
9+
const routing = httpGatewayRouting({
10+
gateways: [
11+
gateway
12+
]
13+
})
14+
15+
const cid = CID.parse('bafyreidykglsfhoixmivffc5uwhcgshx4j465xwqntbmu43nb2dzqwfvae')
16+
17+
const providers = await all(routing.findProviders?.(cid) ?? [])
18+
19+
expect(providers).to.have.lengthOf(1)
20+
expect(providers).to.have.nested.property('[0].protocols').that.includes('transport-ipfs-gateway-http')
21+
expect(providers[0].multiaddrs.map(ma => ma.toString())).to.include('/dns4/example.com/tcp/443/https')
22+
})
23+
})

0 commit comments

Comments
 (0)