diff --git a/.gitignore b/.gitignore index 91bbb866a9..61b3b5aa3d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ docs **/*.log test/repo-tests* **/bundle.js +.cache # Logs logs diff --git a/examples/libp2p-in-the-browser/.babelrc b/examples/libp2p-in-the-browser/.babelrc new file mode 100644 index 0000000000..620e785799 --- /dev/null +++ b/examples/libp2p-in-the-browser/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@babel/preset-env"], + "plugins": ["syntax-async-functions","transform-regenerator"] +} \ No newline at end of file diff --git a/examples/libp2p-in-the-browser/1/.gitignore b/examples/libp2p-in-the-browser/1/.gitignore deleted file mode 100644 index 4187d67743..0000000000 --- a/examples/libp2p-in-the-browser/1/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bundle.js \ No newline at end of file diff --git a/examples/libp2p-in-the-browser/1/package.json b/examples/libp2p-in-the-browser/1/package.json deleted file mode 100644 index 75010eb3c4..0000000000 --- a/examples/libp2p-in-the-browser/1/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "libp2p-in-the-browser", - "version": "0.1.0", - "description": "See other nodes in the network using WebRTC Star discovery mechanism", - "main": "src/index.js", - "scripts": { - "bundle": "browserify src/index.js > public/bundle.js", - "serve": "static public -p 9090 -H '{\"Cache-Control\": \"no-cache, must-revalidate\"}'", - "start": "npm run bundle && npm run serve" - }, - "license": "MIT", - "devDependencies": { - "browserify": "^14.5.0", - "concat-stream": "^1.6.0", - "detect-dom-ready": "^1.0.2", - "node-static": "~0.7.10" - }, - "dependencies": { - "detect-dom-ready": "^1.0.2", - "libp2p": "../../../", - "libp2p-bootstrap": "~0.9.7", - "libp2p-gossipsub": "~0.0.4", - "libp2p-kad-dht": "^0.15.3", - "libp2p-mplex": "~0.8.5", - "libp2p-secio": "~0.11.1", - "libp2p-spdy": "~0.13.3", - "libp2p-webrtc-star": "~0.15.8", - "libp2p-websocket-star": "~0.10.2", - "libp2p-websockets": "~0.12.2", - "peer-info": "~0.15.1" - } -} diff --git a/examples/libp2p-in-the-browser/1/public/index.html b/examples/libp2p-in-the-browser/1/public/index.html deleted file mode 100644 index c13adfe989..0000000000 --- a/examples/libp2p-in-the-browser/1/public/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - libp2p in the browser - - -

libp2p node running \o/

-
-
- - - - diff --git a/examples/libp2p-in-the-browser/1/src/browser-bundle.js b/examples/libp2p-in-the-browser/1/src/browser-bundle.js deleted file mode 100644 index b9ddfd22c5..0000000000 --- a/examples/libp2p-in-the-browser/1/src/browser-bundle.js +++ /dev/null @@ -1,94 +0,0 @@ -'use strict' - -const WebRTCStar = require('libp2p-webrtc-star') -const WebSockets = require('libp2p-websockets') -const WebSocketStar = require('libp2p-websocket-star') -const Mplex = require('libp2p-mplex') -const SPDY = require('libp2p-spdy') -const SECIO = require('libp2p-secio') -const Bootstrap = require('libp2p-bootstrap') -const DHT = require('libp2p-kad-dht') -const Gossipsub = require('libp2p-gossipsub') -const libp2p = require('libp2p') - -// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-browser.json -const bootstrapList = [ - '/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', - '/dns4/sfo-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', - '/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', - '/dns4/sfo-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', - '/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', - '/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu', - '/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', - '/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', - '/dns4/node0.preload.ipfs.io/tcp/443/wss/p2p/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic', - '/dns4/node0.preload.ipfs.io/tcp/443/wss/p2p/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6' -] - -class Node extends libp2p { - constructor ({ peerInfo }) { - const wrtcStar = new WebRTCStar({ id: peerInfo.id }) - const wsstar = new WebSocketStar({ id: peerInfo.id }) - - const defaults = { - modules: { - transport: [ - wrtcStar, - WebSockets, - wsstar - ], - streamMuxer: [ - Mplex, - SPDY - ], - connEncryption: [ - SECIO - ], - peerDiscovery: [ - wrtcStar.discovery, - wsstar.discovery, - Bootstrap - ], - dht: DHT, - pubsub: Gossipsub - }, - config: { - peerDiscovery: { - autoDial: true, - webRTCStar: { - enabled: true - }, - websocketStar: { - enabled: true - }, - bootstrap: { - interval: 20e3, - enabled: true, - list: bootstrapList - } - }, - relay: { - enabled: true, - hop: { - enabled: false, - active: false - } - }, - dht: { - enabled: false - }, - pubsub: { - enabled: false - } - }, - connectionManager: { - minPeers: 10, - maxPeers: 50 - } - } - - super({ ...defaults, peerInfo }) - } -} - -module.exports = Node diff --git a/examples/libp2p-in-the-browser/1/src/create-node.js b/examples/libp2p-in-the-browser/1/src/create-node.js deleted file mode 100644 index 7cd2075d76..0000000000 --- a/examples/libp2p-in-the-browser/1/src/create-node.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict' - -const PeerInfo = require('peer-info') -const Node = require('./browser-bundle') - -function createNode (callback) { - PeerInfo.create((err, peerInfo) => { - if (err) { - return callback(err) - } - - const peerIdStr = peerInfo.id.toB58String() - const webrtcAddr = `/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/p2p-webrtc-star/p2p/${peerIdStr}` - const wsAddr = `/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star` - - peerInfo.multiaddrs.add(webrtcAddr) - peerInfo.multiaddrs.add(wsAddr) - - const node = new Node({ - peerInfo - }) - - node.idStr = peerIdStr - callback(null, node) - }) -} - -module.exports = createNode diff --git a/examples/libp2p-in-the-browser/1/src/index.js b/examples/libp2p-in-the-browser/1/src/index.js deleted file mode 100644 index 81f85d0784..0000000000 --- a/examples/libp2p-in-the-browser/1/src/index.js +++ /dev/null @@ -1,57 +0,0 @@ -/* eslint no-console: ["error", { allow: ["log"] }] */ -/* eslint max-nested-callbacks: ["error", 5] */ -'use strict' - -const domReady = require('detect-dom-ready') -const createNode = require('./create-node') - -domReady(() => { - const myPeerDiv = document.getElementById('my-peer') - const swarmDiv = document.getElementById('swarm') - - createNode((err, node) => { - if (err) { - return console.log('Could not create the Node, check if your browser has WebRTC Support', err) - } - - node.on('peer:discovery', (peerInfo) => { - console.log('Discovered a peer:', peerInfo.id.toB58String()) - }) - - node.on('peer:connect', (peerInfo) => { - const idStr = peerInfo.id.toB58String() - console.log('Got connection to: ' + idStr) - const connDiv = document.createElement('div') - connDiv.innerHTML = 'Connected to: ' + idStr - connDiv.id = idStr - swarmDiv.append(connDiv) - }) - - node.on('peer:disconnect', (peerInfo) => { - const idStr = peerInfo.id.toB58String() - const el = document.getElementById(idStr) - el && el.remove() - }) - - node.start((err) => { - if (err) { - return console.log(err) - } - - const idStr = node.peerInfo.id.toB58String() - - const idDiv = document - .createTextNode('Node is ready. ID: ' + idStr) - - myPeerDiv.append(idDiv) - - console.log('Node is listening o/') - node.peerInfo.multiaddrs.toArray().forEach(ma => { - console.log(ma.toString()) - }) - - // NOTE: to stop the node - // node.stop((err) => {}) - }) - }) -}) diff --git a/examples/libp2p-in-the-browser/README.md b/examples/libp2p-in-the-browser/README.md index 466b0f492a..9cadcc1c04 100644 --- a/examples/libp2p-in-the-browser/README.md +++ b/examples/libp2p-in-the-browser/README.md @@ -1,22 +1,55 @@ -# libp2p running in the Browser +# libp2p in the browser -One of the primary goals with libp2p P2P was to get it fully working in the browser and interopable with the versions running in Go and in Node.js. +This example leverages the [Parcel.js bundler](https://parceljs.org/) to compile and serve the libp2p code in the browser. Parcel uses [Babel](https://babeljs.io/) to handle transpilation of the code. You can use other bundlers such as Webpack or Browserify, but we will not be covering them here. -# 1. Setting up a simple app that lists connections to other nodes +## Setup -Start by installing libp2p's dependencies. +In order to run the example, first install the dependencies from same directory as this README: -```bash -> cd ../../ -> npm install -> cd examples/libp2p-in-the-browser ``` +cd ./examples/libp2p-in-the-browser +npm install +``` + +## Signaling Server + +This example uses the `libp2p-webrtc-star` module, which enables libp2p browser nodes to establish direct connections to one another via a central signaling server. For this example, we are using the signaling server that ships with `libp2p-webrtc-star`. + +You can start the server by running `npm run server`. This will start a signaling server locally on port `9090`. If you'd like to run a signaling server outside of this example, you can see instructions on how to do so in the [`libp2p-webrtc-star` README](https://github.com/libp2p/js-libp2p-webrtc-star). + +When you run the server, you should see output that looks something like this: + +```log +$ npm run server + +> libp2p-in-browser@1.0.0 server +> star-signal + +Listening on: http://0.0.0.0:9090 +``` + +## Running the examples -Then simply go into the folder [1](./1) and execute the following +Once you have started the signaling server, you can run the Parcel server. -```bash -> cd 1 -> npm install -> npm start -# open your browser in port :9090 ``` +npm start +``` + +The output should look something like this: + +```log +$ npm start + +> libp2p-in-browser@1.0.0 start +> parcel index.html + +Server running at http://localhost:1234 +✨ Built in 1000ms. +``` + +This will compile the code and start a server listening on port [http://localhost:1234](http://localhost:1234). Now open your browser to `http://localhost:1234`. You should see a log of your node's Peer ID, the discovered peers from the Bootstrap module, and connections to those peers as they are created. + +Now, if you open a second browser tab to `http://localhost:1234`, you should discover your node from the previous tab. This is due to the fact that the `libp2p-webrtc-star` transport also acts as a Peer Discovery interface. Your node will be notified of any peer that connects to the same signaling server you are connected to. Once libp2p discovers this new peer, it will attempt to establish a direct WebRTC connection. + +**Note**: In the example we assign libp2p to `window.libp2p`, in case you would like to play around with the API directly in the browser. You can of course make changes to `index.js` and Parcel will automatically rebuild and reload the browser tabs. diff --git a/examples/libp2p-in-the-browser/index.html b/examples/libp2p-in-the-browser/index.html new file mode 100644 index 0000000000..1c8f462b5b --- /dev/null +++ b/examples/libp2p-in-the-browser/index.html @@ -0,0 +1,23 @@ + + + + + + + js-libp2p parcel.js browser example + + + +
+

Starting libp2p...

+
+ +
+

+    
+ + + + + + \ No newline at end of file diff --git a/examples/libp2p-in-the-browser/index.js b/examples/libp2p-in-the-browser/index.js new file mode 100644 index 0000000000..2db38cc3c4 --- /dev/null +++ b/examples/libp2p-in-the-browser/index.js @@ -0,0 +1,73 @@ +import 'babel-polyfill' +import Libp2p from 'libp2p' +import Websockets from 'libp2p-websockets' +import WebRTCStar from 'libp2p-webrtc-star' +import Secio from 'libp2p-secio' +import Mplex from 'libp2p-mplex' +import Boostrap from 'libp2p-bootstrap' + +document.addEventListener('DOMContentLoaded', async () => { + // Create our libp2p node + const libp2p = await Libp2p.create({ + modules: { + transport: [Websockets, WebRTCStar], + connEncryption: [Secio], + streamMuxer: [Mplex], + peerDiscovery: [Boostrap] + }, + config: { + peerDiscovery: { + bootstrap: { + enabled: true, + list: [ + '/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', + '/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', + '/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu', + '/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', + '/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64' + ] + } + } + } + }) + + // UI elements + const status = document.getElementById('status') + const output = document.getElementById('output') + + output.textContent = '' + + function log (txt) { + console.info(txt) + output.textContent += `${txt.trim()}\n` + } + + // Add the signaling server address, along with our PeerId to our multiaddrs list + // libp2p will automatically attempt to dial to the signaling server so that it can + // receive inbound connections from other peers + const webrtcAddr = '/ip4/0.0.0.0/tcp/9090/wss/p2p-webrtc-star' + libp2p.peerInfo.multiaddrs.add(webrtcAddr) + + // Listen for new peers + libp2p.on('peer:discovery', (peerInfo) => { + log(`Found peer ${peerInfo.id.toB58String()}`) + }) + + // Listen for new connections to peers + libp2p.on('peer:connect', (peerInfo) => { + log(`Connected to ${peerInfo.id.toB58String()}`) + }) + + // Listen for peers disconnecting + libp2p.on('peer:disconnect', (peerInfo) => { + log(`Disconnected from ${peerInfo.id.toB58String()}`) + }) + + await libp2p.start() + status.innerText = 'libp2p started!' + log(`libp2p id is ${libp2p.peerInfo.id.toB58String()}`) + + // Export libp2p to the window so you can play with the API + window.libp2p = libp2p +}) diff --git a/examples/libp2p-in-the-browser/package.json b/examples/libp2p-in-the-browser/package.json new file mode 100644 index 0000000000..9aa78ac69d --- /dev/null +++ b/examples/libp2p-in-the-browser/package.json @@ -0,0 +1,34 @@ +{ + "name": "libp2p-in-browser", + "version": "1.0.0", + "description": "A libp2p node running in the browser", + "main": "index.js", + "browserslist": [ + "last 2 Chrome versions" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "parcel index.html", + "server": "star-signal" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@babel/preset-env": "^7.8.3", + "libp2p": "../../", + "libp2p-bootstrap": "^0.10.3", + "libp2p-mplex": "^0.9.3", + "libp2p-secio": "^0.12.2", + "libp2p-webrtc-star": "^0.17.3", + "libp2p-websockets": "^0.13.2" + }, + "devDependencies": { + "@babel/cli": "^7.8.3", + "@babel/core": "^7.8.3", + "babel-plugin-syntax-async-functions": "^6.13.0", + "babel-plugin-transform-regenerator": "^6.26.0", + "babel-polyfill": "^6.26.0", + "parcel-bundler": "^1.12.4" + } +} diff --git a/src/transport-manager.js b/src/transport-manager.js index ec7a958146..bcbaa45e1f 100644 --- a/src/transport-manager.js +++ b/src/transport-manager.js @@ -86,8 +86,8 @@ class TransportManager { try { return await transport.dial(ma, options) } catch (err) { - if (err.code) throw err - throw errCode(err, codes.ERR_TRANSPORT_DIAL_FAILED) + if (!err.code) err.code = codes.ERR_TRANSPORT_DIAL_FAILED + throw err } } diff --git a/src/upgrader.js b/src/upgrader.js index 7b3fa12313..b56992883f 100644 --- a/src/upgrader.js +++ b/src/upgrader.js @@ -216,7 +216,10 @@ class Upgrader { Muxer, remotePeer }) { - let muxer, newStream + let muxer + let newStream + // eslint-disable-next-line prefer-const + let connection if (Muxer) { // Create the muxer @@ -261,7 +264,7 @@ class Upgrader { const _timeline = maConn.timeline maConn.timeline = new Proxy(_timeline, { set: (...args) => { - if (args[1] === 'close' && args[2] && !_timeline.close) { + if (connection && args[1] === 'close' && args[2] && !_timeline.close) { connection.stat.status = 'closed' this.onConnectionEnd(connection) } @@ -276,7 +279,7 @@ class Upgrader { } // Create the connection - const connection = new Connection({ + connection = new Connection({ localAddr: maConn.localAddr, remoteAddr: maConn.remoteAddr, localPeer: this.localPeer,