-
Notifications
You must be signed in to change notification settings - Fork 144
feat: add explicit support for subdomain gateways #439
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
dde050c
9d77f79
2aae3b9
ed76171
43810d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import type { CID } from 'multiformats/cid' | ||
| import { base32 } from 'multiformats/bases/base32' | ||
|
|
||
| /** | ||
| * A `TrustlessGateway` keeps track of the number of attempts, errors, and | ||
|
|
@@ -8,6 +9,12 @@ import type { CID } from 'multiformats/cid' | |
| */ | ||
| export class TrustlessGateway { | ||
| public readonly url: URL | ||
|
|
||
| /** | ||
| * Whether this gateway is a subdomain resolution style gateway | ||
| */ | ||
| public isSubdomain: boolean | ||
|
|
||
| /** | ||
| * The number of times this gateway has been attempted to be used to fetch a | ||
| * block. This includes successful, errored, and aborted attempts. By counting | ||
|
|
@@ -36,34 +43,36 @@ export class TrustlessGateway { | |
| */ | ||
| #successes = 0 | ||
|
|
||
| constructor (url: URL | string) { | ||
| constructor(url: URL | string, isSubdomain: boolean = false) { | ||
|
2color marked this conversation as resolved.
Outdated
|
||
| this.url = url instanceof URL ? url : new URL(url) | ||
| this.isSubdomain = isSubdomain | ||
| } | ||
|
|
||
| /** | ||
| * Fetch a raw block from `this.url` following the specification defined at | ||
| * https://specs.ipfs.tech/http-gateways/trustless-gateway/ | ||
| */ | ||
| async getRawBlock (cid: CID, signal?: AbortSignal): Promise<Uint8Array> { | ||
| const gwUrl = this.url | ||
| gwUrl.pathname = `/ipfs/${cid.toString()}` | ||
| async getRawBlock(cid: CID, signal?: AbortSignal): Promise<Uint8Array> { | ||
| const gwUrl = this.getGwUrl(cid) | ||
|
|
||
| // necessary as not every gateway supports dag-cbor, but every should support | ||
| // sending raw block as-is | ||
| gwUrl.search = '?format=raw' | ||
|
|
||
| if (signal?.aborted === true) { | ||
| throw new Error(`Signal to fetch raw block for CID ${cid} from gateway ${this.url} was aborted prior to fetch`) | ||
| throw new Error( | ||
| `Signal to fetch raw block for CID ${cid} from gateway ${this.url} was aborted prior to fetch`, | ||
| ) | ||
|
2color marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| try { | ||
| this.#attempts++ | ||
| const res = await fetch(gwUrl.toString(), { | ||
| signal, | ||
| headers: { | ||
| // also set header, just in case ?format= is filtered out by some | ||
| // reverse proxy | ||
| Accept: 'application/vnd.ipld.raw' | ||
| // also set header, just in case ?format= is filtered out by some | ||
| // reverse proxy | ||
| Accept: 'application/vnd.ipld.raw', | ||
|
2color marked this conversation as resolved.
Outdated
|
||
| }, | ||
| cache: 'force-cache' | ||
| }) | ||
|
|
@@ -84,6 +93,20 @@ export class TrustlessGateway { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Construct the Gateway URL for a CID | ||
| */ | ||
| getGwUrl(cid: CID): URL { | ||
| const gwUrl = new URL(this.url) | ||
|
|
||
| if (this.isSubdomain) { | ||
| gwUrl.hostname = `${cid.toString(base32)}.ipfs.${gwUrl.hostname}` | ||
| } else { | ||
| gwUrl.pathname = `/ipfs/${cid.toString()}` | ||
| } | ||
|
Comment on lines
+108
to
+112
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to check here that the CID can actually be encoded as base32 (v0 will throw, I think?), and that it's not too long to be used as a DNS label. If it's v0 we could convert to v1 first to be able to encode it in a case insensitive way? We'll get the same block data back but I don't know if this will cause other problems.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Right. What other problems that it may cause did you have in mind? |
||
| return gwUrl | ||
| } | ||
|
|
||
| /** | ||
| * Encapsulate the logic for determining whether a gateway is considered | ||
| * reliable, for prioritization. This is based on the number of successful attempts made | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.