Skip to content

Commit

Permalink
feat: add static http gateway routing (#515)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
achingbrain authored Apr 25, 2024
1 parent 361fbd3 commit 2d070b9
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/routers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@helia/delegated-routing-v1-http-api-client": "^3.0.0",
"@helia/interface": "^4.2.0",
"@libp2p/interface": "^1.1.4",
"@multiformats/uri-to-multiaddr": "^8.0.0",
"ipns": "^9.0.0",
"it-first": "^3.0.4",
"it-map": "^3.0.5",
Expand All @@ -66,6 +67,7 @@
"@libp2p/peer-id": "^4.0.7",
"@libp2p/peer-id-factory": "^4.0.7",
"aegir": "^42.2.5",
"it-all": "^3.0.4",
"it-drain": "^3.0.5",
"sinon-ts": "^2.0.0"
},
Expand Down
93 changes: 93 additions & 0 deletions packages/routers/src/http-gateway-routing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { peerIdSymbol } from '@libp2p/interface'
import { uriToMultiaddr } from '@multiformats/uri-to-multiaddr'
import { CID } from 'multiformats/cid'
import { identity } from 'multiformats/hashes/identity'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import type { Provider, Routing, RoutingOptions } from '@helia/interface'
import type { PeerId, PeerInfo } from '@libp2p/interface'
import type { MultihashDigest, Version } from 'multiformats'

export interface HTTPGatwayRouterInit {
gateways?: Array<URL | string>
}

// these values are from https://github.com/multiformats/multicodec/blob/master/table.csv
const TRANSPORT_IPFS_GATEWAY_HTTP_CODE = 0x0920
const inspect = Symbol.for('nodejs.util.inspect.custom')

class URLPeerId implements PeerId {
readonly type = 'url'
readonly multihash: MultihashDigest
readonly privateKey?: Uint8Array
readonly publicKey?: Uint8Array
readonly url: string

constructor (url: URL) {
this.url = url.toString()
this.multihash = identity.digest(uint8ArrayFromString(this.url))
}

[inspect] (): string {
return `PeerId(${this.url})`
}

readonly [peerIdSymbol] = true

toString (): string {
return this.toCID().toString()
}

toCID (): CID {
return CID.createV1(TRANSPORT_IPFS_GATEWAY_HTTP_CODE, this.multihash)
}

toBytes (): Uint8Array {
return this.toCID().bytes
}

equals (other?: PeerId | Uint8Array | string): boolean {
if (other == null) {
return false
}

if (other instanceof Uint8Array) {
other = uint8ArrayToString(other)
}

return other.toString() === this.toString()
}
}

function toPeerInfo (url: string | URL): PeerInfo {
url = url.toString()

return {
id: new URLPeerId(new URL(url)),
multiaddrs: [
uriToMultiaddr(url)
]
}
}

class HTTPGatwayRouter implements Partial<Routing> {
private readonly gateways: PeerInfo[]

constructor (init: HTTPGatwayRouterInit = {}) {
this.gateways = (init.gateways ?? []).map(url => toPeerInfo(url))
}

async * findProviders (cid: CID<unknown, number, number, Version>, options?: RoutingOptions | undefined): AsyncIterable<Provider> {
yield * this.gateways.map(info => ({
...info,
protocols: ['transport-ipfs-gateway-http']
}))
}
}

/**
* Returns a static list of HTTP Gateways as providers
*/
export function httpGatewayRouting (init: HTTPGatwayRouterInit = {}): Partial<Routing> {
return new HTTPGatwayRouter(init)
}
1 change: 1 addition & 0 deletions packages/routers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
* Abstraction layer over different content and peer routing mechanisms.
*/
export { delegatedHTTPRouting } from './delegated-http-routing.js'
export { httpGatewayRouting } from './http-gateway-routing.js'
export { libp2pRouting } from './libp2p-routing.js'
23 changes: 23 additions & 0 deletions packages/routers/test/http-gateway-routing.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { expect } from 'aegir/chai'
import all from 'it-all'
import { CID } from 'multiformats'
import { httpGatewayRouting } from '../src/http-gateway-routing.js'

describe('http-gateway-routing', () => {
it('should find providers', async () => {
const gateway = 'https://example.com'
const routing = httpGatewayRouting({
gateways: [
gateway
]
})

const cid = CID.parse('bafyreidykglsfhoixmivffc5uwhcgshx4j465xwqntbmu43nb2dzqwfvae')

const providers = await all(routing.findProviders?.(cid) ?? [])

expect(providers).to.have.lengthOf(1)
expect(providers).to.have.nested.property('[0].protocols').that.includes('transport-ipfs-gateway-http')
expect(providers[0].multiaddrs.map(ma => ma.toString())).to.include('/dns4/example.com/tcp/443/https')
})
})

0 comments on commit 2d070b9

Please sign in to comment.