Simple ping tutorial
Hi all, welcome to the first nim-libp2p tutorial!
This tutorial is for everyone who is interested in building peer-to-peer applications. No Nim programming experience is needed.
To give you a quick overview, Nim is the programming language we are using and nim-libp2p is the Nim implementation of libp2p, a modular library that enables the development of peer-to-peer network applications.
Hope you'll find it helpful in your journey of learning. Happy coding! ;)
Before you start
The only prerequisite here is Nim, the programming language with a Python-like syntax and a performance similar to C. Detailed information can be found here.
Install Nim via their official website.
Check Nim's installation via nim --version
and its package manager Nimble via nimble --version
.
You can now install the latest version of nim-libp2p
:
A simple ping application
We'll start by creating a simple application, which is starting two libp2p switch, and pinging each other using the Ping protocol.
You can find the source of this tutorial (and other tutorials) in the libp2p/examples folder!
Let's create a part1.nim
, and import our dependencies:
nim-libp2p
Next, we'll create an helper procedure to create our switches. A switch needs a bit of configuration, and it will be easier to do this configuration only once:
proc createSwitch(ma: MultiAddress, rng: ref HmacDrbgContext): Switch =
var switch = SwitchBuilder
.new()
.withRng(rng) # Give the application RNG
.withAddress(ma) # Our local address(es)
.withTcpTransport() # Use TCP as transport
.withMplex() # Use Mplex as muxer
.withNoise() # Use Noise as secure manager
.build()
return switch
You can of course tweak this, to use a different or multiple transport, or tweak the configuration of Mplex and Noise, but this is some sane defaults that we'll use going forward.
Let's now start to create our main procedure:
proc main() {.async, gcsafe.} =
let
rng = newRng()
localAddress = MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
pingProtocol = Ping.new(rng=rng)
rng
instance, our localAddress
, and an instance of the Ping
protocol.
The address is in the MultiAddress format. The port 0
means "take any port available".
tryGet
is procedure which is part of nim-result, that will throw an exception if the supplied MultiAddress is invalid.
We can now create our two switches:
let
switch1 = createSwitch(localAddress, rng)
switch2 = createSwitch(localAddress, rng)
switch1.mount(pingProtocol)
await switch1.start()
await switch2.start()
pingProtocol
on our first switch. This means that the first switch will actually listen for any ping requests coming in, and handle them accordingly.
Now that we've started the nodes, they are listening for incoming peers.
We can find out which port was attributed, and the resulting local addresses, by using switch1.peerInfo.addrs
.
We'll dial the first switch from the second one, by specifying it's Peer ID, it's MultiAddress and the Ping
protocol codec:
Ping
connection setup between the second and the first switch, we can use it to actually ping the node:
# ping the other node and echo the ping duration
echo "ping: ", await pingProtocol.ping(conn)
# We must close the connection ourselves when we're done with it
await conn.close()
main
procedure:
await allFutures(switch1.stop(), switch2.stop()) # close connections and shutdown all transports
waitFor(main())
nim c -r part1.nim
, and you should see the dialing sequence, ending with a ping output.
In the next tutorial, we'll look at how to create our own custom protocol.