Просмотр исходного кода

book: add network tools section and fix rendering on all sections

lunar-mining 4 лет назад
Родитель
Сommit
1b25019301
34 измененных файлов с 614 добавлено и 81 удалено
  1. 1 0
      Cargo.lock
  2. 9 4
      bin/dnetview/src/main.rs
  3. 14 9
      doc/src/SUMMARY.md
  4. 0 0
      doc/src/learn/dchat/creating-dchat/part-2.md
  5. 5 1
      doc/src/learn/dchat/creating-dchat/protocol-dchat.md
  6. 14 10
      doc/src/learn/dchat/creating-dchat/register-protocol.md
  7. 1 1
      doc/src/learn/dchat/creating-dchat/sending-messages.md
  8. 5 7
      doc/src/learn/dchat/creating-dchat/ui.md
  9. 1 1
      doc/src/learn/dchat/creating-dchat/using-dchat.md
  10. 3 3
      doc/src/learn/dchat/dchat.md
  11. 28 9
      doc/src/learn/dchat/deployment/deploy.md
  12. 5 5
      doc/src/learn/dchat/deployment/error-handling.md
  13. 1 1
      doc/src/learn/dchat/deployment/getting-started.md
  14. 1 1
      doc/src/learn/dchat/deployment/part-1.md
  15. 35 1
      doc/src/learn/dchat/deployment/seed-node.md
  16. 1 1
      doc/src/learn/dchat/deployment/sessions.md
  17. 41 3
      doc/src/learn/dchat/deployment/settings.md
  18. 13 14
      doc/src/learn/dchat/deployment/start-run-stop.md
  19. 5 5
      doc/src/learn/dchat/deployment/writing-a-daemon.md
  20. 46 0
      doc/src/learn/dchat/network-tools/accept-addr.md
  21. 112 1
      doc/src/learn/dchat/network-tools/darkfi-rpc.md
  22. 26 0
      doc/src/learn/dchat/network-tools/debug.md
  23. 0 2
      doc/src/learn/dchat/network-tools/dnetview.md
  24. 60 0
      doc/src/learn/dchat/network-tools/get-info.md
  25. BIN
      doc/src/learn/dchat/network-tools/images/dnetview-dchatmsg.jpg
  26. BIN
      doc/src/learn/dchat/network-tools/images/dnetview-msgs.jpg
  27. BIN
      doc/src/learn/dchat/network-tools/images/dnetview-offline.jpg
  28. BIN
      doc/src/learn/dchat/network-tools/images/dnetview-online.jpg
  29. 44 0
      doc/src/learn/dchat/network-tools/jsonrpcinterface.md
  30. 0 2
      doc/src/learn/dchat/network-tools/network-tools.md
  31. 17 0
      doc/src/learn/dchat/network-tools/part-3.md
  32. 21 0
      doc/src/learn/dchat/network-tools/pong.md
  33. 37 0
      doc/src/learn/dchat/network-tools/server.md
  34. 68 0
      doc/src/learn/dchat/network-tools/using-dnetview.md

+ 1 - 0
Cargo.lock

@@ -1383,6 +1383,7 @@ dependencies = [
  "log",
  "num_cpus",
  "serde",
+ "serde_json",
  "simplelog",
  "smol",
  "toml",

+ 9 - 4
bin/dnetview/src/main.rs

@@ -40,7 +40,7 @@ use crate::{
     view::{IdMenu, MsgList, View},
 };
 
-use log::debug;
+//use log::debug;
 
 struct DnetView {
     name: String,
@@ -55,7 +55,7 @@ impl DnetView {
 
     // --> {"jsonrpc": "2.0", "method": "ping", "params": [], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": "pong", "id": 42}
-    async fn _ping(&self) -> Result<Value> {
+    async fn ping(&self) -> Result<Value> {
         let req = JsonRequest::new("ping", json!([]));
         self.rpc_client.request(req).await
     }
@@ -153,6 +153,11 @@ async fn try_connect(model: Arc<Model>, node_name: String, rpc_url: String) -> D
 
 async fn poll(client: DnetView, model: Arc<Model>) -> DnetViewResult<()> {
     loop {
+        match client.ping().await {
+            // TODO
+            Ok(reply) => {}
+            Err(e) => {}
+        }
         match client.get_info().await {
             Ok(reply) => {
                 if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
@@ -259,8 +264,8 @@ async fn parse_data(
     update_msgs(model.clone(), sessions.clone()).await?;
     update_new_id(model.clone()).await;
 
-    debug!("IDS: {:?}", model.ids.lock().await);
-    debug!("INFOS: {:?}", model.nodes.lock().await);
+    //debug!("IDS: {:?}", model.ids.lock().await);
+    //debug!("INFOS: {:?}", model.nodes.lock().await);
 
     Ok(())
 }

+ 14 - 9
doc/src/SUMMARY.md

@@ -27,24 +27,29 @@
   - [Research](learn/research.md)
   - [ZK explainer](learn/zk_explainer.md)
   - [Dchat](learn/dchat/dchat.md)
-    - [Deployment](learn/dchat/deployment/local-deployment.md)
+    - [Deployment](learn/dchat/deployment/part-1.md)
       - [Getting started](learn/dchat/deployment/getting-started.md)
       - [Writing a daemon](learn/dchat/deployment/writing-a-daemon.md)
       - [Sessions](learn/dchat/deployment/sessions.md)
       - [Settings](learn/dchat/deployment/settings.md)
       - [Error handling](learn/dchat/deployment/error-handling.md)
-      - [Running the network](learn/dchat/deployment/start-run-stop.md)
-      - [Seed node](learn/dchat/deployment/seed-node.md)
-      - [Deployment](learn/dchat/deployment/deployment.md)
-    - [Creating dchat](learn/dchat/creating-dchat/creating-dchat.md)
+      - [Start-Run-Stop](learn/dchat/deployment/start-run-stop.md)
+      - [Seed](learn/dchat/deployment/seed-node.md)
+      - [Deploy](learn/dchat/deployment/deploy.md)
+    - [Creating dchat](learn/dchat/creating-dchat/part-2.md)
       - [Message](learn/dchat/creating-dchat/message.md)
       - [Protocols](learn/dchat/creating-dchat/protocols.md)
       - [ProtocolDchat](learn/dchat/creating-dchat/protocol-dchat.md)
-      - [Registering a protocol](learn/dchat/creating-dchat/register-protocol.md)
+      - [Register protocol](learn/dchat/creating-dchat/register-protocol.md)
       - [Sending messages](learn/dchat/creating-dchat/sending-messages.md)
       - [Slap on a UI](learn/dchat/creating-dchat/ui.md)
       - [Using dchat](learn/dchat/creating-dchat/using-dchat.md)
-    - [Net tools](learn/dchat/network-tools/network-tools.md)
-      - [DarkFi RPC](learn/dchat/network-tools/darkfi-rpc.md)
-      - [Dnetview](learn/dchat/network-tools/dnetview.md)
+    - [Net tools](learn/dchat/network-tools/part-3.md)
+      - [RPC interface](learn/dchat/network-tools/jsonrpcinterface.md)
+      - [Accept addr](learn/dchat/network-tools/accept-addr.md)
+      - [Adding methods](learn/dchat/network-tools/pong.md)
+      - [RPC server](learn/dchat/network-tools/server.md)
+      - [get_info](learn/dchat/network-tools/get-info.md)
+      - [Using dnetview](learn/dchat/network-tools/using-dnetview.md)
+      - [Debugging](learn/dchat/network-tools/debug.md)
 

+ 0 - 0
doc/src/learn/dchat/creating-dchat/creating-dchat.md → doc/src/learn/dchat/creating-dchat/part-2.md


+ 5 - 1
doc/src/learn/dchat/creating-dchat/protocol-dchat.md

@@ -46,5 +46,9 @@ As a final step, let's add that task to the `ProtocolJobManager` that is invoked
 in `start()`:
 
 ```rust
-{{#include ../../../../../example/dchat/src/protocol_dchat.rs:42::}}
+{{#include ../../../../../example/dchat/src/protocol_dchat.rs:44}}
+        //...
+{{#include ../../../../../example/dchat/src/protocol_dchat.rs:47}}
+        //...
+{{#include ../../../../../example/dchat/src/protocol_dchat.rs:50}}
 ```

+ 14 - 10
doc/src/learn/dchat/creating-dchat/register-protocol.md

@@ -9,7 +9,7 @@ handle to the p2p network contained in the `Dchat` struct. It will then
 call `register()` on the registry and pass the `ProtocolDchat` constructor.
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:84:95}}
+{{#include ../../../../../example/dchat/src/main.rs:86:97}}
 ```
 
 There's a lot going on here. `register()` takes a closure with two
@@ -31,7 +31,7 @@ instead we wrap the `async move` in a `move` in order to capture the
 variables needed by `ProtocolDchat::init()`.
 
 Notice the use of a `bitflag`. We use `!SESSION_SEED` to specify that
-this protocol should be performed by every session, not including the
+this protocol should be performed by all sessions aside from the
 seed session.
 
 Also notice that `register_protocol()` requires a `DchatMsgsBuffer` that we
@@ -40,29 +40,33 @@ in `main()` and pass it to `Dchat::new()`. Let's add `DchatMsgsBuffer` to the
 `Dchat` struct definition first.
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:13:17}}
+{{#include ../../../../../example/dchat/src/main.rs:13:16}}
+{{#include ../../../../../example/dchat/src/main.rs:18}}
 
-{{#include ../../../../../example/dchat/src/main.rs:26:34}}
-{{#include ../../../../../example/dchat/src/main.rs:119}}
+{{#include ../../../../../example/dchat/src/main.rs:28:36}}
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:121}}
 ```
 
 And initialize it:
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:163:164}}
+{{#include ../../../../../example/dchat/src/main.rs:183:184}}
     //...
-{{#include ../../../../../example/dchat/src/main.rs:182:184}}
+{{#include ../../../../../example/dchat/src/main.rs:205}}
+
+    let mut dchat = Dchat::new(p2p, msgs);
     //...
-{{#include ../../../../../example/dchat/src/main.rs:197}}
+{{#include ../../../../../example/dchat/src/main.rs:224}}
 ```
 
 Finally, call `register_protocol()` in `dchat::start()`:
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:97:103}}
+{{#include ../../../../../example/dchat/src/main.rs:99:105}}
         self.p2p.clone().run(ex.clone()).await?;
 
-{{#include ../../../../../example/dchat/src/main.rs:110:112}}
+{{#include ../../../../../example/dchat/src/main.rs:110:114}}
 ```
 Now try running Alice and Bob and seeing what debug output you get. Keep
 an eye out for the following:

+ 1 - 1
doc/src/learn/dchat/creating-dchat/sending-messages.md

@@ -8,7 +8,7 @@ introduce us to a new p2p method that is essential to our chat app:
 `p2p.broadcast()`.
 
 ```
-{{#include ../../../../../example/dchat/src/main.rs:114:118}}
+{{#include ../../../../../example/dchat/src/main.rs:116:120}}
 ```
 
 We pass a `String` called msg that will be taken from user input. We use

+ 5 - 7
doc/src/learn/dchat/creating-dchat/ui.md

@@ -9,19 +9,17 @@ simply displays the messages that `ProtocolDchat` has saved in the
 Here's what is should look like:
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:36:82}}
+{{#include ../../../../../example/dchat/src/main.rs:38:84}}
 ```
 
 We'll call `menu()` inside of `dchat::start()` along with our other methods, like so:
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:97:98}}
-
-{{#include ../../../../../example/dchat/src/main.rs:103}}
+{{#include ../../../../../example/dchat/src/main.rs:99:100}}
 
+{{#include ../../../../../example/dchat/src/main.rs:104:105}}
         self.p2p.clone().run(ex.clone()).await?;
-
-{{#include ../../../../../example/dchat/src/main.rs:108:112}}
+{{#include ../../../../../example/dchat/src/main.rs:107:114}}
 ```
 
 But wait- if you try running this code, you'll notice that the menu never
@@ -33,5 +31,5 @@ to detach it in the background.
 The complete implementaion looks like this:
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:97:112}}
+{{#include ../../../../../example/dchat/src/main.rs:99:114}}
 ```

+ 1 - 1
doc/src/learn/dchat/creating-dchat/using-dchat.md

@@ -5,7 +5,7 @@ We are finally ready to test our program. Spin up 5 different terminals.
 In terminal 1, run `lilith`.
 
 ```
-cargo run --dchat
+./lilith
 ```
 
 In terminal 2, run Alice.

+ 3 - 3
doc/src/learn/dchat/dchat.md

@@ -4,7 +4,7 @@ This tutorial will teach you how to deploy an app on DarkFi's p2p network.
 
 We will create a terminal-based p2p chat app called dchat that we run
 in two different instances: an inbound and outbound node called Alice
-and Bob. Alice takes a message from stdin and broadcasts it to the
+and Bob. Alice takes a message from `stdin` and broadcasts it to the
 p2p network. When Bob receives the message on on the p2p network it is
 displayed his terminal.
 
@@ -12,8 +12,8 @@ Dchat will showcase some key concepts that you'll need to develop on
 the p2p network, in particular:
 
 * Understanding inbound, outbound and seed nodes.
-* Writing and registering a custom protocol.
-* Creating and subscribing to a custom message type.
+* Writing and registering a custom `Protocol`.
+* Creating and subscribing to a custom `Message` type.
 
 The source code for this tutorial can be found at
 [example/dchat](https://github.com/darkrenaissance/darkfi/tree/master/example/dchat).

+ 28 - 9
doc/src/learn/dchat/deployment/deployment.md → doc/src/learn/dchat/deployment/deploy.md

@@ -2,26 +2,45 @@
 
 Get ready to spin up a bunch of different terminals. We are going to
 run 3 nodes: Alice and Bob and our seed node. To run the seed node,
-go to the `lilith` directory and run it by passing `dchat` as an argument:
+go to the `lilith` directory and spawn a new config file by running it once:
 
 ```bash
-cargo run -- --dchat
+cd darkfi
+make BINS=lilith
+./lilith
+```
+
+You should see the following output:
+
+```
+Config file created in '"/home/USER/.config/darkfi/lilith_config.toml"'. Please review it and try again.
+ ```
+
+Add dchat to the config as follows, keeping in mind that the port number must match the seed we specified
+earlier in Alice and Bob's settings.
+
+```toml
+[network."dchat"]
+port = 50515
+```
+
+Now run `lilith`:
+
+```bash
+./lilith
 ```
 
 Here's what the debug output should look like:
 
 ```
-[DEBUG] (1) net: P2p::start() [BEGIN]
-[DEBUG] (1) net: SeedSession::start() [START]
+[INFO] Found configuration for network: dchat
+[INFO] Starting seed network node for dchat at: tcp://127.0.0.1:50515
 [WARN] Skipping seed sync process since no seeds are configured.
-[DEBUG] (1) net: P2p::start() [END]
-[DEBUG] (1) net: P2p::run() [BEGIN]
-[INFO] Starting inbound session on tcp://127.0.0.1:55555
-[DEBUG] (1) net: tcp transport: listening on 127.0.0.1:55555
+[INFO] Starting inbound session on tcp://127.0.0.1:50515
 [INFO] Starting 0 outbound connection slots.
 ```
 
-Next we'll run Alice.
+Next we'll head back to `dchat` and run Alice. 
 
 ```bash
 cargo run a

+ 5 - 5
doc/src/learn/dchat/deployment/error-handling.md

@@ -7,14 +7,14 @@ the case where a user forgets to add the command-line flag.
 {{#include ../../../../../example/dchat/src/dchat_error.rs:1:12}}
 ```
 
-Finally we can read the flag from the command-line by adding the following lines to main():
+Finally we can read the flag from the command-line by adding the following lines to `main()`:
 
 ```rust
 {{#include ../../../../../example/dchat/src/main.rs:13:14}}
-{{#include ../../../../../example/dchat/src/main.rs:17}}
+{{#include ../../../../../example/dchat/src/main.rs:18}}
 
-{{#include ../../../../../example/dchat/src/main.rs:163:172}}
-...
-{{#include ../../../../../example/dchat/src/main.rs:197}}
+{{#include ../../../../../example/dchat/src/main.rs:182:191}}
+//...
+{{#include ../../../../../example/dchat/src/main.rs:224}}
 ```
 

+ 1 - 1
doc/src/learn/dchat/deployment/getting-started.md

@@ -15,7 +15,7 @@ dchat. We'll need a few more external libraries too, so add these
 dependencies:
 
 ```
-{{#include ../../../../../example/dchat/Cargo.toml:10:26}}
+{{#include ../../../../../example/dchat/Cargo.toml:10:27}}
 ```
 
 

+ 1 - 1
doc/src/learn/dchat/deployment/local-deployment.md → doc/src/learn/dchat/deployment/part-1.md

@@ -6,4 +6,4 @@ introduce a number of key concepts:
 * p2p daemons
 * Inbound, outbound, manual and seed nodes
 * Understanding `Sessions`
-* `p2p.start()` and `p2p.run()`
+* `p2p.start()`, `p2p.run()` and `p2p.stop()`

+ 35 - 1
doc/src/learn/dchat/deployment/seed-node.md

@@ -5,7 +5,41 @@ p2p network into it.  Then we'll add `dchat::start()` to our async loop
 in the main function. 
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:163:197}}
+#[async_std::main]
+async fn main() -> Result<()> {
+    let settings: Result<Settings> = match std::env::args().nth(1) {
+        Some(id) => match id.as_str() {
+            "a" => alice(),
+            "b" => bob(),
+            _ => Err(MissingSpecifier.into()),
+        },
+        None => Err(MissingSpecifier.into()),
+    };
+
+    let p2p = net::P2p::new(settings?.into()).await;
+
+    let dchat = Dchat::new(p2p);
+
+    let nthreads = num_cpus::get();
+    let (signal, shutdown) = async_channel::unbounded::<()>();
+
+    let ex = Arc::new(Executor::new());
+    let ex2 = ex.clone();
+
+    let (_, result) = Parallel::new()
+        .each(0..nthreads, |_| {
+            smol::future::block_on(ex.run(shutdown.recv()))
+        })
+        .finish(|| {
+            smol::future::block_on(async move {
+                dchat.start(ex2).await?;
+                drop(signal);
+                Ok(())
+            })
+        });
+
+    result
+}
 ```
 
 Now try to run the program, don't forget to add a specifier `a` or `b`

+ 1 - 1
doc/src/learn/dchat/deployment/sessions.md

@@ -20,7 +20,7 @@ that takes an address returns a `Channel`.
 
 **Manual**: Uses a `Connector` to connect to a single address that is passed
 to `ManualSession::connect()`. Used to create an explicit connection to
-an address.
+a specified address.
 
 **SeedSync**: Creates a connection to the seed nodes specified in settings.
 Loops through all the configured seeds and tries to connect to them

+ 41 - 3
doc/src/learn/dchat/deployment/settings.md

@@ -1,7 +1,7 @@
 # Settings
 
 On production-ready software, you would usually configure your node
-using a config file or command line inputs. On `dchat` we are keeping
+using a config file or command line inputs. On dchat we are keeping
 things ultra simple. We pass a command line flag that is either `a` or
 `b`. If we pass `a` we will initialize an inbound node. If we pass `b`
 we will initialize an outbound node.
@@ -19,14 +19,52 @@ This is a function that returns the settings to create Alice, an
 inbound node:
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:121:141}}
+fn alice() -> Result<Settings> {
+   let log_level = simplelog::LevelFilter::Debug;
+   let log_config = simplelog::Config::default();
+
+   let log_path = "/tmp/alice.log";
+   let file = File::create(log_path).unwrap();
+   WriteLogger::init(log_level, log_config, file)?;
+
+   let seed = Url::parse("tcp://127.0.0.1:55555").unwrap();
+   let inbound = Url::parse("tcp://127.0.0.1:55554").unwrap();
+   let ext_addr = Url::parse("tcp://127.0.0.1:55554").unwrap();
+
+   let settings = Settings {
+       inbound: Some(inbound),
+       external_addr: Some(ext_addr),
+       seeds: vec![seed],
+       ..Default::default()
+   };
+
+   Ok(settings)
+}
 ```
 
 This is a function that returns the settings to create Bob, an
 outbound node:
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:143:161}}
+fn bob() -> Result<Settings> {
+   let log_level = simplelog::LevelFilter::Debug;
+   let log_config = simplelog::Config::default();
+
+   let log_path = "/tmp/bob.log";
+   let file = File::create(log_path).unwrap();
+   WriteLogger::init(log_level, log_config, file)?;
+
+   let seed = Url::parse("tcp://127.0.0.1:55555").unwrap();
+
+   let settings = Settings {
+       inbound: None,
+       outbound_connections: 5,
+       seeds: vec![seed],
+       ..Default::default()
+   };
+
+   Ok(settings)
+}
 ```
 
 Both outbound and inbound nodes specify a seed address to connect to. The

+ 13 - 14
doc/src/learn/dchat/deployment/start-run-stop.md

@@ -1,6 +1,4 @@
-# Start, run, stop
-
-## Creating the p2p network
+# Start-Run-Stop
 
 Now that we have initialized the network settings we can create an
 instance of the p2p network.
@@ -8,12 +6,10 @@ instance of the p2p network.
 Add the following to `main()`:
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:174}}
+{{#include ../../../../../example/dchat/src/main.rs:196}}
 ```
 
-## Running the p2p network
-
-We will next create a Dchat struct that will store all the data required
+We will next create a `Dchat` struct that will store all the data required
 by dchat. For now, it will just hold a pointer to the p2p network.
 
 ```rust
@@ -33,19 +29,18 @@ takes an executor and runs three p2p methods, `p2p::start()`, `p2p::run()`,
 and `p2p::stop()`.
 
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:97:98}}
+{{#include ../../../../../example/dchat/src/main.rs:99:100}}
 
-{{#include ../../../../../example/dchat/src/main.rs:103}}
+{{#include ../../../../../example/dchat/src/main.rs:105}}
 
         self.p2p.clone().run(ex.clone()).await?;
 
-{{#include ../../../../../example/dchat/src/main.rs:108:112}}
+{{#include ../../../../../example/dchat/src/main.rs:110:114}}
 ```
+Let's take a quick look at the underlying p2p methods we're using here.
 
 ## Start
 
-Let's take a quick look at the underlying p2p methods we're using here.
-
 This is [start()](https://github.com/darkrenaissance/darkfi/blob/master/src/net/p2p.rs#L129):
 
 ```rust
@@ -88,8 +83,12 @@ is received.
 
 ## Stop
 
-To send this shutdown signal, we'll need to manually call
-[stop()](https://github.com/darkrenaissance/darkfi/blob/master/src/net/p2p.rs#L186).
+This is [stop()](https://github.com/darkrenaissance/darkfi/blob/master/src/net/p2p.rs#L186).
+
+```rust
+    {{#include ../../../../../src/net/p2p.rs:186:188}}
+```
+
 `stop()` transmits a shutdown signal to all channels subscribed to the
 stop signal and safely shuts down the network.
 

+ 5 - 5
doc/src/learn/dchat/deployment/writing-a-daemon.md

@@ -8,13 +8,13 @@ can run the p2p network.
 ```rust
 {{#include ../../../../../example/dchat/src/main.rs::9}}
 
-{{#include ../../../../../example/dchat/src/main.rs:23:24}}
+{{#include ../../../../../example/dchat/src/main.rs:25:26}}
 
-{{#include ../../../../../example/dchat/src/main.rs:163:164}}
-{{#include ../../../../../example/dchat/src/main.rs:176:179}}
+{{#include ../../../../../example/dchat/src/main.rs:183:184}}
+{{#include ../../../../../example/dchat/src/main.rs:198:199}}
 
-{{#include ../../../../../example/dchat/src/main.rs:186:189}}
-{{#include ../../../../../example/dchat/src/main.rs:191:197}}
+{{#include ../../../../../example/dchat/src/main.rs:213:216}}
+{{#include ../../../../../example/dchat/src/main.rs:218:224}}
 ```
 
 We get the number of cpu cores using `num_cpus::get()` and spin up a

+ 46 - 0
doc/src/learn/dchat/network-tools/accept-addr.md

@@ -0,0 +1,46 @@
+# Accept addr
+
+To deploy the `JsonRpcInterface` and start receiving JSON-RPC requests,
+we'll need to configure a JSON-RPC accept address.
+
+Let's return to our functions `alice()` and `bob()`. To enable Alice and
+Bob to connect to JSON-RPC, we'll need to generalize this return a RPC
+`Url` as well as a `Settings`.
+
+Let's define a new struct called `AppSettings` that has two fields,
+`Url` and `Settings`.
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:123:132}}
+```
+
+Next, we'll change our `alice()` method to return a `AppSettings`
+instead of a `Settings`.
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:135}}
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:143:158}}
+```
+
+And the same for `bob()`:
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:160}}
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:170:181}}
+```
+
+Update `main()` with the new type:
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:183:192}}
+
+{{#include ../../../../../example/dchat/src/main.rs:194}}
+
+{{#include ../../../../../example/dchat/src/main.rs:196}}
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:224}}
+```
+
+

+ 112 - 1
doc/src/learn/dchat/network-tools/darkfi-rpc.md

@@ -1 +1,112 @@
-# TODO
+# DarkFi RPC
+
+First, we'll need to connect dchat up to JSON-RPC using DarkFi's [rpc
+module](https://github.com/darkrenaissance/darkfi/tree/master/src/rpc).
+
+# AppSettings 
+
+We'll need to set an JSON-RPC `Url` that is specific to our nodes, Alice
+and Bob. To do that, let's return to our functions `alice()` and `bob()`
+that return the type `Settings`. To enable Alice and Bob to connect to
+JSON-RPC, we'll need to generalize this to include a RPC `Url`.
+
+Let's define a new struct called `AppSettings` that has two fields,
+a RPC `Url` and `Settings`.
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:123:132}}
+```
+
+Next, we'll change our `alice()` method to return a `AppSettings`
+instead of a `Settings`.
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:135}}
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:143:158}}
+```
+
+And the same for `bob()`:
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:160}}
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:170:181}}
+```
+
+Update `main()` with the new type:
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:183:192}}
+
+{{#include ../../../../../example/dchat/src/main.rs:194}}
+
+{{#include ../../../../../example/dchat/src/main.rs:197}}
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:225}}
+```
+
+# JsonRpcInterface
+
+Next, we'll define a new struct called `JsonRpcInterface` that takes
+two values, a `Url` that we'll connect the JSON-RPC to, and a pointer
+to the p2p network.
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:1:17}}
+```
+
+We'll need to implement a trait called `RequestHandler` for
+the `JsonRpcInterface`. `RequestHandler` exposes a method called
+`handle_request()` which is a handle for processes incoming
+JSON-RPC requests. `handle_request()` takes a `JsonRequest`
+and returns a `JsonResult`. These types are defined inside
+[jsonrpc.rs](https://github.com/darkrenaissance/darkfi/blob/master/src/rpc/jsonrpc.rs)
+
+This is `JsonResult`:
+```rust
+{{#include ../../../../../src/rpc/jsonrpc.rs:49:55}}
+```
+
+This is `JsonRequest`:
+
+```rust
+{{#include ../../../../../src/rpc/jsonrpc.rs:75:86}}
+```
+
+We'll use `handle_request()` to run a match statement on
+`JsonRequest.method`.
+
+Running a match on `method` will allow us to branch out to functions
+that handle respective methods.  We haven't implemented any methods yet,
+so for now let's just return a `JsonError`.
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:19:28}}
+{{#include ../../../../../example/dchat/src/rpc.rs:31:34}}
+```
+
+# Listen and serve
+
+Now let's implement some methods. We'll start with a simple `pong`
+method that replies to `ping`.
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:36:43}}
+{{#include ../../../../../example/dchat/src/rpc.rs:53}}
+```
+
+And add it to `handle_request()`:
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:19:21}}
+        //...
+{{#include ../../../../../example/dchat/src/rpc.rs:28:29}}
+{{#include ../../../../../example/dchat/src/rpc.rs:31:34}}
+```
+
+To deploy this, we'll need to invoke an `rpc::server` method,
+`listen_and_serve()`.  `listen_and_serve()` starts a JSON-RPC server that
+is bound to the provided accept URL and uses our previously implemented
+`RequestHandler` to handle incoming requests.
+

+ 26 - 0
doc/src/learn/dchat/network-tools/debug.md

@@ -0,0 +1,26 @@
+# Debugging
+
+As a final step, let's quickly turn to the debug output of `dnetview`
+which is stored in `/tmp/dnetview.log`.
+
+Run `dnetview` in `verbose` mode to enable debugging.
+
+```bash
+./dnetview -v
+```
+
+Here's an example output. This is Alice:
+
+```json
+[DEBUG] (16) jsonrpc-client: <-- {"jsonrpc":"2.0","id":8105306807249776489,"result":{"external_addr":"tcp://127.0.0.1:51554","session_inbound":{"connected":{"tcp://127.0.0.1:36428":[{"accept_addr":"tcp://127.0.0.1:51554"},{"last_msg":"addr","last_status":"recv","log":[[1659950874808537094,"send","version"],[1659950874810919251,"recv","version"],[1659950874811104471,"send","verack"],[1659950874811491950,"recv","verack"],[1659950874812397628,"send","getaddr"],[1659950874814847748,"recv","getaddr"],[1659950874815100189,"send","addr"],[1659950874816306644,"recv","addr"]],"random_id":2658393884,"remote_node_id":""}]}},"session_manual":{"key":110},"session_outbound":{"slots":[]},"state":"run"}}
+```
+
+This is Bob: 
+
+```json
+[DEBUG] (16) jsonrpc-client: <-- {"jsonrpc":"2.0","id":17000304364801751931,"result":{"external_addr":null,"session_inbound":{"connected":{}},"session_manual":{"key":110},"session_outbound":{"slots":[{"addr":null,"channel":null,"state":"open"},{"addr":null,"channel":null,"state":"open"},{"addr":"tcp://127.0.0.1:51554","channel":{"last_msg":"addr","last_status":"sent","log":[],"random_id":3924275147,"remote_node_id":""},"state":"connected"},{"addr":null,"channel":null,"state":"open"},{"addr":"tcp://127.0.0.1:50515","channel":{"last_msg":"addr","last_status":"sent","log":[],"random_id":2182348290,"remote_node_id":""},"state":"connected"}]},"state":"run"}}
+```
+
+The raw data might come in useful in some cases.
+
+Happy hacking!

+ 0 - 2
doc/src/learn/dchat/network-tools/dnetview.md

@@ -1,2 +0,0 @@
-# TODO
-

+ 60 - 0
doc/src/learn/dchat/network-tools/get-info.md

@@ -0,0 +1,60 @@
+# get_info
+
+If you run Alice now, you'll see the following output:
+
+```
+[DEBUG] jsonrpc-server: Trying to bind listener on tcp://127.0.0.1:55054
+```
+
+That indicates that our JSON-RPC server is up and running. However,
+there's currently no client for us to connect to. That's where `dnetview`
+comes in. `dnetview` implements a JSON-RPC client that calls a single
+method: `get_info()`.
+
+To use it, let's return to our `JsonRpcInterface` and add the following
+method:
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:45:52}}
+```
+
+And add it to `handle_request()`:
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:21}}
+        //...
+{{#include ../../../../../example/dchat/src/rpc.rs:28:34}}
+```
+
+This calls the p2p function `get_info()` and passes the returned data into a
+`JsonResponse`.
+
+Under the hood, this function triggers a hierarchy of `get_info()`
+calls which deliver info specific to a node, its inbound or outbound
+`Session`'s, and the `Channel`'s those `Session`'s run.
+
+Here's what happens:
+
+```rust
+{{#include ../../../../../src/net/p2p.rs:111:126}}
+```
+
+Here we return two pieces of info that are unique to a node:
+`external_addr` and `state`. We couple that data with `SessionInfo`
+by calling `get_info()` on each `Session`.
+
+`Session::get_info()` returns data related to a `Session`
+(for example, an Inbound `accept_addr` in the case of an
+inbound `Session`). `Session::get_info()` then calls the function
+`Channel::get_info()` which returns data specific to a `Channel`. This
+happens via a child struct called `ChannelInfo`.
+
+This is `ChannelInfo::get_info()`.
+
+```rust
+{{#include ../../../../../src/net/channel.rs:48:58}}
+```
+
+`dnetview` uses the info returned from `Channel` and `Session` and
+node-specific info like `external_addr` to display an overview of the
+p2p network.

BIN
doc/src/learn/dchat/network-tools/images/dnetview-dchatmsg.jpg


BIN
doc/src/learn/dchat/network-tools/images/dnetview-msgs.jpg


BIN
doc/src/learn/dchat/network-tools/images/dnetview-offline.jpg


BIN
doc/src/learn/dchat/network-tools/images/dnetview-online.jpg


+ 44 - 0
doc/src/learn/dchat/network-tools/jsonrpcinterface.md

@@ -0,0 +1,44 @@
+# RPC interface
+
+Let's begin connecting dchat up to JSON-RPC using DarkFi's [rpc
+module](https://github.com/darkrenaissance/darkfi/tree/master/src/rpc).
+
+We'll start by defining a new struct called `JsonRpcInterface` that
+takes two values, an accept `Url` that will receive JSON-RPC requests,
+and a pointer to the p2p network.
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:1:17}}
+```
+
+We'll need to implement a trait called `RequestHandler` for
+the `JsonRpcInterface`. `RequestHandler` exposes a method called
+`handle_request()` which is a handle for processing incoming
+JSON-RPC requests. `handle_request()` takes a `JsonRequest`
+and returns a `JsonResult`. These types are defined inside
+[jsonrpc.rs](https://github.com/darkrenaissance/darkfi/blob/master/src/rpc/jsonrpc.rs)
+
+This is `JsonResult`:
+```rust
+{{#include ../../../../../src/rpc/jsonrpc.rs:49:55}}
+```
+
+This is `JsonRequest`:
+
+```rust
+{{#include ../../../../../src/rpc/jsonrpc.rs:75:86}}
+```
+
+We'll use `handle_request()` to run a match statement on
+`JsonRequest.method`.
+
+Running a match on `method` will allow us to branch out to functions
+that respond to methods received over JSON-RPC.  We haven't implemented
+any methods yet, so for now let's just return a `JsonError`.
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:19:28}}
+{{#include ../../../../../example/dchat/src/rpc.rs:31:34}}
+```
+
+

+ 0 - 2
doc/src/learn/dchat/network-tools/network-tools.md

@@ -1,2 +0,0 @@
-# TODO
-

+ 17 - 0
doc/src/learn/dchat/network-tools/part-3.md

@@ -0,0 +1,17 @@
+# Network tools
+
+In its current state, dchat is ready to use. But there's steps we can
+take to improve it. If we connect dchat to JSON-RPC, we gain access to
+a tool called `dnetview` that allows us to visually explore connections
+and messages on the p2p network.
+
+As well as facilitating debugging, connecting
+`dnetview` is a good excuse to dive into DarkFi's [rpc
+module](https://github.com/darkrenaissance/darkfi/tree/master/src/rpc)
+which is essential to the DarkFi code base.
+
+This section will cover:
+
+* DarkFi's JSON-RPC interface
+* Exploring the p2p network topology using `dnetview`
+

+ 21 - 0
doc/src/learn/dchat/network-tools/pong.md

@@ -0,0 +1,21 @@
+# Methods
+
+We're ready to deploy our `JsonRpcInterface`. But right now now it just
+returns `JsonError::MethodNotFound`. So before testing out the JSON-RPC,
+let's implement some methods.
+
+We'll start with a simple `pong` method that replies to `ping`.
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:36:43}}
+{{#include ../../../../../example/dchat/src/rpc.rs:53}}
+```
+
+And add it to `handle_request()`:
+
+```rust
+{{#include ../../../../../example/dchat/src/rpc.rs:19:21}}
+        //...
+{{#include ../../../../../example/dchat/src/rpc.rs:28:29}}
+{{#include ../../../../../example/dchat/src/rpc.rs:31:34}}
+```

+ 37 - 0
doc/src/learn/dchat/network-tools/server.md

@@ -0,0 +1,37 @@
+# RPC server
+
+To deploy the `JsonRpcInterface`, we'll need to
+create an RPC server using `listen_and_serve()`.
+`listen_and_serve()` is a method defined in DarkFi's [rpc
+module](https://github.com/darkrenaissance/darkfi/tree/master/src/rpc/server.rs).
+It starts a JSON-RPC server that is bound to the provided accept URL
+and uses our previously implemented `RequestHandler` to handle incoming
+requests.
+
+Add the following lines to `main()`:
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:183:184}}
+
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:209:212}}
+    //...
+{{#include ../../../../../example/dchat/src/main.rs:224}}
+```
+
+We create a new `JsonRpcInterface` inside an `Arc` pointer and pass in our
+`accept_addr` and `p2p` object.
+
+Next, we create an async block that calls `listen_and_serve()`. The async
+block uses the `move` keyword to takes ownership of the `accept_addr`
+and `JsonRpcInterface` values and pass them into `listen_and_serve()`.
+We use an `executor` to spawn `listen_and_serve()` as a new thread and
+detach it in the background.
+
+We have enabled JSON-RPC.
+
+Here's what our complete `main()` function looks like:
+
+```rust
+{{#include ../../../../../example/dchat/src/main.rs:183:224}}
+```

+ 68 - 0
doc/src/learn/dchat/network-tools/using-dnetview.md

@@ -0,0 +1,68 @@
+# Using dnetview
+
+Finally, we're ready to use `dnetview`. Go to the `dnetview` directory
+and spawn a new config file by running it once:
+
+```bash
+cd darkfi
+make BINS=dnetview
+./dnetview
+```
+
+You should see the following output:
+
+```
+Config file created in '"/home/USER/.config/darkfi/dnetview_config.toml"'. Please review it and try again.
+ ```
+
+Edit the config file to include the JSON-RPC accept addresses for Alice
+and Bob:
+
+```toml
+[[nodes]]
+name = "alice"
+rpc_url="tcp://127.0.0.1:55054"
+
+[[nodes]]
+name = "bob"
+rpc_url="tcp://127.0.0.1:51054"
+```
+
+Now run `dnetview`:
+
+```bash
+./dnetview
+```
+
+This is what you should see:
+
+![](images/dnetview-offline.jpg)
+
+We haven't ran Alice and Bob yet, so `dnetview` can't connect to them. So
+let's run Alice and Bob.
+
+```bash
+cargo run a
+```
+
+```bash
+cargo run b
+```
+
+Now try running `dnetview` again.
+
+![](images/dnetview-online.jpg)
+
+That's fun. Use `j` and `k` to navigate. See what happens when you select
+a `Channel`.
+
+![](images/dnetview-msgs.jpg)
+
+On each `Channel`, we see a log of messages being sent across the network.
+What happens when we send a message?
+
+![](images/dnetview-dchatmsg.jpg)
+
+This is Bob receiving a DchatMsg message on the `Channel`
+`tcp://127.0.0.1:51554`. Pretty cool.
+