Closed vogdb closed 3 years ago
Hello @vogdb
The issue is that the code snippet his attempting to listen for tcp connections by:
addresses: {
listen: ['/ip4/127.0.0.1/tcp/0']
},
You need to listen for webrtcDirect connections. You need to specify a webrtc-direct valid address like:
addresses: {
listen: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
},
Let me know if you find any other issues. You need to also add the webrtcDirect transport to the js-ipfs daemon if you are looking to connect both through it
Out of this context, from the code snippet, it seems that you are tying to use libp2p-mdns
within a browser context. This will not work as the mdns
protocol is not available in a browser environment
Thank you so much for the response. If there is documentation/example about integration of WebrtcDirect and js-ipfs, just please point me to it. Otherwise, I still have some questions:
You need to also add the webrtcDirect transport to the js-ipfs daemon if you are looking to connect both through it
How to do it? I don't see any mentioning of this in documentation of config paragraph https://github.com/ipfs/js-ipfs/blob/master/docs/CONFIG.md. Also the search does not give anything https://github.com/ipfs/js-ipfs/search?q=webrtcdirect.
Out of this context, from the code snippet, it seems that you are tying to use libp2p-mdns within a browser context. This will not work as the mdns protocol is not available in a browser environment
I hoped to establish Browser to Node.js connections among IPFS nodes. What would be your recommendation on that? Again if there is documentation somewhere, just point me. I couldn't find any.
Thank you again.
There is no direct documentation on how to do this at the moment. If you are willing to help with that once you create your setup it would be super helpful.
The IPFS daemon itself is not easy to configure at this level currently. The ipfs-daemon
package allows specifying the libp2p config https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs-daemon/src/index.js#L46 but it seems that you would need to orchestrate the daemon with the cli+http server yourself. Anyway, I am not sure if supporting this type of interactions at the daemon level is something the project wants to support. I am not really into the ipfs setup in these scenarios.
So, I would like to understand your requirements and if you really want to use the daemon. The ipfs daemon would be useful if you expect to leverage its HTTP API + CLI while it is deployed somewhere. If you are not looking into this, I highly recommend you to use IPFS as a library instead like the above browser code snippet but for Node. You can also create an issue in js-ipfs
if you like, in order to understand if supporting this type of customisation in the daemon is desirable and better guidelines on how to do it.
Taking into account that you use IPFS as a library, you would create two projects (browser + node) using IPFS+libp2p as dependencies, which allow you to provide your own libp2p bundle with webrtcDirect.
I hoped to establish Browser to Node.js connections among IPFS nodes. What would be your recommendation on that? Again if there is documentation somewhere, just point me. I couldn't find any.
Do you have any requirement on achieving this with WebRTC for that connectivity? The usual scenarios we currently use are:
webrtc-star
for browser - browser connectionswebsockets
for browser - node connectionsThe main reason for this is that other IPFS implementations (including go-ipfs) do not support webrtc yet. This would mean that you would only be able to connect with js-ipfs
Node.js nodes, which is not desirable as your node network topology would be highly affected.
For websockets, you just need to use a websocket address in your IPFS config https://github.com/ipfs/js-ipfs/blob/master/docs/CONFIG.md#swarm . The caveat here is that your IPFS node will need to be behind an SSL certificate with dns because browser security policies do not allow websocket connections with bare websockets. With this in mind, you need to use https://github.com/ipfs/js-ipfs/blob/master/docs/CONFIG.md#announce where you will specify the dns based addresses like: dns4/example.libp2p.io/tcp/443/wss/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs65
. It is also important pointing out that since libp2p-websockets@0.15
we do not support attempting to dial non dns+wss
addresses because they do not work in production as mentioned. However, for local testing/experimentations, it is possible to use local addresses without setting up SSL+DNS. If you want to experiment with that look at https://github.com/libp2p/js-libp2p/blob/master/doc/migrations/v0.29-v0.30.md#development-and-testing
FYI: we will be working over the next months on improving the user experience of IPFS/libp2p in this side of things, aiming to have IPFS capable of having its own certificate running out of the box. But, this is not there yet.
Happy to discuss this further, either way you want to go with your work
There is no direct documentation on how to do this at the moment. If you are willing to help with that once you create your setup it would be super helpful.
I will be happy to help. I am very fond of the project in general.
So, I would like to understand your requirements...
No need for the daemon. It's a hobby project aside of my main work (scientific Python stack). I want to create an app to transfer files between a mobile and a PC when they are on the same local network/WiFi router (possibly extend it later for Internet). For mobile I want to wrap a browser IPFS into Cordova/Capacitor. For PC I want to have an electron app with Node.js IPFS. I went for WebrtcDirect as it looked as a solution with minimum to manage. No need for Webrtc signaling server or SSL+DNS in Websocket's case.
I lack knowledge in telecommunications/networking. If you can advice on a better approach, I would really appreciate it, and of course I will be happy to update documentation of the project if necessary. The idea of IPFS is thrilling, the current corporate Internet disappoints me.
No need for the daemon For mobile I want to wrap a browser IPFS into Cordova/Capacitor. For PC I want to have an electron app with Node.js IPFS. I went for WebrtcDirect as it looked as a solution with minimum to manage.
With the points mentioned I would recommend using IPFS as a library for Node.js as well: You would have something like:
node.js
const Libp2p = require('libp2p')
const IPFS = require('ipfs')
const WebRTCDirect = require('libp2p-webrtc-direct')
const Mplex = require('libp2p-mplex')
const {NOISE} = require('libp2p-noise')
const createLibp2p = (opts) => {
const peerId = opts.peerId
return new Libp2p({
peerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
},
modules: {
transport: [WebRTCDirect],
streamMuxer: [Mplex],
connEncryption: [NOISE]
}
})
}
// TODO: create IPFS with this function
browser.js
const Libp2p = require('libp2p')
const IPFS = require('ipfs')
const WebRTCDirect = require('libp2p-webrtc-direct')
const Mplex = require('libp2p-mplex')
const {NOISE} = require('libp2p-noise')
const Bootstrap = require('libp2p-bootstrap')
const createLibp2p = (opts, bootstrappers) => {
const peerId = opts.peerId
return new Libp2p({
modules: {
transport: [WebRTCDirect],
streamMuxer: [Mplex],
connEncryption: [NOISE],
peerDiscovery: [Bootstrap]
},
config: {
peerDiscovery: {
[Bootstrap.tag]: {
enabled: true,
list: bootstrappers
}
}
}
})
}
// TODO: create IPFS with this function
// Note the bootstrappers parameter. It should be an array with the multiaddr of your node: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
With this, if you use IPFS's swarm API you will be able to log the connected peers and after both peers are running, they should be connected and they are ready to exchange files.
Let me know if you could connect both nodes. For moving this into the public network, you would need to have a public address for your server that could be reached from anywhere.
Thank you so much that you find time to help me during New Eve's holidays!
...array with the multiaddr of your node: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
Can you please clarify what do you mean by that? Here is the code for node.js
const Libp2p = require('libp2p')
const IPFS = require('ipfs')
const WebRTCDirect = require('libp2p-webrtc-direct')
const Mplex = require('libp2p-mplex')
const {NOISE} = require('libp2p-noise')
const libp2pBundle = (opts) => {
const peerId = opts.peerId
return new Libp2p({
peerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
},
modules: {
transport: [WebRTCDirect],
streamMuxer: [Mplex],
connEncryption: [NOISE]
}
})
}
async function main () {
const node = await IPFS.create({
repo: 'ipfs-' + Math.random(),
libp2p: libp2pBundle
})
console.log(`ipfs node's config: ${JSON.stringify(await node.config.get('Addresses'), null, 2)}`)
setInterval(async () => {
try {
const peers = await node.swarm.peers()
if (peers.length > 0)
console.log(`The node now has ${peers.length} peers.`)
} catch (err) {
console.log('An error occurred trying to check out peers:', err)
}
}, 2000)
}
main()
It starts OK with the output:
node public/node-ipfs.js
generating 2048-bit (rsa only) rsa keypair...
to get started, enter:
jsipfs cat /ipfs/QmfGBRT6BbWJd7yUc2uYdaUZJBbnEFvTqehPFoSMQ6wgdr/readme
Swarm listening on /ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/Qma5nB1MDePZoFcgztXGDYr9K7VdiVZhQrbd5cz9DEXvis
ipfs node's config: {
"Swarm": [
"/ip4/0.0.0.0/tcp/4002",
"/ip4/127.0.0.1/tcp/4003/ws"
],
"API": "/ip4/127.0.0.1/tcp/5002",
"Gateway": "/ip4/127.0.0.1/tcp/9090",
"Delegates": [
"/dns4/node0.delegate.ipfs.io/tcp/443/https",
"/dns4/node1.delegate.ipfs.io/tcp/443/https",
"/dns4/node2.delegate.ipfs.io/tcp/443/https",
"/dns4/node3.delegate.ipfs.io/tcp/443/https"
]
}
What address should I use for browser.js? /ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/Qma5nB1MDePZoFcgztXGDYr9K7VdiVZhQrbd5cz9DEXvis
? I tried it but peers didn't seem to connect. I receive 10 external peers on browser.js but not the local one. Node.js does not log any peers.
The node now has 10 peers. bundle.js:114827:15
peers: [
{
"addr": "/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd",
"peer": "QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd"
},
...
]
How to correctly set bootstrappers
? For now I've hardcoded them directly but in the comments you can see my alternative attempts.
Some minor notes. I see that in browser.js, Bootstrap.tag
is disabled: enabled: false,
. Is it correct? Also peerId
is not used for new Libp2p({
.
browser.js that I used:
const Libp2p = require('libp2p')
const IPFS = require('ipfs')
const WebRTCDirect = require('libp2p-webrtc-direct')
const Mplex = require('libp2p-mplex')
const {NOISE} = require('libp2p-noise')
const Bootstrap = require('libp2p-bootstrap')
const createLibp2p = (opts, bootstrappers) => {
const peerId = opts.peerId
return new Libp2p({
peerId,
modules: {
transport: [WebRTCDirect],
streamMuxer: [Mplex],
connEncryption: [NOISE],
peerDiscovery: [Bootstrap]
},
config: {
peerDiscovery: {
[Bootstrap.tag]: {
enabled: false,
list: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/Qma5nB1MDePZoFcgztXGDYr9K7VdiVZhQrbd5cz9DEXvis']
}
}
}
})
}
async function main () {
const node = await IPFS.create({
repo: 'ipfs-' + Math.random(),
lib2p: createLibp2p,
// How to correctly set bootstrappers?
// libp2p: (...args) => createLibp2p(...args, ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/Qma5nB1MDePZoFcgztXGDYr9K7VdiVZhQrbd5cz9DEXvis']),
// Bootstrap: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/Qma5nB1MDePZoFcgztXGDYr9K7VdiVZhQrbd5cz9DEXvis']
})
setInterval(async () => {
try {
const peers = await node.swarm.peers()
console.log(`The node now has ${peers.length} peers.`)
console.log(`peers: ${JSON.stringify(peers, null, 2)}`)
} catch (err) {
console.log('An error occurred trying to check our peers:', err)
}
}, 30000)
}
document.addEventListener('DOMContentLoaded', async () => {
main()
})
Sorry. I missed the notification for the latest message.
server.js
const Libp2p = require('libp2p')
const IPFS = require('ipfs')
const Bootstrap = require('libp2p-bootstrap')
const WebRTCDirect = require('libp2p-webrtc-direct')
const Mplex = require('libp2p-mplex')
const {NOISE} = require('libp2p-noise')
const libp2pBundle = (opts) => {
const peerId = opts.peerId
return new Libp2p({
peerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
},
modules: {
transport: [WebRTCDirect],
streamMuxer: [Mplex],
connEncryption: [NOISE]
},
config: {
peerDiscovery: {
[Bootstrap.tag]: {
enabled: false,
}
}
}
})
}
async function main () {
const node = await IPFS.create({
repo: 'ipfs-' + Math.random(),
libp2p: libp2pBundle
})
console.log(`ipfs node's id: ${JSON.stringify(await node.id()}`)
setInterval(async () => {
try {
const peers = await node.swarm.peers()
if (peers.length > 0)
console.log(`The node now has ${peers.length} peers.`)
} catch (err) {
console.log('An error occurred trying to check out peers:', err)
}
}, 2000)
}
main()
Just changed bootstrap discovery to false
and the node log in the context of this experiment. If you want your node to connect to the public network, you should not disable the bootstrap, but in this case it will be easy to see what other nodes connect, as the ones connecting with you were bootstrap nodes.
Moving into your questions, the bootstrap address is good! /ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/Qma5nB1MDePZoFcgztXGDYr9K7VdiVZhQrbd5cz9DEXvis
It should always be the same as presented in Node.js node logs as Swarm listening on ...
. You don't need to move them from the function, and can have them as you did.
The problem to not get the connection might be the bootstrap set to false
. Sorry, I did a copy paste and forgot to change it to true. And also you did good in adding the peerId.
Let me know if you got this to work with bootstrap enabled. If not, do you have this demo in any repo I can try?
I tried your suggestions, I still can't see the connection. The repo is here https://github.com/vogdb/ipfs-custom-lib2p. Readme contains the recipe, I use to test. Please let me know if anything to add there.
Thanks for reaching out @vogdb
I looked into this, and while there is an issue with your code, I also found some bugs on our code that I created PRs to fix (you can see them linked above this comment). I will create a PR to fix your module for now
Thank you for your changes. A couple of remaining questions from me.
There is no direct documentation on how to do this at the moment. If you are willing to help with that once you create your setup it would be super helpful.
How you recommend to update documentation? Should I create a separate page in this repo? In js-ipfs repo? Or write more documentation in ipfs-custom-lib2p and move it under https://github.com/ipfs as an example?
One thing that bothers me now is that I have to copy-paste the address of node.js node into browser's node. I mean this code in browser-ipfs.js
config: {
peerDiscovery: {
enabled: true,
list: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/QmPj9ZZ6notLfV9khV1FtxH1Goe5sVaUyqgoXrTYQWp382']
}
}
}
Is there a way to avoid this long hash QmPj9ZZ6notLfV9khV1FtxH1Goe5sVaUyqgoXrTYQWp382
? Or at least shorten it to 6 symbols max, so a user can type it.
How you recommend to update documentation? Should I create a separate page in this repo? In js-ipfs repo? Or write more documentation in ipfs-custom-lib2p and move it under https://github.com/ipfs as an example?
Probably an example in the libp2p repo would be the ideal https://github.com/libp2p/js-libp2p/tree/master/examples . While you are using IPFS here, the main components used are libp2p. You can also extend the IPFS example https://github.com/ipfs/js-ipfs/tree/master/examples/custom-libp2p to reference this example, or missing bits to how to configure libp2p within IPFS.
Is there a way to avoid this long hash QmPj9ZZ6notLfV9khV1FtxH1Goe5sVaUyqgoXrTYQWp382? Or at least shorten it to 6 symbols max, so a user can type it.
The hash is a cryptographically generated identifier from the Peer key pair. This way, it is not possible to shorten it. I understand your point, but this is something needed
Thank you for clarifying. I'm waiting then for #97. After its merge and release, I will update the documentation.
@vogdb closing this issue as I am releasing a new version of the module with the fix now. Feel free to re-open if further issues appear
I've just checked. It works. Thank you. One thing to notice is that it didn't work in Firefox 84.0.2 (64-bit) Ubuntu Linux. Worked in Chromium Version 88.0.4324.96 (Official Build) snap (64-bit).
One thing to notice is that it didn't work in Firefox 84.0.2 (64-bit) Ubuntu Linux. Worked in Chromium Version 88.0.4324.96 (Official Build) snap (64-bit).
Thanks for this feedback. Can you open a new issue with this information so that I can have a look soon
@vasco-santos sorry for pinging here. I'm trying to find a company that works with IPFS/Libp2p. Can you recommend one? So far, I could find only Textile. I'm thinking to switch to IPFS/Libp2p fulltime.
Hey @vogdb You can reach out to andre@moxy.studio via email. I already talked with him
Thank you!
Can you please advice on how to use it with an IPFS node in node.js? I tried this snippet:
But received:
The main IPFS node was started via
jsipfs daemon
: