Skip to content

Commit 03dc652

Browse files
committed
docs: add delegated routing example
1 parent d8d3eaa commit 03dc652

File tree

10 files changed

+395
-0
lines changed

10 files changed

+395
-0
lines changed

examples/delegated-routing/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Delegated Routing with Libp2p and IPFS
2+
3+
This example shows how to use delegated peer and content routing. The [Peer and Content Routing Example](../peer-and-content-routing) focuses
4+
on the DHT implementation. This example takes that a step further and introduces delegated routing. Delegated routing is
5+
especially useful when your libp2p node will have limited resources, making running a DHT impractical. It's
6+
also highly useful if your node is generating content, but can't reliably be on the network. You can use delegate nodes
7+
to provide content on your behalf.
8+
9+
The starting [Libp2p Bundle](./src/libp2p-bundle.js) in this example starts by disabling the DHT and adding the Delegated Peer and Content Routers.
10+
Once you've completed the example, you should try enabled the DHT and see what kind of results you get! You can also enable the
11+
various Peer Discovery modules and see the impact it has on your Peer count.
12+
13+
## Prerequisite
14+
**NOTE**: This example is currently dependent on a clone of the [delegated routing support branch of go-ipfs](https://github.com/ipfs/go-ipfs/pull/4595).
15+
16+
## Running this example
17+
18+
1. Install IPFS locally if you dont already have it. [Install Guide](https://docs.ipfs.io/introduction/install/)
19+
2. Run the IPFS daemon: `ipfs daemon`
20+
3. The daemon will output a line about its API address, like `API server listening on /ip4/127.0.0.1/tcp/8080`
21+
4. In another window output the addresses of the node: `ipfs id`. Make note of the websocket address, is will contain `/ws/` in the address.
22+
5. In `./src/libp2p-bundle.js` replace the `delegatedApiOptions` host and port of your node if they are different.
23+
6. In `./src/App.js` replace `BootstrapNode` with your nodes Websocket address from step 4.
24+
7. Start this example:
25+
26+
```sh
27+
npm install
28+
npm start
29+
```
30+
31+
This should open your browser to http://localhost:3000. If it does not, go ahead and do that now.
32+
33+
8. Your browser should show you connected to at least 1 peer.
34+
35+
### Finding Content via the Delegate
36+
1. Add a file to your IPFS node. From this example root you can do `ipfs add ./README.md` to add the example readme.
37+
2. Copy the hash from line 5, it will look something like *Qmf33vz4HJFkqgH7XPP1uA6atYKTX1BWQEQthzpKcAdeyZ*.
38+
3. In the browser, paste the hash into the *Hash* field and hit `Find`. The readme contents should display.
39+
40+
This will do a few things:
41+
* The delegate nodes api will be queried to find providers of the content
42+
* The content will be fetched from the providers
43+
* Since we now have the content, we tell the delegate node to fetch the content from us and become a provider
44+
45+
### Finding Peers via the Delegate
46+
1. Get a list of your delegate nodes peer by querying the IPFS daemon: `ipfs swarm peers`
47+
2. Copy one of the CIDs from the list of peer addresses, this will be the last portion of the address and will look something like `QmdoG8DpzYUZMVP5dGmgmigZwR1RE8Cf6SxMPg1SBXJAQ8`.
48+
3. In your browser, paste the CID into the *Peer* field and hit `Find`.
49+
4. You should see information about the peer including its addresses.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "delegated-routing-example",
3+
"version": "0.1.0",
4+
"private": true,
5+
"dependencies": {
6+
"ipfs": "~0.32.2",
7+
"libp2p": "../../",
8+
"libp2p-delegated-content-routing": "~0.2.2",
9+
"libp2p-delegated-peer-routing": "~0.2.2",
10+
"libp2p-kad-dht": "~0.10.4",
11+
"libp2p-mplex": "~0.8.0",
12+
"libp2p-secio": "~0.10.0",
13+
"libp2p-webrtc-star": "~0.15.5",
14+
"libp2p-websocket-star": "~0.8.1",
15+
"libp2p-websockets": "~0.12.0",
16+
"react": "^16.5.2",
17+
"react-dom": "^16.5.2",
18+
"react-scripts": "1.1.5"
19+
},
20+
"scripts": {
21+
"start": "react-scripts start",
22+
"build": "react-scripts build",
23+
"test": "react-scripts test --env=jsdom",
24+
"eject": "react-scripts eject"
25+
}
26+
}
3.78 KB
Binary file not shown.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6+
<meta name="theme-color" content="#000000">
7+
<title>Delegated Routing</title>
8+
</head>
9+
<body>
10+
<noscript>
11+
You need to enable JavaScript to run this app.
12+
</noscript>
13+
<div id="root"></div>
14+
</body>
15+
</html>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
section * {
2+
margin: 10px;
3+
}
4+
5+
header {
6+
background-color: #222;
7+
height: 150px;
8+
padding: 20px;
9+
color: white;
10+
}
11+
12+
.center {
13+
text-align: center;
14+
}
15+
16+
pre {
17+
background-color: bisque;
18+
min-height: 100px;
19+
margin: 0px;
20+
padding: 10px;
21+
}
22+
23+
.loader {
24+
text-align: center;
25+
height: 64px;
26+
margin-bottom: -64px;
27+
}
28+
29+
.loading .lds-ripple {
30+
display: inline-block;
31+
position: relative;
32+
width: 64px;
33+
height: 64px;
34+
}
35+
.loading .lds-ripple div {
36+
position: absolute;
37+
border: 4px solid #000;
38+
opacity: 1;
39+
border-radius: 50%;
40+
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
41+
margin: auto;
42+
}
43+
.loading .lds-ripple div:nth-child(2) {
44+
animation-delay: -0.5s;
45+
}
46+
@keyframes lds-ripple {
47+
0% {
48+
top: 28px;
49+
left: 28px;
50+
width: 0;
51+
height: 0;
52+
opacity: 1;
53+
}
54+
100% {
55+
top: -1px;
56+
left: -1px;
57+
width: 58px;
58+
height: 58px;
59+
opacity: 0;
60+
}
61+
}

examples/delegated-routing/src/App.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import React, { Component } from 'react';
2+
import './App.css';
3+
import Ipfs from 'ipfs';
4+
import libp2pBundle from './libp2p-bundle';
5+
6+
const BootstrapNode = '/ip4/127.0.0.1/tcp/8081/ws/ipfs/QmdoG8DpzYUZMVP5dGmgmigZwR1RE8Cf6SxMPg1SBXJAQ8'
7+
8+
class App extends Component {
9+
constructor(props) {
10+
super(props);
11+
this.state = {
12+
peers: 0,
13+
// This hash is the IPFS readme
14+
hash: 'QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB',
15+
// This peer is one of the Bootstrap nodes for IPFS
16+
peer: 'QmV6kA2fB8kTr6jc3pL5zbNsjKbmPUHAPKKHRBYe1kDEyc',
17+
isLoading: 0
18+
};
19+
this.peerInterval = null;
20+
21+
this.handleHashChange = this.handleHashChange.bind(this);
22+
this.handleHashSubmit = this.handleHashSubmit.bind(this);
23+
this.handlePeerChange = this.handlePeerChange.bind(this);
24+
this.handlePeerSubmit = this.handlePeerSubmit.bind(this);
25+
}
26+
27+
handleHashChange(event) {
28+
this.setState({
29+
hash: event.target.value
30+
});
31+
}
32+
handlePeerChange(event) {
33+
this.setState({
34+
peer: event.target.value
35+
});
36+
}
37+
38+
handleHashSubmit(event) {
39+
event.preventDefault();
40+
this.setState({
41+
isLoading: this.state.isLoading + 1
42+
})
43+
44+
this.ipfs.files.cat(this.state.hash, (err, data) => {
45+
if (err) console.log('Error', err)
46+
47+
this.setState({
48+
response: data.toString(),
49+
isLoading: this.state.isLoading - 1
50+
})
51+
});
52+
}
53+
handlePeerSubmit(event) {
54+
event.preventDefault();
55+
this.setState({
56+
isLoading: this.state.isLoading + 1
57+
})
58+
59+
this.ipfs.dht.findpeer(this.state.peer, (err, results) => {
60+
if (err) console.log('Error', err)
61+
62+
this.setState({
63+
response: JSON.stringify(results, null, 2),
64+
isLoading: this.state.isLoading - 1
65+
})
66+
});
67+
}
68+
69+
componentDidMount() {
70+
window.ipfs = this.ipfs = new Ipfs({
71+
config: {
72+
Addresses: {
73+
Swarm: []
74+
},
75+
Discovery: {
76+
MDNS: {
77+
Enabled: false
78+
},
79+
webRTCStar: {
80+
Enabled: false
81+
}
82+
},
83+
Bootstrap: [
84+
BootstrapNode
85+
]
86+
},
87+
preload: {
88+
enabled: false
89+
},
90+
libp2p: libp2pBundle
91+
})
92+
this.ipfs.on('ready', () => {
93+
if (this.peerInterval) {
94+
clearInterval(this.peerInterval)
95+
}
96+
97+
this.ipfs.swarm.connect(BootstrapNode, (err) => {
98+
if (err) {
99+
console.log('Error connecting to the node', err)
100+
}
101+
console.log('Connected!')
102+
})
103+
104+
this.peerInterval = setInterval(() => {
105+
this.ipfs.swarm.peers((err, peers) => {
106+
if (err) console.log(err)
107+
if (peers) this.setState({peers: peers.length})
108+
})
109+
}, 2500)
110+
})
111+
}
112+
113+
render() {
114+
return (
115+
<div>
116+
<header className="center">
117+
<h1>Delegated Routing</h1>
118+
<h2>There are currently {this.state.peers} peers.</h2>
119+
</header>
120+
<section className="center">
121+
<form onSubmit={this.handleHashSubmit}>
122+
<label>
123+
Hash:
124+
<input type="text" value={this.state.hash} onChange={this.handleHashChange} />
125+
<input type="submit" value="Find" />
126+
</label>
127+
</form>
128+
<form onSubmit={this.handlePeerSubmit}>
129+
<label>
130+
Peer:
131+
<input type="text" value={this.state.peer} onChange={this.handlePeerChange} />
132+
<input type="submit" value="Find" />
133+
</label>
134+
</form>
135+
</section>
136+
<section className={[this.state.isLoading > 0 ? 'loading': '', 'loader'].join(' ')}>
137+
<div className="lds-ripple"><div></div><div></div></div>
138+
</section>
139+
<section>
140+
<pre>
141+
{this.state.response}
142+
</pre>
143+
</section>
144+
</div>
145+
);
146+
}
147+
}
148+
149+
export default App;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import App from './App';
4+
5+
it('renders without crashing', () => {
6+
const div = document.createElement('div');
7+
ReactDOM.render(<App />, div);
8+
ReactDOM.unmountComponentAtNode(div);
9+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
body {
2+
margin: 0;
3+
padding: 0;
4+
font-family: sans-serif;
5+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import './index.css';
4+
import App from './App';
5+
6+
ReactDOM.render(<App />, document.getElementById('root'));

0 commit comments

Comments
 (0)