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 <dryajov@gmail.com> * fix all the comments * Update README.md wording Co-Authored-By: Dmitriy Ryajov <dryajov@gmail.com> * 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 <dryajov@gmail.com>
This commit is contained in:
parent
e1928456a7
commit
a4090c7382
11
README.md
11
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);
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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. <br>
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -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())
|
||||
|
|
@ -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())
|
||||
|
Loading…
Reference in New Issue