Skip to content
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

Leverage Service Worker and WebTransport on Public Gateways #207

Open
lidel opened this issue Mar 6, 2023 · 4 comments
Open

Leverage Service Worker and WebTransport on Public Gateways #207

lidel opened this issue Mar 6, 2023 · 4 comments
Labels
epic kind/discussion Topical discussion; usually not changes to codebase kind/enhancement A net-new feature or an improvement to an existing feature making the case need/community-input Needs input from the wider community need/maintainers-input Needs input from the current maintainer(s)

Comments

@lidel
Copy link
Member

lidel commented Mar 6, 2023

This is a stub/meta issue for tracking work to leverage Service Workers (SW) as a fallback on public gateways.

cc historical SW threads for discovery: #57 #171 #158 ipfs/kubo#4025 #55

Broad strokes idea

  • SW would intercept requests for specific content root (/ipfs/cid/ or /ipns/id) and load data using
    • Helia
    • delegated routing over HTTPs (caskadht from cid.contact, /routing/v1/providers/cid?cascade=ipfs-dht)
    • bitswap over WebTransport transport (allowing direct fetch from Kubo)

Prior art

There are two ways one can fetch blocks:

  • Demo on js.ipfs.tech uses ancient js-ipfs not sure if it still works. But we could redo that with Helia, IPNI and WebTransport.
  • Saturn' browser client uses ?format=car instead, and fetches it from a single public gateway. Unsure if good prior art to look at tho.

I think the thing we want to create something robust that does do both, and use all public gateways as a fallback

Open questions

When SW is registered / used

First HTTP GET will always hit the gateway. Response could register worker and reload.
Future requests will hit SW, as long they come from the same Origin (see "no foreign fetch" below)

No foreign fetch

⚠️ before anyone gets too creative, read an understand fundamental limitation of ServiceWorkers: the lack of foreign fetch.
tldr: this means SW is active only if the root document loaded in the browser comes from the same Origin.

Use case ideas

(A) Client-side recovery

When gateway returns error (list tbd, could be 429 and maybe also 502 503 and 504), and it knows request comes from web browser, return text/html response (ipfs/boxo#262).

Augument text/html response to include an option to recover from page load error via a Service Worker IPFS node.

This is a good candidate for dipping our toes, does not impact "successful" flow, but allows for recovery from 429 Too Many Requests and Saturn CDN hiccups we will see in the near future.

Recovery could be based on Helia and WebTransport and/or verifiable HTTP block/car requests to public gateways

(B) Ability to register global worker

Giving user ability to prefer local JS for future requests, not only for errors, but all responses.

(C) Ability to isolate path gateway

We could do something related to #157 where actual payload is loaded in sandboxed iframe

@lidel lidel added the need/triage Needs initial labeling and prioritization label Mar 6, 2023
@whizzzkid
Copy link

whizzzkid commented Mar 8, 2023

Nice! @lidel a few questions:

First HTTP GET will always hit the gateway. Response could register worker and reload.

I am not sure how this would work, serviceWorker.register() can only be called from the navigator context. Which means, calling gateway directly won't register a service worker. To register a service worker, the gateway needs to be loaded explicitly which can call navigator.serviceWorker.register().

Giving user ability to prefer local JS for future requests

I feel the users should be oblivious to the fact where the content is being loaded from. This should be local first by-default and recover from a public gateway if needed.

Other Thoughts

  • Helia can ship with a bootstrap service worker, which can register a when loaded with in a navigator context. All requests heading out to the gateway can then be handled here. This out of the box functionality.
  • If we want to explicitly have a service worker per gateway and not per consumer, we can think in terms of shipping this gateway registration mechanism with helia or a hosted esm, which loads the gateway in an iframe, but that needs to conform to this caveat. i.e. the page will need to provide respective headers to allow browsers to register the worker from the iframe-context.

@whizzzkid whizzzkid added kind/enhancement A net-new feature or an improvement to an existing feature making the case epic kind/discussion Topical discussion; usually not changes to codebase need/community-input Needs input from the wider community need/maintainers-input Needs input from the current maintainer(s) and removed need/triage Needs initial labeling and prioritization labels Mar 8, 2023
@lidel
Copy link
Member Author

lidel commented Mar 14, 2023

[..] The gateway needs to be loaded explicitly which can call navigator.serviceWorker.register().

Yes, just like you noted, the idea is the gateway will return HTML that loads JS responsible for registering SW.

Initially, we would be doing that (A) on HTTP 502 and 504 error pages (show a button, which when clicked, registers worker, and reloads page). This allows us to figure out SW parts without having to implement full gateway (we only implement flat files).

I feel the users should be oblivious to the fact where the content is being loaded from. This should be local first by-default and recover from a public gateway if needed. [..] loads the gateway in an iframe [..]

Yes, that would be the endgame for same origin requests send by web browser for the root document.
But I urge everyone to NOT focus on that, and instead prioritize MVP that will make (A) HTTP error recovery UX pleasant and useful.

Rationale: start with smaller scope, make things robust first, Reimplementing the full gateway spec in JS to support for anything other than flat deserialized files will be a lot of work, and we need to have a reliable way of testing (gateway tests are wip).

@lidel
Copy link
Member Author

lidel commented Mar 14, 2023

Dropping some thoughts on core pieces:

@SgtPooki
Copy link
Member

2023-03-17 Discussion in weekly standup

  • serviceworker should be able to take request that was going to service worker and send somewhere else..
  • not hosting on gateway to start, simple html page that can be rendered locally in browser.

End Goal

basic plan

  • simple html page that can do content routing: accept URL/CID in input element, return cat jpg beneath it (result of IPFS.get(URL/CID))
  • accept input element info via URL to the html page, should auto-fill input element and submit; render cat jpg beneath it
    • Then support video rendering?
  • migrate code to library and demo to using service-worker
  • service-worker is pluggable for different retrieval methods (bitswap, libp2p stream, libp2p graph...?)

potential showoff items

  • Implement a brand new (madeup) transport and implement in demo - show users they can do this without going through bureaucracy.
  • Allow graph based requests over http/whatever

workstreams:

  • Demo of app that fetch blocks over http/bitswap from providers (direct).. verify blocks, render content
  • Use same logic, but over libp2p stream.

initial action items

  • @aschmahmann to provide basic diagram of "IPFS components" necessary to make this work
  • @SgtPooki to build demo repo, html page and basic layout that we can start working in.
  • @MarcoPolo to build "fetch over libp2p"

open questions

  • can service worker intercept Libp2p requests? (foreign-fetch).

callouts

  • will bundle with webpack and build locally runnable site (npm start) at first. webpack should help building a single "deployable" html page that can simply be ran locally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
epic kind/discussion Topical discussion; usually not changes to codebase kind/enhancement A net-new feature or an improvement to an existing feature making the case need/community-input Needs input from the wider community need/maintainers-input Needs input from the current maintainer(s)
Projects
None yet
Development

No branches or pull requests

3 participants