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

Adding browser example with communication between peers #616

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/chat-in-the-browser/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["@babel/preset-env"],
"plugins": ["syntax-async-functions","transform-regenerator"]
}
55 changes: 55 additions & 0 deletions examples/chat-in-the-browser/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# libp2p chat in the browser

This example leverages the [Parcel.js bundler](https://parceljs.org/) to compile and serve the libp2p chat 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.

## Setup

In order to run the example, first install the dependencies from same directory as this README:

```
cd ./examples/chat-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

> [email protected] server
> star-signal

Listening on: http://0.0.0.0:9090
```

## Running the examples

Once you have started the signaling server, you can run the Parcel server.

```
npm start
```

The output should look something like this:

```log
$ npm start

> [email protected] 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.
25 changes: 25 additions & 0 deletions examples/chat-in-the-browser/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="utf-8" />
<title>js-libp2p parcel.js browser example</title>
</head>

<body>
<header>
<h1 id="status">Starting...</h1>
</header>

<chat>
<input id="txt_send" type="text" />
<button id="btn_send" onclick="send()">Send</button>
</chat>

<main>
<pre id="output"></pre>
</main>

<script src="./index.js"></script>
</body>
</html>
97 changes: 97 additions & 0 deletions examples/chat-in-the-browser/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
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'
import pipe from 'it-pipe'

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')
const txtSend = document.getElementById('txt_send')

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
let dialedStream = null
libp2p.on('peer:connect', peerInfo => {
log(`Connected to ${peerInfo.id.toB58String()}`)
libp2p.dialProtocol(peerInfo, ['/chat']).then(({ stream }) => {
log('dialed a stream', stream)
dialedStream = stream
})
})
svdo marked this conversation as resolved.
Show resolved Hide resolved

// 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()}`)

let handledStream = null
await libp2p.handle(['/chat'], ({ connection, stream }) => {
log(`handle chat from ${connection.remotePeer.toB58String()}`)
handledStream = stream
pipe(handledStream, async function (source) {
for await (const msg of source) {
log(`Received message: ${msg}`)
}
})
})

function send () {
const value = txtSend.value
pipe([value], dialedStream)
svdo marked this conversation as resolved.
Show resolved Hide resolved
}

// Export libp2p and send to the window so you can play with the API
window.libp2p = libp2p
window.send = send
})
34 changes: 34 additions & 0 deletions examples/chat-in-the-browser/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "chat-in-the-browser",
"version": "1.0.0",
"description": "A libp2p-based chat 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"
}
}