Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Awesome Endeavour: Async Iterators #1670

Closed
alanshaw opened this issue Oct 25, 2018 · 47 comments
Closed

Awesome Endeavour: Async Iterators #1670

alanshaw opened this issue Oct 25, 2018 · 47 comments
Assignees
Labels
awesome endeavour exp/wizard Extensive knowledge (implications, ramifications) required help wanted Seeking public contribution on this issue status/in-progress In progress

Comments

@alanshaw
Copy link
Member

alanshaw commented Oct 25, 2018

JS IPFS supports two types of stream at the API level, but uses pull streams for internals. If I was working on js-ipfs at the time I'd have made the same decision. Since then, async/await became part of the JS language and the majority of JavaScript runtimes now support async/await, async iterators and for/await/of (i.e. no need to transpile). These tools give us the power to stream data without needing to rely on a library.

Just because there are new language features available doesn't mean we should switch to using them. It's a significant upheaval to change the core interface spec and its implementations (js-ipfs, js-ipfs-api etc.) without good reason.

That said, it has become apparent that there are a growing number of good reasons to do this:

  • Reduction in bundle size - no need to bundle two different stream implementations, and their eco-system helper modules, no need for the async module.
  • Reduce npm install time - fewer dependencies to install.
  • Allows us to remove a bunch of plumbing code that converts Node.js streams to pull streams and vice versa.
  • Reduces API surface area, no addPullStream, addReadableStream.
  • Building an interface-ipfs-core compatible interface becomes a whole lot easier, no dual promise/callback API and no multiple stream implementation variations of the same function. It would also reduce the number of tests in the interface-ipfs-core test suite for the same reasons.
  • Node.js readable streams are now async iterators thanks to #17755!
  • Of note, it is trivial to convert from pull stream to (async) iterator and vice versa.
  • Unhandled throws that cannot be caught will no longer be a problem
  • Better stack traces, stacks no longer clipped at async boundaries, await stack traces better than promise stack traces
  • A modern, up to date and cutting edge API will aid community contributions and adoption.

The rough plan is:

  1. Drop support for dual callback/promise based APIs
  2. Expose only APIs that return promises or iterators for async actions
  3. Use async/await over then/catch when dealing with promises

This will require significant discussion and coordination from the JS teams. We'll need to reach agreement on the best API to expose for each module and manage releases carefully.

Below is a table documenting the multiformats, libp2p, ipld and ipfs modules that will likely need work. I suspect that some of these modules can be removed as they do not expose an async API. Likewise there's probably modules that got missed. If you notice either way then please edit the table or comment below.

If you'd like to own this enhancement task for a module then please comment below (or add yourself to the table if you know what you are doing). Please open a PR against the module asap (does not have to be anywhere near complete!) so we can add it here also and track progress.

  • 🍎 = Not started
  • 🍊 = In progress
  • 🍏 = Complete

Core

Multiformats

  • Current progress:
  • 🍏 2/2
  • 🍊 0/2
  • 🍎 0/2
Module PR Owner Status Priority
multihashing-async multiformats/js-multihashing-async#37 @hugomrdias 🍏 P0
multistream-select https://github.com/multiformats/js-multistream-select/releases/tag/v0.15.0 @alanshaw 🍏 P1

libp2p

libp2p/js-libp2p#266

  • Current progress:
  • 🍏 25/30
  • 🍊 3/30
  • 🍎 2/30
Module PR Owner Status Priority
peer-id libp2p/js-peer-id#87 @hacdias 🍏 P3+
peer-info libp2p/js-peer-info#67 @hacdias 🍏 P3+
libp2p https://github.com/libp2p/js-libp2p/tree/refactor/async-await @jacobheun 🍊 P0
libp2p-bootstrap libp2p/js-libp2p-bootstrap#89 @dirkmc 🍏 P3+
libp2p-crypto libp2p/js-libp2p-crypto#131 @alanshaw 🍏 P3+
libp2p-crypto-secp256k1 libp2p/js-libp2p-crypto-secp256k1#9 @alanshaw 🍏 P1
libp2p-keychain libp2p/js-libp2p-keychain#37 @jacobheun 🍏 P3+
libp2p-kad-dht libp2p/js-libp2p-kad-dht#148 libp2p/js-libp2p-kad-dht#153 @vasco-santos 🍏 P3+
libp2p-delegated-content-routing libp2p/js-libp2p-delegated-content-routing#7 @achingbrain 🍏 P3+
libp2p-delegated-peer-routing libp2p/js-libp2p-delegated-peer-routing#8 @achingbrain 🍏 P3+
libp2p-floodsub libp2p/js-libp2p-floodsub#88 @vasco-santos 🍏 P3+
libp2p-gossipsub ChainSafe/js-libp2p-gossipsub#49 @vasco-santos 🍏 P3+
libp2p-pubsub libp2p/js-libp2p-pubsub#26 @vasco-santos 🍏 P0
libp2p-secio libp2p/js-libp2p-secio#108 @mkg20001 🍏 P3+
libp2p-spdy 🍎 P1
libp2p-mplex libp2p/js-libp2p-mplex#94 @alanshaw 🍏 P1
libp2p-record libp2p/js-libp2p-record#13 @dirkmc 🍏 P1
libp2p-rendezvous 🍎 P3+
libp2p-mdns libp2p/js-libp2p-mdns#78 @dirkmc 🍏 P3+
libp2p-tcp libp2p/js-libp2p-tcp#112 @dirkmc + @alanshaw 🍏 P3+
libp2p-utp libp2p/js-libp2p-utp#81 @vasco-santos 🍊 P1
libp2p-webrtc-direct libp2p/js-libp2p-webrtc-direct#30 @vasco-santos 🍏 P1
libp2p-webrtc-star libp2p/js-libp2p-webrtc-star#183 @vasco-santos 🍏 P3+
libp2p-websocket-star libp2p/js-libp2p-websocket-star#77 @vasco-santos 🍊 P3+
libp2p-websocket-star-rendezvous libp2p/js-libp2p-websocket-star-rendezvous#35 @achingbrain 🍏 P3+
libp2p-websockets libp2p/js-libp2p-websockets#92 @alanshaw + @vasco-santos 🍏 P1
interface-connection libp2p/interface-connection#29 @vasco-santos 🍏 P0
interface-transport libp2p/interface-transport#44 @dirkmc 🍏 P0
interface-peer-discovery libp2p/interface-peer-discovery#10 @vasco-santos 🍏 P0
interface-stream-muxer libp2p/interface-stream-muxer#55 @alanshaw 🍏 P3+

IPLD

Please read #1670 (comment) before contributing.

  • Current progress:
  • 🍏 8/8
  • 🍊 0/8
  • 🍎 0/8
Module PR Owner Status Priority
ipld ipld/js-ipld#190 @vmx 🍏 P3+
ipld-bitcoin ipld/js-ipld-bitcoin#48 @vmx 🍏 P3+
ipld-dag-pb ipld/js-ipld-dag-pb#124 @vmx 🍏 P1
ipld-dag-cbor ipld/js-ipld-dag-cbor#107 @vmx 🍏 P1
ipld-ethereum ipld/js-ipld-ethereum#51 @vmx 🍏 P1
ipld-git ipld/js-ipld-git#51 @vmx 🍏 P1
ipld-raw ipld/js-ipld-raw#32 @vmx 🍏 P1
ipld-zcash ipld/js-ipld-zcash#39 @vmx 🍏 P1

IPFS

  • Current progress:
  • 🍏 19/19
  • 🍊 0/19
  • 🍎 0/19
Module PR Owner Status Priority
interface-datastore ipfs/interface-datastore#25 @alanshaw 🍏 P0
datastore-core ipfs/js-datastore-core#17 @zcstarr 🍏 P1
datastore-fs ipfs/js-datastore-fs#22 @zcstarr 🍏 P1
datastore-level ipfs/js-datastore-level#12 @alanshaw 🍏 P2
datastore-pubsub ipfs/js-datastore-pubsub#15 @vasco-santos 🍏 P3+
datastore-s3 ipfs/js-datastore-s3#17 @dirkmc 🍏 P2
interface-ipfs-core ipfs-inactive/interface-js-ipfs-core#562 @PedroMiguelSS 🍏 P3+
interop ipfs/interop#87 @PedroMiguelSS 🍏 P3+
ipfs #2495 #2379 #2517 #2547 #2658 #2659 #2660 #2661 #2664 #2665 #2666 #2668 #2671 #2672 #2683 #2724 #2726 @alanshaw / @achingbrain 🍏 P3+
ipns ipfs/js-ipns#19 @dirkmc 🍏 P3+
ipfs-http-client ipfs-inactive/js-ipfs-http-client#1059 ipfs-inactive/js-ipfs-http-client#1087 ipfs-inactive/js-ipfs-http-client#1101 ipfs-inactive/js-ipfs-http-client#1124 ipfs-inactive/js-ipfs-http-client#1149 ipfs-inactive/js-ipfs-http-client#1153 ipfs-inactive/js-ipfs-http-client#1154 ipfs-inactive/js-ipfs-http-client#1155 ipfs-inactive/js-ipfs-http-client#1156 ipfs-inactive/js-ipfs-http-client#1157 ipfs-inactive/js-ipfs-http-client#1161 ipfs-inactive/js-ipfs-http-client#1160 ipfs-inactive/js-ipfs-http-client#1164 ipfs-inactive/js-ipfs-http-client#1165 ipfs-inactive/js-ipfs-http-client#1166 ipfs-inactive/js-ipfs-http-client#1168 ipfs-inactive/js-ipfs-http-client#1169 ipfs-inactive/js-ipfs-http-client#1170 ipfs-inactive/js-ipfs-http-client#1172 ipfs-inactive/js-ipfs-http-client#1173 ipfs-inactive/js-ipfs-http-client#1174 ipfs-inactive/js-ipfs-http-client#1183 @alanshaw / @achingbrain 🍏 P3+
ipfs-bitswap ipfs/js-ipfs-bitswap#202 @achingbrain 🍏 P3+
ipfs-block-service ipfs/js-ipfs-block-service#85 @dirkmc 🍏 P3+
ipfs-http-response ipfs/js-ipfs-http-response#28 @PedroMiguelSS 🍏 P1
ipfs-mfs ipfs-inactive/js-ipfs-mfs#49 @achingbrain 🍏 P3+
ipfs-multipart ipfs-inactive/js-ipfs-multipart#17 @achingbrain 🍏 P0
ipfs-repo ipfs/js-ipfs-repo#189 @zcstarr 🍏 P3+
ipfs-unixfs-exporter ipfs-inactive/js-ipfs-unixfs-exporter#21 @achingbrain 🍏 P3+
ipfs-unixfs-importer ipfs-inactive/js-ipfs-unixfs-importer#24 @achingbrain 🍏 P3+

Dependents

These modules use IPFS and fall under the ipfs/ipfs-shipyard umbrella so should also be updated.

Current progress:

  • 🍏 1/44
  • 🍊 2/44
  • 🍎 40/44
Module PR Owner Status Priority
awesome-ipfs 🍎
benchmark-js.ipfs.io 🍎
cid-utils-website 🍎
demo-ipfs-todo 🍎
ipfs-companion @lidel 🍎
ipfs-desktop 🍎
ipfs-fuse @alanshaw 🍎
ipfs-geoip ipfs-shipyard/ipfs-geoip#67 @nijynot 🍊 P0
ipfs-iiif-db 🍎
ipfs-level 🍎
ipfs-blob-store ipfs-shipyard/ipfs-blob-store#26 @niinpatel 🍊 P3+
ipfs-locations 🍎
ipfs-performance-profiling 🍎
ipfs-pubsub-peer-monitor 🍎
ipfs-pubsub-room 🍎
ipfs-pubsub-room-demo 🍎
ipfs-redux-bundle 🍎
ipfs-registry-mirror 🍎
ipfs-postmsg-proxy @alanshaw 🍎
ipfs-pubsub-1on1 🍎
ipfs-service-worker @vasco-santos 🍎
ipfs-share-files 🍎
ipfs-stats 🍎
ipfs-webui 🍎
ipfsd-ctl ipfs/js-ipfsd-ctl#353 @achingbrain 🍏
ipld-explorer 🍎
ipld-explorer-cli @alanshaw 🍎
ipld-explorer-components 🍎
ipscend 🍎
npm-on-ipfs @achingbrain 🍎
peer-crdt-textarea-binding 🍎
peer-flipchart 🍎
peer-pad-core 🍎
peer-star-app 🍎
peer-star-network-vis 🍎
peer-star-network-vis-react 🍎
peer-star-peer-color 🍎
peer-star-react 🍎
peerpad-peer-crdt 🍎
service-worker-gateway 🍎
tevere 🍎
window.ipfs-fallback @alanshaw 🍎
y-ipfs-connector 🍎
ipld-graph-builder 🍎 P3+
@alanshaw alanshaw added exp/wizard Extensive knowledge (implications, ramifications) required help wanted Seeking public contribution on this issue status/ready Ready to be worked awesome endeavour labels Oct 25, 2018
@daviddias
Copy link
Member

This is a "Everyone is Welcome" effort and a excellent opportunity for everyone to get their feet wet on the codebase, improve documentation, testing and refresh the code.

Hoping that we can count with help from the IPFS GUI, IPFS in Web Browsers, Community WG and Dynamic Data & Capabilities. This will make our JS APIs better for all the modern/new JS developers!

@ipfs/javascript-team Unite ✨👋🏽⚡️

@dignifiedquire
Copy link
Member

this is awesome and makes me so happy to see 🎉

@hugomrdias
Copy link
Member

add me to multihashing-async, ipfsd-ctl, ipfs-multipart

@daviddias
Copy link
Member

@hugomrdias you got it! :)

alanshaw added a commit to alanshaw/js-libp2p-crypto-secp256k1 that referenced this issue Oct 28, 2018
This PR changes this module to remove callbacks and use async/await. The API is unchanged aside from the obvious removal of the `callback` parameter.

depends on `multihashing-async` PR TODO

refs ipfs/js-ipfs#1670

License: MIT
Signed-off-by: Alan Shaw <alan.shaw@protocol.ai>
@vasco-santos
Copy link
Member

Updated the table with my assignements

@hacdias
Copy link
Member

hacdias commented Oct 30, 2018

@alanshaw I'm taking a stab at libp2p/js-peer-id#87 😄

Update: I added myself to peer-info too.

@alanshaw
Copy link
Member Author

Thoughts and views on https://github.com/libp2p/interface-peer-discovery/issues/2 please!

@hacdias
Copy link
Member

hacdias commented Oct 30, 2018

@alanshaw I was thinking at taking a look at ipld-* and I noticed interface-ipld-format is missing from the table. Despite not being code, it is also required to be updated. I'll take a look at that one, does it make sense?

@mikeal
Copy link
Contributor

mikeal commented Oct 30, 2018

RE: IPLD

We (@vmx and I) aren't too happy with interface-ipld-format and have been talking about a re-write for a some time now. Originally we had intended to use async functions as a test case "before advocating that all of js-ipfs moves to it" but you're beating us to it now :)

Perhaps we should accelerate the timeline for this refactor rather than trying to update the current interface?

@daviddias
Copy link
Member

@mikeal it would be great if you, @vmx and @hacdias could work together on that refactor/redesign. I is a great opportunity for @hacdias to learn the IPLD way and learn from you two :)

@hacdias
Copy link
Member

hacdias commented Oct 31, 2018

Yeah, that would be awesome. @mikeal @vmx as you can see by my previous comment, I already created a PR on interface-ipld-format. Maybe we could continue the discussion there!

@mikeal
Copy link
Contributor

mikeal commented Oct 31, 2018

it would be great if you, @vmx and @hacdias could work together on that refactor/redesign

Sounds great, but I do want to make sure I'm prioritizing things in the right order (there's a lot on my plate from being out on vacation and now I'm sick). Is this refactor already blocking downstream refactors?

@daviddias daviddias added the Epic label Nov 5, 2019
alanshaw added a commit that referenced this issue Dec 9, 2019
This PR allows ipfsx to be used by calling `IPFS.create(options)` with `{ EXPERIMENTAL: { ipfsx: true } }` options.

It adds a single API method `add` that returns an iterator that yields objects of the form `{ cid, path, size }`. The iterator is decorated with a `first` and `last` function so users can conveniently `await` on the first or last item to be yielded as per the [proposal here](https://github.com/ipfs-shipyard/ipfsx/blob/master/API.md#add).

In order to boot up a new ipfsx node I refactored the boot procedure to enable the following:

1. **Remove the big stateful blob "`self`" - components are passed just the dependencies they need to operate.** Right now it is opaque as to which components require which parts of an IPFS node without inspecting the entirety of the component's code. This change makes it easier to look at a component and know what aspects of the IPFS stack it uses and consequently allows us to understand which APIs should be available at which points of the node's lifecycle. It makes the code easier to understand, more maintainable and easier to mock dependencies for unit tests.
1. **Restrict APIs to appropriate lifecycle stage(s).** This PR introduces an `ApiManager` that allows us to update the API that is exposed at any given point. It allows us to (for example) disallow `ipfs.add` before the node is initialized or access `libp2p` before the node is started. The lifecycle methods `init`, `start` and `stop` each define which API methods are available after they have run avoiding having to put boilerplate in every method to check if it can be called when the node is in a particular state. See #1438
1. **Safer and more flexible API usage.** The `ApiManager` allows us to temporarily change APIs to stop `init` from being called again while it is already running and has the facility to rollback to the previous API state if an operation fails. It also enables piggybacking so we don't attempt 2 or more concurrent start/stop calls at once. See #1061 #2257
1. **Enable config changes at runtime.** Having an API that can be updated during a node's lifecycle will enable this feature in the future.

**FEEDBACK REQUIRED**: The changes I've made here are a little...racy. They have a bunch of benefits, as I've outlined above but the `ApiManager` is implemented as a `Proxy`, allowing us to swap out the underlying API at will. How do y'all feel about that? Is there a better way or got a suggestion?

resolves #1438
resolves #1061
resolves #2257
refs #2509
refs #1670

License: MIT
Signed-off-by: Alan Shaw <alan.shaw@protocol.ai>
alanshaw added a commit that referenced this issue Dec 10, 2019
This PR allows ipfsx to be used by calling `IPFS.create(options)` with `{ EXPERIMENTAL: { ipfsx: true } }` options.

It adds a single API method `add` that returns an iterator that yields objects of the form `{ cid, path, size }`. The iterator is decorated with a `first` and `last` function so users can conveniently `await` on the first or last item to be yielded as per the [proposal here](https://github.com/ipfs-shipyard/ipfsx/blob/master/API.md#add).

In order to boot up a new ipfsx node I refactored the boot procedure to enable the following:

1. **Remove the big stateful blob "`self`" - components are passed just the dependencies they need to operate.** Right now it is opaque as to which components require which parts of an IPFS node without inspecting the entirety of the component's code. This change makes it easier to look at a component and know what aspects of the IPFS stack it uses and consequently allows us to understand which APIs should be available at which points of the node's lifecycle. It makes the code easier to understand, more maintainable and easier to mock dependencies for unit tests.
1. **Restrict APIs to appropriate lifecycle stage(s).** This PR introduces an `ApiManager` that allows us to update the API that is exposed at any given point. It allows us to (for example) disallow `ipfs.add` before the node is initialized or access `libp2p` before the node is started. The lifecycle methods `init`, `start` and `stop` each define which API methods are available after they have run avoiding having to put boilerplate in every method to check if it can be called when the node is in a particular state. See #1438
1. **Safer and more flexible API usage.** The `ApiManager` allows us to temporarily change APIs to stop `init` from being called again while it is already running and has the facility to rollback to the previous API state if an operation fails. It also enables piggybacking so we don't attempt 2 or more concurrent start/stop calls at once. See #1061 #2257
1. **Enable config changes at runtime.** Having an API that can be updated during a node's lifecycle will enable this feature in the future.

**FEEDBACK REQUIRED**: The changes I've made here are a little...racy. They have a bunch of benefits, as I've outlined above but the `ApiManager` is implemented as a `Proxy`, allowing us to swap out the underlying API at will. How do y'all feel about that? Is there a better way or got a suggestion?

resolves #1438
resolves #1061
resolves #2257
refs #2509
refs #1670

License: MIT
Signed-off-by: Alan Shaw <alan.shaw@protocol.ai>
@alanshaw alanshaw added status/in-progress In progress and removed status/ready Ready to be worked labels Dec 11, 2019
alanshaw added a commit that referenced this issue Jan 23, 2020
A roundup of the following PRs:

* closes #2658
* closes #2660
* closes #2661
* closes #2668
* closes #2674
* closes #2676
* closes #2680
* test fixes and other fix ups

---

To allow us to pass the interface tests, the timeout option is now supported in the `object.get` and `refs` APIs. It doesn't actually cancel the operation all the way down the stack, but allows the method call to return when the timeout is reached.

https://github.com/ipfs/js-ipfs/pull/2683/files#diff-47300e7ecd8989b6246221de88fc9a3cR170

---

Supersedes #2724

---

resolves #1438
resolves #1061
resolves #2257
resolves #2509
resolves #1670
refs ipfs-inactive/interface-js-ipfs-core#394

BREAKING CHANGE: `IPFS.createNode` removed

BREAKING CHANGE: IPFS is not a class that can be instantiated - use `IPFS.create`. An IPFS node instance is not an event emitter.

BREAKING CHANGE: Instance `.ready` property removed. Please use `IPFS.create` instead.

BREAKING CHANGE: Callbacks are no longer supported on any API methods. Please use a utility such as [`callbackify`](https://www.npmjs.com/package/callbackify) on API methods that return Promises to emulate previous behaviour.

BREAKING CHANGE: `PeerId` and `PeerInfo` classes are no longer statically exported from `ipfs-http-client` since they are no longer used internally.

BREAKING CHANGE: `pin.add` results now contain a `cid` property (a [CID instance](https://github.com/multiformats/js-cid)) instead of a string `hash` property.

BREAKING CHANGE: `pin.ls` now returns an async iterable.

BREAKING CHANGE: `pin.ls` results now contain a `cid` property (a [CID instance](https://github.com/multiformats/js-cid)) instead of a string `hash` property.

BREAKING CHANGE: `pin.rm` results now contain a `cid` property (a [CID instance](https://github.com/multiformats/js-cid)) instead of a string `hash` property.

BREAKING CHANGE: `add` now returns an async iterable.

BREAKING CHANGE: `add` results now contain a `cid` property (a [CID instance](https://github.com/multiformats/js-cid)) instead of a string `hash` property.

BREAKING CHANGE: `addReadableStream`, `addPullStream` have been removed.

BREAKING CHANGE: `ls` now returns an async iterable.

BREAKING CHANGE: `ls` results now contain a `cid` property (whose value is a [CID instance](https://github.com/multiformats/js-cid)) instead of a `hash` property.

BREAKING CHANGE: `files.readPullStream` and `files.readReadableStream` have been removed.

BREAKING CHANGE: `files.read` now returns an async iterable.

BREAKING CHANGE: `files.lsPullStream` and `files.lsReadableStream` have been removed.

BREAKING CHANGE: `files.ls` now returns an async iterable.

BREAKING CHANGE: `files.ls` results now contain a `cid` property (whose value is a [CID instance](https://github.com/multiformats/js-cid)) instead of a `hash` property.

BREAKING CHANGE: `files.ls` no longer takes a `long` option (in core) - you will receive all data by default.

BREAKING CHANGE: `files.stat` result now contains a `cid` property (whose value is a [CID instance](https://github.com/multiformats/js-cid)) instead of a `hash` property.

BREAKING CHANGE: `get` now returns an async iterable. The `content` property value for objects yielded from the iterator is now an async iterable that yields [`BufferList`](https://github.com/rvagg/bl) objects.

BREAKING CHANGE: `stats.bw` now returns an async iterable.

BREAKING CHANGE: `addFromStream` has been removed. Use `add` instead.

BREAKING CHANGE: `addFromFs` has been removed. Please use the exported `globSource` utility and pass the result to `add`. See the [glob source documentation](https://github.com/ipfs/js-ipfs-http-client#glob-source) for more details and an example.

BREAKING CHANGE: `addFromURL` has been removed. Please use the exported `urlSource` utility and pass the result to `add`. See the [URL source documentation](https://github.com/ipfs/js-ipfs-http-client#url-source) for more details and an example.

BREAKING CHANGE: `name.resolve` now returns an async iterable. It yields increasingly more accurate resolved values as they are discovered until the best value is selected from the quorum of 16. The "best" resolved value is the last item yielded from the iterator. If you are interested only in this best value you could use `it-last` to extract it like so:

```js
const last = require('it-last')
await last(ipfs.name.resolve('/ipns/QmHash'))
```

BREAKING CHANGE: `block.rm` now returns an async iterable.

BREAKING CHANGE: `block.rm` now yields objects of `{ cid: CID, error: Error }`.

BREAKING CHANGE: `dht.findProvs`, `dht.provide`, `dht.put` and `dht.query` now all return an async iterable.

BREAKING CHANGE: `dht.findPeer`, `dht.findProvs`, `dht.provide`, `dht.put` and `dht.query` now yield/return an object `{ id: CID, addrs: Multiaddr[] }` instead of a `PeerInfo` instance(s).

BREAKING CHANGE: `refs` and `refs.local` now return an async iterable.

BREAKING CHANGE: `object.data` now returns an async iterable that yields `Buffer` objects.

BREAKING CHANGE: `ping` now returns an async iterable.

BREAKING CHANGE: `repo.gc` now returns an async iterable.

BREAKING CHANGE: `swarm.peers` now returns an array of objects with a `peer` property that is a `CID`, instead of a `PeerId` instance.

BREAKING CHANGE: `swarm.addrs` now returns an array of objects `{ id: CID, addrs: Multiaddr[] }` instead of `PeerInfo` instances.

BREAKING CHANGE: `block.stat` result now contains a `cid` property (whose value is a [CID instance](https://github.com/multiformats/js-cid)) instead of a `key` property.

BREAKING CHANGE: `bitswap.wantlist` now returns an array of [CID](https://github.com/multiformats/js-cid) instances.

BREAKING CHANGE: `bitswap.stat` result has changed - `wantlist` and `peers` values are now an array of [CID](https://github.com/multiformats/js-cid) instances.

BREAKING CHANGE: the `init` option passed to the IPFS constructor will now not take any initialization steps if it is set to `false`. Previously, the repo would be initialized if it already existed. This is no longer the case. If you wish to initialize a node but only if the repo exists, pass `init: { allowNew: false }` to the constructor.

BREAKING CHANGE: removed `file ls` command from the CLI and HTTP API.

BREAKING CHANGE: Delegated peer and content routing modules are no longer included as part of core (but are still available if starting a js-ipfs daemon from the command line). If you wish to use delegated routing and are creating your node _programmatically_ in Node.js or the browser you must `npm install libp2p-delegated-content-routing` and/or `npm install libp2p-delegated-peer-routing` and provide configured instances of them in [`options.libp2p`](https://github.com/ipfs/js-ipfs#optionslibp2p). See the module repos for further instructions:

- https://github.com/libp2p/js-libp2p-delegated-content-routing
- https://github.com/libp2p/js-libp2p-delegated-peer-routing
alanshaw added a commit to ipfs-inactive/js-ipfs-http-client that referenced this issue Jan 23, 2020
TLDR;

* Remove Node.js streams and pull streams
* Remove callbacks
* Remove `peer-info` and `peer-id`

---

Now that internals are all async/await/iterables and `fetch` the next step is to bubble up that goodness to the core API, removing the multiple stream APIs and removing callback support.

I'm also proposing removing `peer-info` and `peer-id`, since these drastically increase the bundle size by pulling in `libp2p-crypto`, for which 99% of it's capability is unused. In place of `peer-id` we return a `CID`, which can easily be converted to a `PeerId` instance via:

```js
const peerId = PeerId.createFromCID(peerCid)
```

In place of `peer-info` we return an object `{ id: CID, addrs: Multiaddr[] }`, which can easily be converted to a `PeerInfo` like:

```js
const peerInfo = new PeerInfo(PeerId.createFromCID(info.id))
info.addrs.forEach(addr => peerInfo.multiaddrs.add(addr))
```

refs ipfs/js-ipfs#1670
refs ipfs/js-ipfs#2611
refs ipfs-inactive/interface-js-ipfs-core#394

TODO:

* [x] Refactor local tests
* [x] Remove `addFromFs` and `addFromUrl` and export `globSource` and `urlSource` instead
* [x] Refactor `interface-ipfs-core` tests
* [x] Document new APIs in `interface-ipfs-core`
* [x] Update README with API changes
* [x] [Document upgrade path from Node.js/pull streams to async iterables](https://gist.github.com/alanshaw/04b2ddc35a6fff25c040c011ac6acf26)

Depends on:

* [x] ipfs/js-ipfs-utils#15
* [x] ipfs-inactive/interface-js-ipfs-core#567

BREAKING CHANGE: Callbacks are no longer supported on any API methods. Please use a utility such as [`callbackify`](https://www.npmjs.com/package/callbackify) on API methods that return Promises to emulate previous behaviour.

BREAKING CHANGE: `PeerId` and `PeerInfo` classes are no longer statically exported from `ipfs-http-client` since they are no longer used internally.

BREAKING CHANGE: `pin.add` results now contain a `cid` property (a [CID instance](https://github.com/multiformats/js-cid)) instead of a string `hash` property.

BREAKING CHANGE: `pin.ls` now returns an async iterable.

BREAKING CHANGE: `pin.ls` results now contain a `cid` property (a [CID instance](https://github.com/multiformats/js-cid)) instead of a string `hash` property.

BREAKING CHANGE: `pin.rm` results now contain a `cid` property (a [CID instance](https://github.com/multiformats/js-cid)) instead of a string `hash` property.

BREAKING CHANGE: `add` now returns an async iterable.

BREAKING CHANGE: `add` results now contain a `cid` property (a [CID instance](https://github.com/multiformats/js-cid)) instead of a string `hash` property.

BREAKING CHANGE: `addReadableStream`, `addPullStream` have been removed.

BREAKING CHANGE: `ls` now returns an async iterable.

BREAKING CHANGE: `ls` results now contain a `cid` property (whose value is a [CID instance](https://github.com/multiformats/js-cid)) instead of a `hash` property.

BREAKING CHANGE: `files.ls` now returns an async iterable.

BREAKING CHANGE: `files.readPullStream` and `files.readReadableStream` have been removed.

BREAKING CHANGE: `files.read` now returns an async iterable.

BREAKING CHANGE: `files.lsPullStream` and `files.lsReadableStream` have been removed.

BREAKING CHANGE: `files.ls` now returns an async iterable.

BREAKING CHANGE: `files.ls` results now contain a `cid` property (whose value is a [CID instance](https://github.com/multiformats/js-cid)) instead of a `hash` property.

BREAKING CHANGE: `files.ls` no longer takes a `long` option (in core) - you will receive all data by default.

BREAKING CHANGE: `files.stat` result now contains a `cid` property (whose value is a [CID instance](https://github.com/multiformats/js-cid)) instead of a `hash` property.

BREAKING CHANGE: `get` now returns an async iterable. The `content` property value for objects yielded from the iterator is now an async iterable that yields [`BufferList`](https://github.com/rvagg/bl) objects.

BREAKING CHANGE: `stats.bw` now returns an async iterable.

BREAKING CHANGE: `addFromStream` has been removed. Use `add` instead.

BREAKING CHANGE: `isIPFS` is no longer exported from the client, please `npm i is-ipfs` or include the CDN script tag `<script src="https://unpkg.com/is-ipfs/dist/index.min.js"></script>` to use this utility in your applications.

BREAKING CHANGE: `addFromFs` has been removed. Please use the exported `globSource` utility and pass the result to `add`. See the [glob source documentation](https://github.com/ipfs/js-ipfs-http-client#glob-source) for more details and an example.

BREAKING CHANGE: `addFromURL` has been removed. Please use the exported `urlSource` utility and pass the result to `add`. See the [URL source documentation](https://github.com/ipfs/js-ipfs-http-client#url-source) for more details and an example.

BREAKING CHANGE: `name.resolve` now returns an async iterable. It yields increasingly more accurate resolved values as they are discovered until the best value is selected from the quorum of 16. The "best" resolved value is the last item yielded from the iterator. If you are interested only in this best value you could use `it-last` to extract it like so:

```js
const last = require('it-last')
await last(ipfs.name.resolve('/ipns/QmHash'))
```

BREAKING CHANGE: `block.rm` now returns an async iterable.

BREAKING CHANGE: `block.rm` now yields objects of `{ cid: CID, error: Error }`.

BREAKING CHANGE: `dht.findProvs`, `dht.provide`, `dht.put` and `dht.query` now all return an async iterable.

BREAKING CHANGE: `dht.findPeer`, `dht.findProvs`, `dht.provide`, `dht.put` and `dht.query` now yield/return an object `{ id: CID, addrs: Multiaddr[] }` instead of a `PeerInfo` instance(s).

BREAKING CHANGE: `refs` and `refs.local` now return an async iterable.

BREAKING CHANGE: `object.data` now returns an async iterable that yields `Buffer` objects.

BREAKING CHANGE: `ping` now returns an async iterable.

BREAKING CHANGE: `repo.gc` now returns an async iterable.

BREAKING CHANGE: `swarm.peers` now returns an array of objects with a `peer` property that is a `CID`, instead of a `PeerId` instance.

BREAKING CHANGE: `swarm.addrs` now returns an array of objects `{ id: CID, addrs: Multiaddr[] }` instead of `PeerInfo` instances.

BREAKING CHANGE: `block.stat` result now contains a `cid` property (whose value is a [CID instance](https://github.com/multiformats/js-cid)) instead of a `key` property.

BREAKING CHANGE: `bitswap.wantlist` now returns an array of [CID](https://github.com/multiformats/js-cid) instances.

BREAKING CHANGE: `bitswap.stat` result has changed - `wantlist` and `peers` values are now an array of [CID](https://github.com/multiformats/js-cid) instances.
@alanshaw alanshaw unpinned this issue Jan 24, 2020
@alanshaw
Copy link
Member Author

alanshaw commented Jan 24, 2020

Thank you EVERYONE who contributed to this. It has been the biggest journey I've ever taken - you've all been with me the whole way and you're all incredible. There's still some bits to finish up but expect to see all this goodness in js-ipfs 0.41 soon.

I'll also write a blog post and try to note down some of the many wins this work has made and enabled for the future.

Once again ❤️ to you all.

achingbrain pushed a commit that referenced this issue Jun 22, 2020
On `js-ipfs@0.41`, we removed the `websocket-star` module from the libp2p default configuration for browser nodes in `js-ipfs`. We removed it because this module was not refactored during #1670, since the libp2p goal is to [sunset the star protocols](libp2p/js-libp2p#385) and we preferred to use the time refactoring `websocket-star` into improving the browser support.

In the refactor, the `webrtc-star` module was refactored so that browser users could discover other peers in the network. In addition, `circuit-relay` may be used for establishing connections between browser nodes using `websockets`.

However, this migration has not been smooth for `js-ipfs` users. Users previously using `websocket-star` swarm addresses, did not have enough visibility of this change, since the removal of `websocket-star` was transparent for them and on the default `js-ipfs` release and not technically a programmable breaking change. 

With the above in mind, once `js-ipfs` users updated they started getting errors from `js-libp2p` in scenarios where they were providing only `websocket-star` swarm addresses. When `js-libp2p` receives listening multiaddrs, it throws an error if it cannot use any to listen on the configured transports, which was the case here (For instance #2779).

In `js-libp2p`, we added an option to tolerate these errors [libp2p/js-libp2p#643](libp2p/js-libp2p#643), which was also mentioned for some other cases earlier.

After syncing about this issue, we decided to temporarily throw an error when `js-ipfs` receives `websocket-star` multiaddrs. This aims to help users who still need to migrate to identify the problem faster.
github-actions bot pushed a commit to ipfs-examples/js-ipfs-custom-libp2p that referenced this issue Jun 14, 2021
Since I was going through these anyway to ensure they work with [0.37](ipfs/js-ipfs#2192) I've updated the examples to use the new [`IPFS.create` constructor](https://github.com/ipfs/js-ipfs#ipfs-constructor) and switched to using the promised API so that we onboard new users to using promises and minimise the disruption caused when ipfs/js-ipfs#1670 bubbles up to here.

License: MIT
Signed-off-by: Alan Shaw <alan.shaw@protocol.ai>
oliveriosousa pushed a commit to ipfs-examples/js-ipfs-examples that referenced this issue Jul 26, 2021
…#2068)

This is part of the Awesome Endeavour: Async Iterators: ipfs/js-ipfs#1670

Depends on

* [x] ipld/js-ipld-dag-pb#137
* [x] ipfs-inactive/interface-js-ipfs-core#473
* [x] ipfs-inactive/js-ipfs-http-client#1010
* [x] ipfs/js-ipfs-http-response#25

resolves #1995

BREAKING CHANGE: The default string encoding for version 1 CIDs has changed to `base32`.

IPLD formats have been updated to the latest versions. IPLD nodes returned by `ipfs.dag` and `ipfs.object` commands have significant breaking changes. If you are using these commands in your application you are likely to encounter the following changes to `dag-pb` nodes (the default node type that IPFS creates):

* `DAGNode` properties have been renamed as follows:
    * `data` => `Data`
    * `links` => `Links`
    * `size` => `size` (Note: no change)
* `DAGLink` properties have been renamed as follows:
    * `cid` => `Hash`
    * `name` => `Name`
    * `size` => `Tsize`

See CHANGELOGs for each IPLD format for it's respective changes, you can read more about the [`dag-pb` changes in the CHANGELOG](https://github.com/ipld/js-ipld-dag-pb/blob/master)

License: MIT
Signed-off-by: Alan Shaw <alan.shaw@protocol.ai>
oliveriosousa pushed a commit to ipfs-examples/js-ipfs-examples that referenced this issue Jul 26, 2021
Since I was going through these anyway to ensure they work with [0.37](ipfs/js-ipfs#2192) I've updated the examples to use the new [`IPFS.create` constructor](https://github.com/ipfs/js-ipfs#ipfs-constructor) and switched to using the promised API so that we onboard new users to using promises and minimise the disruption caused when ipfs/js-ipfs#1670 bubbles up to here.

License: MIT
Signed-off-by: Alan Shaw <alan.shaw@protocol.ai>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
awesome endeavour exp/wizard Extensive knowledge (implications, ramifications) required help wanted Seeking public contribution on this issue status/in-progress In progress
Projects
None yet
Development

Successfully merging a pull request may close this issue.

17 participants