Skip to content

Commit

Permalink
feat: add peer/content routing example (#174)
Browse files Browse the repository at this point in the history
Restores peer/content routing example
  • Loading branch information
achingbrain authored Sep 20, 2024
1 parent 9a23d76 commit d8439b3
Show file tree
Hide file tree
Showing 14 changed files with 366 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 @@ -27,6 +27,7 @@ jobs:
- js-libp2p-example-custom-protocols
- js-libp2p-example-delegated-routing
- js-libp2p-example-discovery-mechanisms
- js-libp2p-example-peer-and-content-routing
- js-libp2p-example-webrtc-private-to-private
defaults:
run:
Expand Down Expand Up @@ -82,6 +83,7 @@ jobs:
- js-libp2p-example-custom-protocols
- js-libp2p-example-delegated-routing
- js-libp2p-example-discovery-mechanisms
- js-libp2p-example-peer-and-content-routing
- js-libp2p-example-webrtc-private-to-private
steps:
- uses: convictional/trigger-workflow-and-wait@f69fa9eedd3c62a599220f4d5745230e237904be
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
49 changes: 49 additions & 0 deletions examples/js-libp2p-example-peer-and-content-routing/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* eslint-disable no-console */

import { noise } from '@chainsafe/libp2p-noise'
import { yamux } from '@chainsafe/libp2p-yamux'
import { identify, identifyPush } from '@libp2p/identify'
import { kadDHT, removePublicAddressesMapper } from '@libp2p/kad-dht'
import { tcp } from '@libp2p/tcp'
import { createLibp2p } from 'libp2p'

const createNode = async () => {
const node = await createLibp2p({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
transports: [tcp()],
streamMuxers: [yamux()],
connectionEncrypters: [noise()],
services: {
// configure Kad-DHT to run on the local network
dht: kadDHT({
protocol: '/ipfs/lan/kad/1.0.0',
peerInfoMapper: removePublicAddressesMapper,
clientMode: false
}),
identify: identify(),
identifyPush: identifyPush()
}
})

return node
}

const [node1, node2, node3] = await Promise.all([
createNode(),
createNode(),
createNode()
])

// Connect the nodes 1 -> 2 -> 3
await Promise.all([
node1.dial(node2.getMultiaddrs()),
node2.dial(node3.getMultiaddrs())
])

// find peer 3 from peer 1 (there is no direct connection)
const peer = await node1.peerRouting.findPeer(node3.peerId)

console.log('Found it, multiaddrs are:')
peer.multiaddrs.forEach((ma) => console.log(ma.toString()))
52 changes: 52 additions & 0 deletions examples/js-libp2p-example-peer-and-content-routing/2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable no-console */

import { noise } from '@chainsafe/libp2p-noise'
import { yamux } from '@chainsafe/libp2p-yamux'
import { identify, identifyPush } from '@libp2p/identify'
import { kadDHT, removePublicAddressesMapper } from '@libp2p/kad-dht'
import { tcp } from '@libp2p/tcp'
import all from 'it-all'
import { createLibp2p } from 'libp2p'
import { CID } from 'multiformats/cid'

const createNode = async () => {
const node = await createLibp2p({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
transports: [tcp()],
streamMuxers: [yamux()],
connectionEncrypters: [noise()],
services: {
dht: kadDHT({
protocol: '/ipfs/lan/kad/1.0.0',
peerInfoMapper: removePublicAddressesMapper,
clientMode: false
}),
identify: identify(),
identifyPush: identifyPush()
}
})

return node
}

const [node1, node2, node3] = await Promise.all([
createNode(),
createNode(),
createNode()
])

await Promise.all([
node1.dial(node2.getMultiaddrs()),
node2.dial(node3.getMultiaddrs())
])

const cid = CID.parse('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL')
await node1.contentRouting.provide(cid)

console.log('Node %s is providing %s', node1.peerId.toString(), cid.toString())

const providers = await all(node3.contentRouting.findProviders(cid, { timeout: 3000 }))

console.log('Found provider:', providers[0].id.toString())
4 changes: 4 additions & 0 deletions examples/js-libp2p-example-peer-and-content-routing/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This project is dual licensed under MIT and Apache-2.0.

MIT: https://www.opensource.org/licenses/mit
Apache-2.0: https://www.apache.org/licenses/license-2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
19 changes: 19 additions & 0 deletions examples/js-libp2p-example-peer-and-content-routing/LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
The MIT License (MIT)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
124 changes: 124 additions & 0 deletions examples/js-libp2p-example-peer-and-content-routing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# @libp2p/example-peer-and-content-routing

[![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)

> How to use peer and content routing
Peer Routing is the category of modules that offer a way to find other peers in the network by intentionally issuing queries, iterative or recursive, until a Peer is found or the closest Peers, given the Peer Routing algorithm strategy are found.

Content Routing is the category of modules that offer a way to find where content lives in the network, it works in two steps: 1) Peers provide (announce) to the network that they are holders of specific content (multihashes) and 2) Peers issue queries to find where that content lives. A Content Routing mechanism could be as complex as a Kademlia DHT or a simple registry somewhere in the network.

## 1. Using Peer Routing to find other peers

This example builds on top of the [Protocol and Stream Muxing](../protocol-and-stream-muxing). We need to install `@libp2p/kad-dht`, go ahead and `npm install @libp2p/kad-dht`. If you want to see the final version, open [1.js](./1.js).

First, let's update our config to support Peer Routing and Content Routing.

```JavaScript
import { noise } from '@chainsafe/libp2p-noise'
import { yamux } from '@chainsafe/libp2p-yamux'
import { identify, identifyPush } from '@libp2p/identify'
import { kadDHT, removePublicAddressesMapper } from '@libp2p/kad-dht'
import { tcp } from '@libp2p/tcp'
import { createLibp2p } from 'libp2p'

const createNode = async () => {
const node = await createLibp2p({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
transports: [tcp()],
streamMuxers: [yamux()],
connectionEncrypters: [noise()],
services: {
// configure Kad-DHT to run on the local network
dht: kadDHT({
protocol: '/ipfs/lan/kad/1.0.0',
peerInfoMapper: removePublicAddressesMapper,
clientMode: false
}),
identify: identify(),
identifyPush: identifyPush()
}
})

return node
}
```

Once that is done, we can use the createNode function we developed in the previous example to create 3 nodes. Connect node 1 to node 2 and node 2 to node 3. We will use node 2 as a way to find the whereabouts of node 3

```JavaScript
const [node1, node2, node3] = await Promise.all([
createNode(),
createNode(),
createNode()
])

await Promise.all([
node1.dial(node2.getMultiaddrs()),
node2.dial(node3.getMultiaddrs())
])

const peer = await node1.peerRouting.findPeer(node3.peerId)

console.log('Found it, multiaddrs are:')
peer.multiaddrs.forEach((ma) => console.log(ma.toString()))
```

You should see the output being something like:

```Bash
> node 1.js
Found it, multiaddrs are:
/ip4/127.0.0.1/tcp/63617
/ip4/192.168.86.41/tcp/63617
```

You have successfully used Peer Routing to find a peer that you were not directly connected. Now all you have to do is to dial to the multiaddrs you discovered.

## 2. Using Content Routing to find providers of content

With Content Routing, you can create records that are stored in multiple points in the network, these records can be resolved by you or other peers and they act as memos or rendezvous points. A great usage of this feature is to support discovery of content, where one node holds a file and instead of using a centralized tracker to inform other nodes that it holds that file, it simply puts a record in the network that can be resolved by other peers. Peer Routing and Content Routing are commonly known as Distributed Hash Tables, DHT.

You can find this example completed in [2.js](./2.js), however as you will see it is very simple to update the previous example.

Instead of calling `peerRouting.findPeer`, we will use `contentRouting.provide` and `contentRouting.findProviders`.

```JavaScript
import { CID } from 'multiformats/cid'
import all from 'it-all'

const cid = CID.parse('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL')
await node1.contentRouting.provide(cid)

console.log('Node %s is providing %s', node1.peerId.toString(), cid.toString())

const providers = await all(node3.contentRouting.findProviders(cid, { timeout: 5000 }))

console.log('Found provider:', providers[0].id.toString())
```

The output of your program should look like:

```bash
> node 2.js
Node QmSsmVPoTy3WpzwiNPnsKmonBaZjK2HitFs2nWUvwK31Pz is providing QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL
Found provider: QmSsmVPoTy3WpzwiNPnsKmonBaZjK2HitFs2nWUvwK31Pz
```

That's it, now you know how to find peers that have pieces of information that interest you!

## 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.
33 changes: 33 additions & 0 deletions examples/js-libp2p-example-peer-and-content-routing/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@libp2p/example-peer-and-content-routing",
"version": "0.0.0",
"description": "How to use peer and content routing",
"license": "Apache-2.0 OR MIT",
"homepage": "https://github.com/libp2p/js-libp2p-examples/tree/master/examples/js-libp2p-example-peer-and-content-routing#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/libp2p/js-libp2p-examples.git"
},
"bugs": {
"url": "https://github.com/libp2p/js-libp2p-examples/issues"
},
"type": "module",
"scripts": {
"lint": "aegir lint",
"test": "test-node-example test/*"
},
"dependencies": {
"@chainsafe/libp2p-noise": "^16.0.0",
"@chainsafe/libp2p-yamux": "^7.0.0",
"@libp2p/identify": "^3.0.1",
"@libp2p/kad-dht": "^13.0.0",
"@libp2p/tcp": "^10.0.0",
"it-all": "^3.0.2",
"libp2p": "^2.0.0",
"multiformats": "^13.1.1"
},
"devDependencies": {
"test-ipfs-example": "^1.1.0"
},
"private": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test as test1 } from './test-1.js'
import { test as test2 } from './test-2.js'

await test1()
await test2()
13 changes: 13 additions & 0 deletions examples/js-libp2p-example-peer-and-content-routing/test/test-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import path from 'path'
import { fileURLToPath } from 'url'
import { waitForOutput } from 'test-ipfs-example/node'

const __dirname = path.dirname(fileURLToPath(import.meta.url))

export async function test () {
process.stdout.write('1.js\n')

await waitForOutput('Found it, multiaddrs are:', 'node', [path.join(__dirname, '../1.js')], {
cwd: __dirname
})
}
13 changes: 13 additions & 0 deletions examples/js-libp2p-example-peer-and-content-routing/test/test-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import path from 'path'
import { fileURLToPath } from 'url'
import { waitForOutput } from 'test-ipfs-example/node'

const __dirname = path.dirname(fileURLToPath(import.meta.url))

export async function test () {
process.stdout.write('2.js\n')

await waitForOutput('Found provider:', 'node', [path.join(__dirname, '../2.js')], {
cwd: __dirname
})
}
11 changes: 11 additions & 0 deletions examples/js-libp2p-example-webrtc-private-to-private/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,14 @@ Received message 'hellob'
The WebRTC transport is not limited to browsers.

Why don't you try to create a Node.js version of the [browser peer script](./index.js)?

## 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.

0 comments on commit d8439b3

Please sign in to comment.