Skip to content

Commit

Permalink
chore: add pubsub example
Browse files Browse the repository at this point in the history
  • Loading branch information
achingbrain committed Oct 31, 2023
1 parent 711d44c commit 768371c
Show file tree
Hide file tree
Showing 10 changed files with 595 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
fail-fast: false
matrix:
project:
- js-libp2p-example-browser-pubsub
- js-libp2p-example-chat
- js-libp2p-example-circuit-relay
- js-libp2p-example-connection-encryption
Expand Down Expand Up @@ -70,6 +71,7 @@ jobs:
fail-fast: true
matrix:
project:
- js-libp2p-example-browser-pubsub
- js-libp2p-example-chat
- js-libp2p-example-circuit-relay
- js-libp2p-example-connection-encryption
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# ⚠️ IMPORTANT ⚠️

# Please do not create a Pull Request for this repository

The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.

Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.

## Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.

1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
4. Push to the Branch (`git push origin feature/amazing-example`)
5. Open a Pull Request
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: pull

on:
workflow_dispatch

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Pull from another repository
uses: ipfs-examples/actions-pull-directory-from-repo@main
with:
source-repo: libp2p/js-libp2p-examples
source-folder-path: examples/${{ github.event.repository.name }}
source-branch: main
target-branch: main
git-username: github-actions
git-email: github-actions@github.com
104 changes: 104 additions & 0 deletions examples/js-libp2p-example-browser-pubsub/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# @libp2p/example-browser-pubsub <!-- omit in toc -->

[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io)
[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-examples.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-examples)
[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-examples/ci.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-examples/actions/workflows/ci.yml?query=branch%3Amain)

> User libp2p pubsub in browsers
This example leverages the [vite bundler](https://vitejs.dev/) to compile and serve the libp2p code in the browser. You can use other bundlers such as Webpack, but we will not be covering them here.

## Table of contents <!-- omit in toc -->

- [Setup](#setup)
- [Running](#running)
- [Why do I need a Relay Server?](#why-do-i-need-a-relay-server)
- [Start the Relay Server](#start-the-relay-server)
- [Running the Example](#running-the-example)
- [License](#license)
- [Contribution](#contribution)

## Setup

1. Install example depenedencies and build the project
```console
$ npm install
$ npm run build
```
2. Open 2 terminal windows in the `./src` directory.

## Running

This example has three components. Two browser windows which will send pubsub messages and a relay server that they will use to establish the initial connection.

### Why do I need a Relay Server?

The only transport available to browser nodes that lets them be dialed by remote peers is the [WebRTC](https://www.npmjs.com/package/@libp2p/webrtc) transport.

This transport requires an initial [handshake](https://en.wikipedia.org/wiki/Session_Description_Protocol) to be done out-of-band, during which the two peers exchange their capabilities, addresses and open ports.

We use a [Circuit Relay](https://docs.libp2p.io/concepts/nat/circuit-relay/) server to establish an initial communication channel between the two browsers for this process, after which they will have negotiated a peer-to-peer connection and the relay will no longer be used.

```mermaid
sequenceDiagram
Browser A->>Relay: Create reservation
activate Relay
Browser B->>Relay: Dial Browser A
Relay->>Browser A: Relayed dial from Browser B
Browser B->>Relay: WebRTC handshake request
Relay->>Browser A: Relayed WebRTC handshake request
Browser A->>Relay: WebRTC handshake response
Relay->>Browser B: Relayed WebRTC handshake response
deactivate Relay
Browser B->>Browser A: WebRTC connection
```

### Start the Relay Server

For browsers to communicate, we first need to run the libp2p relay server:

```console
$ npm run relay
```

Copy one of the multiaddresses in the output.

### Running the Example

Start the Vite server:

```console
$ npm start
```

A browser window will automatically open. Let's call this `Browser A`.

1. Paste the copied multiaddress from the relay server, paste it into the `Dial MultiAddr` input and click the `Connect` button
2. `Browser A` is now connected to the relay server
3. Copy the multiaddress located after the `Listening on` message

Now open a second browser with the url `http://localhost:5173/`. Let's call this `Browser B`.

1. Using the copied multiaddress from `Listening on` section in `Browser A`, paste it into the `Remote MultiAddress` input and click the `Connect` button
2. `Browser B` is now connected to `Browser A`

You can now shut down the relay server if you wish.

1. In both `Browser A` and `Browser B`, enter the same topic name in the "Subscribe to topic" input and click the "Subscribe" button
2. In either browser, enter a message in the `Send Message to Topic` field and click "Send"

You should see the message appear in the output section towards the bottom of the other browser window.

## License

Licensed under either of

- Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT ([LICENSE-MIT](LICENSE-MIT) / <http://opensource.org/licenses/MIT>)

## Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
84 changes: 84 additions & 0 deletions examples/js-libp2p-example-browser-pubsub/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>js-libp2p browser pubsub</title>
<style>
label,
button {
display: block;
font-weight: bold;
margin: 5px 0;
}
div {
margin-bottom: 20px;
}
#send-section {
display: none;
}
input[type="text"] {
width: 800px;
}
</style>
</head>
<body>
<h1>libp2p Browser PubSub example</h1>
<p>This example demonstrates the pubsub API running in a browser</p>
<ol>
<li>Start a relay using the command line: <pre>$ node ./relay.js
Relay listening on multiaddr(s): [
'${multiaddr}'
]
</pre></li>
<li>Copy the relay's multiaddr and use the "Dial Multaddr" section to dial the relay</li>
<li>Wait for a WebRTC address to appear in the "Listening Addresses" area</li>
<li>Open the same page in another browser window</li>
<li>Use the "Dial Multiaddr" section in the second window to dial the WebRTC address from the first</li>
<li>Subscribe both windows to the same topic using the "PubSub" section</li>
<li>Send messages between the windows using the "PubSub" section</li>
</ol>
<hr />
<div>
<h2>Node</h2>
<label for="relay">Dial MultiAddr</label>
<input type="text" id="dial-multiaddr-input" placeholder="/ip4/127.0.0.1/tcp/1234/ws/p2p/123Foo" />
<button id="dial-multiaddr-button">Connect</button>

<h4>PeerId</h4>
<p id="peer-id"></p>

<h4>Listening Addresses</h4>
<ul id="listening-addresses">
<li>None</li>
</ul>

<h4>Connected Peers</h4>
<ul id="peer-connections">
<li>None</li>
</ul>
</div>
<hr />
<div>
<h2>PubSub</h2>
<label for="topic">Subscribe to topic</label>
<input type="text" id="subscribe-topic-input" placeholder="my-topic" />
<button id="subscribe-topic-button">Subscribe</button>

<h4>Topic Peers</h4>
<ul id="topic-peers">
<li>None</li>
</ul>

<label for="topic">Send Message to Topic</label>
<input type="text" id="send-topic-message-input" placeholder="hello world" disabled="disabled" />
<button id="send-topic-message-button" disabled="disabled">Send</button>
</div>
<hr />
<div>
<h2>Output</h2>
<pre id="output"></pre>
</div>
<script type="module" src="./index.js"></script>
</body>
</html>
Loading

0 comments on commit 768371c

Please sign in to comment.