From a4090c7382a2f0534cd776f6f15f3f02d6987de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=A9=B7=E5=A9=B7?= Date: Thu, 30 Apr 2020 14:57:49 +0800 Subject: [PATCH] Update the links to tutorials (#151) * update readme and organize the example folder * adding package list * add packages done * basic readme done * fix the go-daemon example folder * add go-daemon folder in readme * fix readme icon * add badges * add nim min version * Update README background Co-Authored-By: Dmitriy Ryajov * fix all the comments * Update README.md wording Co-Authored-By: Dmitriy Ryajov * fix file path in examples/ * add comments to example * add comments to directchat and fix start.nim * remove unnecessary modules from directchat * del customdata * improve directchat * finish second.nim * removea gcsafe * with err * change var to let * remove final.nim * fix comments on pull request * fix comments on pull request * replace result with return * add hint when start and exit command * update output string * fix above comments * add api documentation * fix readme format * update readme format * readme table of content done * fix format * fix format * include links to the tutorial article Co-authored-by: Dmitriy Ryajov --- README.md | 11 +- docs/README.md | 29 +++++ docs/api/data_types/peer.md | 0 docs/api/data_types/peerinfo.md | 0 docs/api/libp2p/daemonapi.md | 56 ++++++++++ docs/api/libp2p/interop.md | 0 docs/api/pubsub/floodsub.md | 0 docs/api/pubsub/gossipsub.md | 0 docs/api/pubsub/pubsub.md | 0 docs/api/secure_channels/secio.md | 0 docs/api/stream_multiplexers/mplex.md | 0 docs/api/transports/tcptransport.md | 0 docs/api/utilities/crypto.md | 0 docs/api/utilities/secp256k1.md | 0 docs/tutorial/directchat/second.nim | 151 ++++++++++++++++++++++++++ docs/tutorial/directchat/start.nim | 39 +++++++ 16 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 docs/README.md create mode 100644 docs/api/data_types/peer.md create mode 100644 docs/api/data_types/peerinfo.md create mode 100644 docs/api/libp2p/daemonapi.md create mode 100644 docs/api/libp2p/interop.md create mode 100644 docs/api/pubsub/floodsub.md create mode 100644 docs/api/pubsub/gossipsub.md create mode 100644 docs/api/pubsub/pubsub.md create mode 100644 docs/api/secure_channels/secio.md create mode 100644 docs/api/stream_multiplexers/mplex.md create mode 100644 docs/api/transports/tcptransport.md create mode 100644 docs/api/utilities/crypto.md create mode 100644 docs/api/utilities/secp256k1.md create mode 100644 docs/tutorial/directchat/second.nim create mode 100644 docs/tutorial/directchat/start.nim diff --git a/README.md b/README.md index a54943941..d0877d550 100644 --- a/README.md +++ b/README.md @@ -61,16 +61,21 @@ nimble install libp2p ## Usage ### API -The specification is available on [API.md](docs/API.md) (coming soon). +The specification is available in the [docs/api](docs/api) folder. ### Getting Started Please read the [GETTING_STARTED.md](docs/GETTING_STARTED.md) guide. ### Tutorials and Examples -Examples can be found in the [examples folder](/examples). +Example code can be found in the [examples folder](/examples). +#### Direct Chat Tutorial +- [Part I](https://our.status.im/nim-libp2p-tutorial-a-peer-to-peer-chat-example-1/): Set up the main function and use multi-thread for processing IO. +- [Part II](https://our.status.im/nim-libp2p-tutorial-a-peer-to-peer-chat-example-2/): Dial remote peer and allow customized user input commands. +- [Part III](https://our.status.im/nim-libp2p-tutorial-a-peer-to-peer-chat-example-3/): Configure and establish a libp2p node. + ### Using the Go Daemon -Please find the installation and usage intructions in [GO_DAEMON.md](docs/GO_DAEMON.md). +Please find the installation and usage intructions in [daemonapi.md](docs/api/libp2p/daemonapi.md). Examples can be found in the [examples/go-daemon folder](https://github.com/status-im/nim-libp2p/tree/readme/examples/go-daemon); diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..f6a82fbd2 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,29 @@ +# Introduction +This folder contains the documentation for each nim-libp2p module and the sample code for the tutorials. + +# Table of Contents +### [Getting Started](GETTING_STARTED.md) +### Tutorials +- P2P Chat Example + - [part I](tutorial/directchat/start.nim) + - [part II](tutorial/directchat/second.nim) +### API Specifications +- libp2p + - [libp2p-daemon-client](api/libp2p/daemonapi.md) + - [interop-libp2p](api/libp2p/interop.md) +- transports + - [libp2p-tcp](api/transports/tcptransport.md) +- secure channels + - [libp2p-secio](api/secure_channels/secio.md) +- stream multiplexers + - [libp2p-mplex](api/stream_multiplexers/mplex.md) +- utilities + - [libp2p-crypto](api/utilities/crypto.md) + - [libp2p-crypto-secp256k1](api/utilities/secp256k1.md) +- data types + - [peer-id](api/data_types/peer.md) + - [peer-info](api/data_types/peerinfo.md) +- pubsub + - [libp2p-pubsub](api/pubsub/pubsub.md) + - [libp2p-floodsub](api/pubsub/floodsub.md) + - [libp2p-gossipsub](api/pubsub/gossipsub.md) \ No newline at end of file diff --git a/docs/api/data_types/peer.md b/docs/api/data_types/peer.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/data_types/peerinfo.md b/docs/api/data_types/peerinfo.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/libp2p/daemonapi.md b/docs/api/libp2p/daemonapi.md new file mode 100644 index 000000000..ebddd31e8 --- /dev/null +++ b/docs/api/libp2p/daemonapi.md @@ -0,0 +1,56 @@ +# Table of Contents +- [Introduction](#introduction) +- [Installation](#installation) +- [Usage](#usage) + - [Example](#example) + - [Getting Started](#getting-started) + +# Introduction +This is a libp2p-backed daemon wrapping the functionalities of go-libp2p for use in Nim.
+For more information about the go daemon, check out [this repository](https://github.com/libp2p/go-libp2p-daemon). + +# Installation +```sh +# clone and install dependencies +git clone https://github.com/status-im/nim-libp2p +cd nim-libp2p +nimble install + +# perform unit tests +nimble test + +# update the git submodule to install the go daemon +git submodule update --init --recursive +go version +git clone https://github.com/libp2p/go-libp2p-daemon +cd go-libp2p-daemon +git checkout v0.0.1 +go install ./... +cd .. +``` + +# Usage + +## Example +Examples can be found in the [examples folder](https://github.com/status-im/nim-libp2p/tree/readme/examples/go-daemon) + +## Getting Started +Try out the chat example. Full code can be found [here](https://github.com/status-im/nim-libp2p/blob/master/examples/chat.nim): + +```bash +nim c -r --threads:on examples\chat.nim +``` + +This will output a peer ID such as `QmbmHfVvouKammmQDJck4hz33WvVktNEe7pasxz2HgseRu` which you can use in another instance to connect to it. + +```bash +./example/chat +/connect QmbmHfVvouKammmQDJck4hz33WvVktNEe7pasxz2HgseRu +``` + +You can now chat between the instances! + +![Chat example](https://imgur.com/caYRu8K.gif) + + + diff --git a/docs/api/libp2p/interop.md b/docs/api/libp2p/interop.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/pubsub/floodsub.md b/docs/api/pubsub/floodsub.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/pubsub/gossipsub.md b/docs/api/pubsub/gossipsub.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/pubsub/pubsub.md b/docs/api/pubsub/pubsub.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/secure_channels/secio.md b/docs/api/secure_channels/secio.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/stream_multiplexers/mplex.md b/docs/api/stream_multiplexers/mplex.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/transports/tcptransport.md b/docs/api/transports/tcptransport.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/utilities/crypto.md b/docs/api/utilities/crypto.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api/utilities/secp256k1.md b/docs/api/utilities/secp256k1.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorial/directchat/second.nim b/docs/tutorial/directchat/second.nim new file mode 100644 index 000000000..3addd81a3 --- /dev/null +++ b/docs/tutorial/directchat/second.nim @@ -0,0 +1,151 @@ +when not(compileOption("threads")): + {.fatal: "Please, compile this program with the --threads:on option!".} + +import tables, strformat, strutils +import chronos +import ../libp2p/[switch, + multistream, + crypto/crypto, + protocols/identify, + connection, + transports/transport, + transports/tcptransport, + multiaddress, + peerinfo, + peer, + protocols/protocol, + protocols/secure/secure, + protocols/secure/secio, + muxers/muxer, + muxers/mplex/mplex, + muxers/mplex/types] + +const ChatCodec = "/nim-libp2p/chat/1.0.0" +const DefaultAddr = "/ip4/127.0.0.1/tcp/55505" + +const Help = """ + Commands: /[?|hep|connect|disconnect|exit] + help: Prints this help + connect: dials a remote peer + disconnect: ends current session + exit: closes the chat +""" + +type ChatProto = ref object of LPProtocol + switch: Switch # a single entry point for dialing and listening to peer + transp: StreamTransport # transport streams between read & write file descriptor + conn: Connection # create and close read & write stream + connected: bool # if the node is connected to another peer + started: bool # if the node has started + +# copied from https://github.com/status-im/nim-beacon-chain/blob/0ed657e953740a92458f23033d47483ffa17ccb0/beacon_chain/eth2_network.nim#L109-L115 +proc initAddress(T: type MultiAddress, str: string): T = + let address = MultiAddress.init(str) + if IPFS.match(address) and matchPartial(multiaddress.TCP, address): + result = address + else: + raise newException(MultiAddressError, + "Invalid bootstrap node multi-address") + +proc dialPeer(p: ChatProto, address: string) {.async.} = + let multiAddr = MultiAddress.initAddress(address); + let parts = address.split("/") + let remotePeer = PeerInfo.init(parts[^1], + [multiAddr]) + + echo &"dialing peer: {multiAddr}" + p.conn = await p.switch.dial(remotePeer, ChatCodec) + p.connected = true + +proc readAndPrint(p: ChatProto) {.async.} = + while true: + while p.connected: + echo cast[string](await p.conn.readLp()) + await sleepAsync(100.millis) + +proc writeAndPrint(p: ChatProto) {.async.} = + while true: + if not p.connected: + echo "type an address or wait for a connection:" + echo "type /[help|?] for help" + + let line = await p.transp.readLine() + if line.startsWith("/help") or line.startsWith("/?") or not p.started: + echo Help + continue + + if line.startsWith("/disconnect"): + echo "Ending current session" + if p.connected and p.conn.closed.not: + await p.conn.close() + p.connected = false + elif line.startsWith("/connect"): + if p.connected: + var yesno = "N" + echo "a session is already in progress, do you want end it [y/N]?" + yesno = await p.transp.readLine() + if yesno.cmpIgnoreCase("y") == 0: + await p.conn.close() + p.connected = false + elif yesno.cmpIgnoreCase("n") == 0: + continue + else: + echo "unrecognized response" + continue + + echo "enter address of remote peer" + let address = await p.transp.readLine() + if address.len > 0: + await p.dialPeer(address) + + elif line.startsWith("/exit"): + if p.connected and p.conn.closed.not: + await p.conn.close() + p.connected = false + + await p.switch.stop() + echo "quitting..." + quit(0) + else: + if p.connected: + await p.conn.writeLp(line) + else: + try: + if line.startsWith("/") and "ipfs" in line: + await p.dialPeer(line) + except: + echo &"unable to dial remote peer {line}" + echo getCurrentExceptionMsg() + +proc readWriteLoop(p: ChatProto) {.async.} = + asyncCheck p.writeAndPrint() # execute the async function but does not block + asyncCheck p.readAndPrint() + +proc processInput(rfd: AsyncFD) {.async.} = + let transp = fromPipe(rfd) + while true: + let a = await transp.readLine() + echo "You just entered: " & a + +proc readInput(wfd: AsyncFD) {.thread.} = + ## This procedure performs reading from `stdin` and sends data over + ## pipe to main thread. + let transp = fromPipe(wfd) + + while true: + let line = stdin.readLine() + discard waitFor transp.write(line & "\r\n") + +proc main() {.async.} = + let (rfd, wfd) = createAsyncPipe() + if rfd == asyncInvalidPipe or wfd == asyncInvalidPipe: + raise newException(ValueError, "Could not initialize pipe!") + + var thread: Thread[AsyncFD] + thread.createThread(readInput, wfd) + + await processInput(rfd) + +when isMainModule: # isMainModule = true when the module is compiled as the main file + waitFor(main()) + \ No newline at end of file diff --git a/docs/tutorial/directchat/start.nim b/docs/tutorial/directchat/start.nim new file mode 100644 index 000000000..7e7b8326f --- /dev/null +++ b/docs/tutorial/directchat/start.nim @@ -0,0 +1,39 @@ +when not(compileOption("threads")): + {.fatal: "Please, compile this program with the --threads:on option!".} + +import chronos # an efficient library for async + +proc processInput(rfd: AsyncFD) {.async.} = + echo "Type something below to see if the multithread IO works:\nType 'exit' to exit." + + let transp = fromPipe(rfd) + while true: + let a = await transp.readLine() + + if a == "exit": + quit(0); + + echo "You just entered: " & a + +proc readInput(wfd: AsyncFD) {.thread.} = + ## This procedure performs reading from `stdin` and sends data over + ## pipe to main thread. + let transp = fromPipe(wfd) + + while true: + let line = stdin.readLine() + discard waitFor transp.write(line & "\r\n") + +proc main() {.async.} = + let (rfd, wfd) = createAsyncPipe() + if rfd == asyncInvalidPipe or wfd == asyncInvalidPipe: + raise newException(ValueError, "Could not initialize pipe!") + + var thread: Thread[AsyncFD] + thread.createThread(readInput, wfd) + + await processInput(rfd) + +when isMainModule: # isMainModule = true when the module is compiled as the main file + waitFor(main()) + \ No newline at end of file