From 3fc352ca3a62d8e125ba78e25bac92b5cddc813d Mon Sep 17 00:00:00 2001 From: dirkmc Date: Wed, 27 Nov 2019 06:24:22 -0500 Subject: [PATCH] refactor(docs): async await version of examples/echo (#483) * fix: performance bottleneck in stat.js (#463) Array.shift seems to be very slow, perhaps linear, on some engines, resulting in _update consuming a lot of CPU. * docs(fix): correct docs and example for pnet (#464) * docs(fix): correct docs and example for pnet * docs(fix): correct pnet docs * docs(fix): update README.md language (#468) * docs: reciprocate (#474) * docs(example): fix ipfs cat (#475) `ipfs.files.cat` is incorrect. the correct function is `ipfs.cat` * fix: async await examples/echo * fix: examples readme typos (#481) * fix: simplify libp2p bundle for echo example --- README.md | 22 ++++---- examples/README.md | 6 ++- examples/delegated-routing/src/App.js | 2 +- examples/echo/src/dialer.js | 73 ++++++++++++++------------- examples/echo/src/libp2p-bundle.js | 54 +------------------- examples/echo/src/listener.js | 57 ++++++++++----------- examples/pnet-ipfs/index.js | 6 +-- examples/pnet-ipfs/libp2p-bundle.js | 2 +- examples/pnet-ipfs/package.json | 11 ++-- src/pnet/README.md | 27 +++++----- src/switch/stats/stat.js | 6 +-- 11 files changed, 109 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index 8c868dc4fe..e28f2dfd47 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ We've come a long way, but this project is still in Alpha, lots of development i ## Background -libp2p is the product of a long and arduous quest to understand the evolution of the Internet networking stack. In order to build P2P applications, devs have long had to made custom ad-hoc solutions to fit their needs, sometimes making some hard assumptions about their runtimes and the state of the network at the time of their development. Today, looking back more than 20 years, we see a clear pattern in the types of mechanisms built around the Internet Protocol, IP, which can be found throughout many layers of the OSI layer system, libp2p distils these mechanisms into flat categories and defines clear interfaces that once exposed, enable other protocols and applications to use and swap them, enabling upgradability and adaptability for the runtime, without breaking the API. +libp2p is the product of a long and arduous quest to understand the evolution of the Internet networking stack. In order to build P2P applications, devs have long had to make custom ad-hoc solutions to fit their needs, sometimes making some hard assumptions about their runtimes and the state of the network at the time of their development. Today, looking back more than 20 years, we see a clear pattern in the types of mechanisms built around the Internet Protocol, IP, which can be found throughout many layers of the OSI layer system, libp2p distils these mechanisms into flat categories and defines clear interfaces that once exposed, enable other protocols and applications to use and swap them, enabling upgradability and adaptability for the runtime, without breaking the API. We are in the process of writing better documentation, blog posts, tutorials and a formal specification. Today you can find: @@ -101,7 +101,7 @@ You can find multiple examples on the [examples folder](/examples) that will gui ### Creating your own libp2p bundle -The libp2p module acts as a glue for every libp2p module that you can use to create your own libp2p bundle. Creating your own libp2p bundle gives you a lot of freedom when it comes to customize it with features and default setup. We recommend creating your own libp2p bundle for the app you are developing that takes in account your needs (e.g. for a browser working version of libp2p that acts as the network layer of IPFS, we have a built one that leverages the Browser transports). +The libp2p module acts as a glue for every libp2p module that you can use to create your own libp2p bundle. Creating your own libp2p bundle gives you a lot of freedom when it comes to customize it with features and default setup. We recommend creating your own libp2p bundle for the app you are developing that takes into account your needs (e.g. for a browser working version of libp2p that acts as the network layer of IPFS, we have built one that leverages the Browser transports). **Example:** @@ -122,7 +122,7 @@ const MulticastDNS = require('libp2p-mdns') const DHT = require('libp2p-kad-dht') const GossipSub = require('libp2p-gossipsub') const defaultsDeep = require('@nodeutils/defaults-deep') -const Protector = require('libp2p-pnet') +const Protector = require('libp2p/src/pnet') const DelegatedPeerRouter = require('libp2p-delegated-peer-routing') const DelegatedContentRouter = require('libp2p-delegated-content-routing') @@ -432,7 +432,7 @@ Returns an object containing the following keys: - dataSent - dataReceived -Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` miliseconds). +Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` milliseconds). Each one of these values is [an exponential moving-average instance](https://github.com/pgte/moving-average#readme). @@ -456,7 +456,7 @@ Returns an object containing the following keys: dataSent dataReceived -Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` miliseconds). +Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` milliseconds). Each one of these values is [an exponential moving-average instance](https://github.com/pgte/moving-average#readme). @@ -481,7 +481,7 @@ Returns an object containing the following keys: - dataSent - dataReceived -Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` miliseconds). +Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` milliseconds). Each one of these values is [an exponential moving-average instance](https://github.com/pgte/moving-average#readme). @@ -506,13 +506,13 @@ Returns an object containing the following keys: - dataSent - dataReceived -Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` miliseconds). +Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` milliseconds). Each one of these values is [an exponential moving-average instance](https://github.com/pgte/moving-average#readme). #### Stats update interval -Stats are not updated in real-time. Instead, measurements are buffered and stats are updated at an interval. The maximum interval can be defined through the `Switch` constructor option `stats.computeThrottleTimeout`, defined in miliseconds. +Stats are not updated in real-time. Instead, measurements are buffered and stats are updated at an interval. The maximum interval can be defined through the `Switch` constructor option `stats.computeThrottleTimeout`, defined in milliseconds. ### Private Networks @@ -523,15 +523,15 @@ Libp2p provides support for connection protection, such as for private networks. #### Protectors Some available network protectors: -* [libp2p-pnet](https://github.com/libp2p/js-libp2p-pnet) +* [libp2p-pnet](https://github.com/libp2p/js-libp2p/tree/master/src/pnet) ## Development **Clone and install dependencies:** ```sh -> git clone https://github.com/ipfs/js-ipfs.git -> cd js-ipfs +> git clone https://github.com/libp2p/js-libp2p.git +> cd js-libp2p > npm install ``` diff --git a/examples/README.md b/examples/README.md index 910e91e1df..aeba02a41c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,8 +1,8 @@ # `js-libp2p` Examples and Tutorials -In this folder, you can find a variety of examples to help you get started in using js-libp2p, in Node.js and in the Browser. Every example as a specific purpose and some of each incorporate a full tutorial that you can follow through, helping you expand your knowledge about libp2p and p2p networks in general. +In this folder, you can find a variety of examples to help you get started in using js-libp2p, in Node.js and in the Browser. Every example has a specific purpose and some incorporate a full tutorial that you can follow through, helping you expand your knowledge about libp2p and p2p networks in general. -Let us know if you find any issue or if you want to contribute and add a new tutorial, feel welcome to submit a PR, thank you! +Let us know if you find any issues, or if you want to contribute and add a new tutorial, feel free to submit a PR, thank you! ## Understanding how libp2p works @@ -22,3 +22,5 @@ Let us know if you find any issue or if you want to contribute and add a new tut - Running libp2p in the Electron (future) - [The standard echo net example with libp2p](./echo) - [A simple chat app with libp2p](./chat) + +For go-libp2p examples, check out https://github.com/libp2p/go-libp2p-examples#examples-and-tutorials diff --git a/examples/delegated-routing/src/App.js b/examples/delegated-routing/src/App.js index 2547496b93..ce6af6777f 100644 --- a/examples/delegated-routing/src/App.js +++ b/examples/delegated-routing/src/App.js @@ -44,7 +44,7 @@ class App extends Component { isLoading: this.state.isLoading + 1 }) - this.ipfs.files.cat(this.state.hash, (err, data) => { + this.ipfs.cat(this.state.hash, (err, data) => { if (err) console.log('Error', err) this.setState({ diff --git a/examples/echo/src/dialer.js b/examples/echo/src/dialer.js index e703501126..d2b7cfe732 100644 --- a/examples/echo/src/dialer.js +++ b/examples/echo/src/dialer.js @@ -8,51 +8,54 @@ const PeerId = require('peer-id') const PeerInfo = require('peer-info') const Node = require('./libp2p-bundle') -const pull = require('pull-stream') -const async = require('async') +const pipe = require('it-pipe') -async.parallel([ - (cb) => PeerId.createFromJSON(require('./id-d'), cb), - (cb) => PeerId.createFromJSON(require('./id-l'), cb) -], (err, ids) => { - if (err) { throw err } +async function run() { + const [dialerId, listenerId] = await Promise.all([ + PeerId.createFromJSON(require('./id-d')), + PeerId.createFromJSON(require('./id-l')) + ]) // Dialer - const dialerId = ids[0] const dialerPeerInfo = new PeerInfo(dialerId) dialerPeerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0') const dialerNode = new Node({ peerInfo: dialerPeerInfo }) - // Peer to Dial - const listenerPeerInfo = new PeerInfo(ids[1]) - const listenerId = ids[1] + // Peer to Dial (the listener) + const listenerPeerInfo = new PeerInfo(listenerId) const listenerMultiaddr = '/ip4/127.0.0.1/tcp/10333/p2p/' + listenerId.toB58String() listenerPeerInfo.multiaddrs.add(listenerMultiaddr) - dialerNode.start((err) => { - if (err) { throw err } - - console.log('Dialer ready, listening on:') - dialerPeerInfo.multiaddrs.forEach((ma) => console.log(ma.toString() + - '/p2p/' + dialerId.toB58String())) - - console.log('Dialing to peer:', listenerMultiaddr.toString()) - dialerNode.dialProtocol(listenerPeerInfo, '/echo/1.0.0', (err, conn) => { - if (err) { throw err } - - console.log('nodeA dialed to nodeB on protocol: /echo/1.0.0') - - pull( - pull.values(['hey']), - conn, - pull.collect((err, data) => { - if (err) { throw err } - console.log('received echo:', data.toString()) - }) - ) - }) - }) -}) + // Start the dialer libp2p node + await dialerNode.start() + + console.log('Dialer ready, listening on:') + dialerPeerInfo.multiaddrs.forEach((ma) => console.log(ma.toString() + + '/p2p/' + dialerId.toB58String())) + + // Dial the listener node + console.log('Dialing to peer:', listenerMultiaddr.toString()) + const { stream } = await dialerNode.dialProtocol(listenerPeerInfo, '/echo/1.0.0') + + console.log('nodeA dialed to nodeB on protocol: /echo/1.0.0') + + pipe( + // Source data + ['hey'], + // Write to the stream, and pass its output to the next function + stream, + // Sink function + async function (source) { + // For each chunk of data + for await (const data of source) { + // Output the data + console.log('received echo:', data.toString()) + } + } + ) +} + +run() diff --git a/examples/echo/src/libp2p-bundle.js b/examples/echo/src/libp2p-bundle.js index c45b4cfaf5..cca65f8f95 100644 --- a/examples/echo/src/libp2p-bundle.js +++ b/examples/echo/src/libp2p-bundle.js @@ -1,41 +1,12 @@ 'use strict' const TCP = require('libp2p-tcp') -const MulticastDNS = require('libp2p-mdns') const WS = require('libp2p-websockets') -const Bootstrap = require('libp2p-bootstrap') -const spdy = require('libp2p-spdy') -const KadDHT = require('libp2p-kad-dht') const mplex = require('libp2p-mplex') const secio = require('libp2p-secio') const defaultsDeep = require('@nodeutils/defaults-deep') const libp2p = require('../../..') -function mapMuxers (list) { - return list.map((pref) => { - if (typeof pref !== 'string') { - return pref - } - switch (pref.trim().toLowerCase()) { - case 'spdy': return spdy - case 'mplex': return mplex - default: - throw new Error(pref + ' muxer not available') - } - }) -} - -function getMuxers (muxers) { - const muxerPrefs = process.env.LIBP2P_MUXER - if (muxerPrefs && !muxers) { - return mapMuxers(muxerPrefs.split(',')) - } else if (muxers) { - return mapMuxers(muxers) - } else { - return [mplex, spdy] - } -} - class Node extends libp2p { constructor (_options) { const defaults = { @@ -44,29 +15,8 @@ class Node extends libp2p { TCP, WS ], - streamMuxer: getMuxers(_options.muxer), - connEncryption: [ secio ], - peerDiscovery: [ - MulticastDNS, - Bootstrap - ], - dht: KadDHT - }, - config: { - peerDiscovery: { - mdns: { - interval: 10000, - enabled: false - }, - bootstrap: { - interval: 10000, - enabled: false, - list: _options.bootstrapList - } - }, - dht: { - kBucketSize: 20 - } + streamMuxer: [ mplex ], + connEncryption: [ secio ] } } diff --git a/examples/echo/src/listener.js b/examples/echo/src/listener.js index 10546ec38f..476ca7e20f 100644 --- a/examples/echo/src/listener.js +++ b/examples/echo/src/listener.js @@ -8,39 +8,34 @@ const PeerId = require('peer-id') const PeerInfo = require('peer-info') const Node = require('./libp2p-bundle') -const pull = require('pull-stream') -const series = require('async/series') - -let listenerId -let listenerNode - -series([ - (cb) => { - PeerId.createFromJSON(require('./id-l'), (err, id) => { - if (err) { return cb(err) } - listenerId = id - cb() - }) - }, - (cb) => { - const listenerPeerInfo = new PeerInfo(listenerId) - listenerPeerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/10333') - listenerNode = new Node({ - peerInfo: listenerPeerInfo - }) - - listenerNode.on('peer:connect', (peerInfo) => { - console.log('received dial to me from:', peerInfo.id.toB58String()) - }) - - listenerNode.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn)) - listenerNode.start(cb) - } -], (err) => { - if (err) { throw err } +const pipe = require('it-pipe') + +async function run() { + const listenerId = await PeerId.createFromJSON(require('./id-l')) + + // Listener libp2p node + const listenerPeerInfo = new PeerInfo(listenerId) + listenerPeerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/10333') + const listenerNode = new Node({ + peerInfo: listenerPeerInfo + }) + + // Log a message when we receive a connection + listenerNode.on('peer:connect', (peerInfo) => { + console.log('received dial to me from:', peerInfo.id.toB58String()) + }) + + // Handle incoming connections for the protocol by piping from the stream + // back to itself (an echo) + await listenerNode.handle('/echo/1.0.0', ({ stream }) => pipe(stream.source, stream.sink)) + + // Start listening + await listenerNode.start() console.log('Listener ready, listening on:') listenerNode.peerInfo.multiaddrs.forEach((ma) => { console.log(ma.toString() + '/p2p/' + listenerId.toB58String()) }) -}) +} + +run() diff --git a/examples/pnet-ipfs/index.js b/examples/pnet-ipfs/index.js index c0d9572860..1df9417157 100644 --- a/examples/pnet-ipfs/index.js +++ b/examples/pnet-ipfs/index.js @@ -3,7 +3,7 @@ const IPFS = require('ipfs') const assert = require('assert').strict -const writeKey = require('libp2p-pnet').generate +const { generate: writeKey } = require('libp2p/src/pnet') const path = require('path') const fs = require('fs') const privateLibp2pBundle = require('./libp2p-bundle') @@ -117,7 +117,7 @@ const connectAndTalk = async () => { // Add some data to node 1 let addedCID try { - addedCID = await node1.files.add(dataToAdd) + addedCID = await node1.add(dataToAdd) } catch (err) { return doStop(err) } @@ -126,7 +126,7 @@ const connectAndTalk = async () => { // Retrieve the data from node 2 let cattedData try { - cattedData = await node2.files.cat(addedCID[0].path) + cattedData = await node2.cat(addedCID[0].path) } catch (err) { return doStop(err) } diff --git a/examples/pnet-ipfs/libp2p-bundle.js b/examples/pnet-ipfs/libp2p-bundle.js index b7c700a58b..ff4fd37e82 100644 --- a/examples/pnet-ipfs/libp2p-bundle.js +++ b/examples/pnet-ipfs/libp2p-bundle.js @@ -5,7 +5,7 @@ const TCP = require('libp2p-tcp') const MPLEX = require('libp2p-mplex') const SECIO = require('libp2p-secio') const fs = require('fs') -const Protector = require('libp2p-pnet') +const Protector = require('libp2p/src/pnet') /** * Options for the libp2p bundle diff --git a/examples/pnet-ipfs/package.json b/examples/pnet-ipfs/package.json index f4b05a5dc9..649e2711d9 100644 --- a/examples/pnet-ipfs/package.json +++ b/examples/pnet-ipfs/package.json @@ -11,11 +11,10 @@ "author": "", "license": "ISC", "dependencies": { - "ipfs": "~0.32.3", - "libp2p": "~0.23.1", - "libp2p-mplex": "~0.8.2", - "libp2p-pnet": "../../", - "libp2p-secio": "~0.10.0", - "libp2p-tcp": "~0.13.0" + "ipfs": "^0.38.0", + "libp2p": "^0.26.2", + "libp2p-mplex": "^0.8.5", + "libp2p-secio": "^0.11.1", + "libp2p-tcp": "^0.13.2" } } diff --git a/src/pnet/README.md b/src/pnet/README.md index 180df12a22..97d5c0b557 100644 --- a/src/pnet/README.md +++ b/src/pnet/README.md @@ -7,12 +7,15 @@ js-libp2p-pnet ## Table of Contents -- [Usage](#usage) - - [Examples](#examples) - - [Private Shared Keys (PSK)](#private-shared-keys) - - [PSK Generation](#psk-generation) -- [Contribute](#contribute) -- [License](#license) +- [js-libp2p-pnet](#js-libp2p-pnet) + - [Table of Contents](#table-of-contents) + - [Usage](#usage) + - [Examples](#examples) + - [Private Shared Keys](#private-shared-keys) + - [PSK Generation](#psk-generation) + - [From libp2p-pnet](#from-libp2p-pnet) + - [From a module using libp2p](#from-a-module-using-libp2p) + - [Programmatically](#programmatically) ## Usage @@ -23,7 +26,7 @@ const privateConnection = protector.protect(myPublicConnection, (err) => { }) ``` ### Examples -[Private Networks with IPFS](./examples/pnet-ipfs) +[Private Networks with IPFS](../../examples/pnet-ipfs) ### Private Shared Keys @@ -42,25 +45,25 @@ use one of the methods below to generate your key. #### From libp2p-pnet -If you have libp2p-pnet locally, you can run the following from the projects root. +If you have libp2p locally, you can run the following from the projects root. ```sh -node ./key-generator.js > swarm.key +node ./src/pnet/key-generator.js > swarm.key ``` #### From a module using libp2p -If you have a module locally that depends on libp2p-pnet, you can run the following from +If you have a module locally that depends on libp2p, you can run the following from that project, assuming the node_modules are installed. ```sh -node -e "require('libp2p-pnet').generate(process.stdout)" > swarm.key +node -e "require('libp2p/src/pnet').generate(process.stdout)" > swarm.key ``` #### Programmatically ```js -const writeKey = require('libp2p-pnet').generate +const writeKey = require('libp2p/src/pnet').generate const swarmKey = Buffer.alloc(95) writeKey(swarmKey) fs.writeFileSync('swarm.key', swarmKey) diff --git a/src/switch/stats/stat.js b/src/switch/stats/stat.js index e90c9f83a7..9b9b4dec04 100644 --- a/src/switch/stats/stat.js +++ b/src/switch/stats/stat.js @@ -139,10 +139,10 @@ class Stats extends EventEmitter { this._timeout = null if (this._queue.length) { let last - while (this._queue.length) { - const op = last = this._queue.shift() - this._applyOp(op) + for (last of this._queue) { + this._applyOp(last) } + this._queue = [] this._updateFrequency(last[2]) // contains timestamp of last op