2020-03-16 07:43:08 +00:00
|
|
|
# Getting Started
|
|
|
|
Welcome to nim-libp2p! This guide will walk you through a peer to peer chat example. <br>
|
|
|
|
The full code can be found in [directchat.nim](examples/directchat.nim) under the examples folder.
|
|
|
|
|
|
|
|
|
|
|
|
### Direct Chat Example
|
|
|
|
To run nim-libp2p, add it to your project's nimble file and spawn a node as follows:
|
|
|
|
|
|
|
|
```nim
|
|
|
|
import tables
|
|
|
|
import chronos
|
|
|
|
import ../libp2p/[switch,
|
|
|
|
multistream,
|
|
|
|
protocols/identify,
|
|
|
|
connection,
|
|
|
|
transports/transport,
|
|
|
|
transports/tcptransport,
|
|
|
|
multiaddress,
|
|
|
|
peerinfo,
|
|
|
|
crypto/crypto,
|
|
|
|
peer,
|
|
|
|
protocols/protocol,
|
|
|
|
muxers/muxer,
|
|
|
|
muxers/mplex/mplex,
|
|
|
|
muxers/mplex/types,
|
|
|
|
protocols/secure/secio,
|
|
|
|
protocols/secure/secure]
|
|
|
|
|
|
|
|
const TestCodec = "/test/proto/1.0.0" # custom protocol string
|
|
|
|
|
|
|
|
type
|
|
|
|
TestProto = ref object of LPProtocol # declare a custom protocol
|
|
|
|
|
|
|
|
method init(p: TestProto) {.gcsafe.} =
|
|
|
|
# handle incoming connections in closure
|
|
|
|
proc handle(conn: Connection, proto: string) {.async, gcsafe.} =
|
2020-05-08 20:58:23 +00:00
|
|
|
echo "Got from remote - ", cast[string](await conn.readLp(1024))
|
2020-03-16 07:43:08 +00:00
|
|
|
await conn.writeLp("Hello!")
|
|
|
|
await conn.close()
|
|
|
|
|
|
|
|
p.codec = TestCodec # init proto with the correct string id
|
|
|
|
p.handler = handle # set proto handler
|
|
|
|
|
|
|
|
proc createSwitch(ma: MultiAddress): (Switch, PeerInfo) =
|
|
|
|
## Helper to create a swith
|
|
|
|
|
|
|
|
let seckey = PrivateKey.random(RSA) # use a random key for peer id
|
|
|
|
var peerInfo = PeerInfo.init(seckey) # create a peer id and assign
|
|
|
|
peerInfo.addrs.add(ma) # set this peer's multiaddresses (can be any number)
|
|
|
|
|
|
|
|
let identify = newIdentify(peerInfo) # create the identify proto
|
|
|
|
|
|
|
|
proc createMplex(conn: Connection): Muxer =
|
|
|
|
# helper proc to create multiplexers,
|
|
|
|
# use this to perform any custom setup up,
|
|
|
|
# such as adjusting timeout or anything else
|
|
|
|
# that the muxer requires
|
|
|
|
result = newMplex(conn)
|
|
|
|
|
|
|
|
let mplexProvider = newMuxerProvider(createMplex, MplexCodec) # create multiplexer
|
|
|
|
let transports = @[Transport(newTransport(TcpTransport))] # add all transports (tcp only for now, but can be anything in the future)
|
|
|
|
let muxers = {MplexCodec: mplexProvider}.toTable() # add all muxers
|
|
|
|
let secureManagers = {SecioCodec: Secure(newSecio(seckey))}.toTable() # setup the secio and any other secure provider
|
|
|
|
|
|
|
|
# create the switch
|
|
|
|
let switch = newSwitch(peerInfo,
|
|
|
|
transports,
|
|
|
|
identify,
|
|
|
|
muxers,
|
|
|
|
secureManagers)
|
|
|
|
result = (switch, peerInfo)
|
|
|
|
|
|
|
|
proc main() {.async, gcsafe.} =
|
|
|
|
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
|
|
|
|
let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
|
|
|
|
|
|
|
|
var peerInfo1, peerInfo2: PeerInfo
|
|
|
|
var switch1, switch2: Switch
|
|
|
|
(switch1, peerInfo1) = createSwitch(ma1) # create node 1
|
|
|
|
|
|
|
|
# setup the custom proto
|
|
|
|
let testProto = new TestProto
|
|
|
|
testProto.init() # run it's init method to perform any required initialization
|
|
|
|
switch1.mount(testProto) # mount the proto
|
|
|
|
var switch1Fut = await switch1.start() # start the node
|
|
|
|
|
|
|
|
(switch2, peerInfo2) = createSwitch(ma2) # create node 2
|
|
|
|
var switch2Fut = await switch2.start() # start second node
|
|
|
|
let conn = await switch2.dial(switch1.peerInfo, TestCodec) # dial the first node
|
|
|
|
|
|
|
|
await conn.writeLp("Hello!") # writeLp send a length prefixed buffer over the wire
|
|
|
|
# readLp reads length prefixed bytes and returns a buffer without the prefix
|
2020-05-08 20:58:23 +00:00
|
|
|
echo "Remote responded with - ", cast[string](await conn.readLp(1024))
|
2020-03-16 07:43:08 +00:00
|
|
|
|
|
|
|
await allFutures(switch1.stop(), switch2.stop()) # close connections and shutdown all transports
|
|
|
|
await allFutures(switch1Fut & switch2Fut) # wait for all transports to shutdown
|
|
|
|
|
|
|
|
waitFor(main())
|
|
|
|
```
|