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

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",
  "log",
  "num_cpus",
  "num_cpus",
  "serde",
  "serde",
+ "serde_json",
  "simplelog",
  "simplelog",
  "smol",
  "smol",
  "toml",
  "toml",

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

@@ -40,7 +40,7 @@ use crate::{
     view::{IdMenu, MsgList, View},
     view::{IdMenu, MsgList, View},
 };
 };
 
 
-use log::debug;
+//use log::debug;
 
 
 struct DnetView {
 struct DnetView {
     name: String,
     name: String,
@@ -55,7 +55,7 @@ impl DnetView {
 
 
     // --> {"jsonrpc": "2.0", "method": "ping", "params": [], "id": 42}
     // --> {"jsonrpc": "2.0", "method": "ping", "params": [], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": "pong", "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!([]));
         let req = JsonRequest::new("ping", json!([]));
         self.rpc_client.request(req).await
         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<()> {
 async fn poll(client: DnetView, model: Arc<Model>) -> DnetViewResult<()> {
     loop {
     loop {
+        match client.ping().await {
+            // TODO
+            Ok(reply) => {}
+            Err(e) => {}
+        }
         match client.get_info().await {
         match client.get_info().await {
             Ok(reply) => {
             Ok(reply) => {
                 if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
                 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_msgs(model.clone(), sessions.clone()).await?;
     update_new_id(model.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(())
     Ok(())
 }
 }

+ 14 - 9
doc/src/SUMMARY.md

@@ -27,24 +27,29 @@
   - [Research](learn/research.md)
   - [Research](learn/research.md)
   - [ZK explainer](learn/zk_explainer.md)
   - [ZK explainer](learn/zk_explainer.md)
   - [Dchat](learn/dchat/dchat.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)
       - [Getting started](learn/dchat/deployment/getting-started.md)
       - [Writing a daemon](learn/dchat/deployment/writing-a-daemon.md)
       - [Writing a daemon](learn/dchat/deployment/writing-a-daemon.md)
       - [Sessions](learn/dchat/deployment/sessions.md)
       - [Sessions](learn/dchat/deployment/sessions.md)
       - [Settings](learn/dchat/deployment/settings.md)
       - [Settings](learn/dchat/deployment/settings.md)
       - [Error handling](learn/dchat/deployment/error-handling.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)
       - [Message](learn/dchat/creating-dchat/message.md)
       - [Protocols](learn/dchat/creating-dchat/protocols.md)
       - [Protocols](learn/dchat/creating-dchat/protocols.md)
       - [ProtocolDchat](learn/dchat/creating-dchat/protocol-dchat.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)
       - [Sending messages](learn/dchat/creating-dchat/sending-messages.md)
       - [Slap on a UI](learn/dchat/creating-dchat/ui.md)
       - [Slap on a UI](learn/dchat/creating-dchat/ui.md)
       - [Using dchat](learn/dchat/creating-dchat/using-dchat.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()`:
 in `start()`:
 
 
 ```rust
 ```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.
 call `register()` on the registry and pass the `ProtocolDchat` constructor.
 
 
 ```rust
 ```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
 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()`.
 variables needed by `ProtocolDchat::init()`.
 
 
 Notice the use of a `bitflag`. We use `!SESSION_SEED` to specify that
 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.
 seed session.
 
 
 Also notice that `register_protocol()` requires a `DchatMsgsBuffer` that we
 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.
 `Dchat` struct definition first.
 
 
 ```rust
 ```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:
 And initialize it:
 
 
 ```rust
 ```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()`:
 Finally, call `register_protocol()` in `dchat::start()`:
 
 
 ```rust
 ```rust
-{{#include ../../../../../example/dchat/src/main.rs:97:103}}
+{{#include ../../../../../example/dchat/src/main.rs:99:105}}
         self.p2p.clone().run(ex.clone()).await?;
         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
 Now try running Alice and Bob and seeing what debug output you get. Keep
 an eye out for the following:
 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()`.
 `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
 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:
 Here's what is should look like:
 
 
 ```rust
 ```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:
 We'll call `menu()` inside of `dchat::start()` along with our other methods, like so:
 
 
 ```rust
 ```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?;
         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
 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:
 The complete implementaion looks like this:
 
 
 ```rust
 ```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`.
 In terminal 1, run `lilith`.
 
 
 ```
 ```
-cargo run --dchat
+./lilith
 ```
 ```
 
 
 In terminal 2, run Alice.
 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
 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
 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
 p2p network. When Bob receives the message on on the p2p network it is
 displayed his terminal.
 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:
 the p2p network, in particular:
 
 
 * Understanding inbound, outbound and seed nodes.
 * 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
 The source code for this tutorial can be found at
 [example/dchat](https://github.com/darkrenaissance/darkfi/tree/master/example/dchat).
 [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
 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,
 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
 ```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:
 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.
 [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.
 [INFO] Starting 0 outbound connection slots.
 ```
 ```
 
 
-Next we'll run Alice.
+Next we'll head back to `dchat` and run Alice. 
 
 
 ```bash
 ```bash
 cargo run a
 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}}
 {{#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
 ```rust
 {{#include ../../../../../example/dchat/src/main.rs:13:14}}
 {{#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:
 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
 * p2p daemons
 * Inbound, outbound, manual and seed nodes
 * Inbound, outbound, manual and seed nodes
 * Understanding `Sessions`
 * 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. 
 in the main function. 
 
 
 ```rust
 ```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`
 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
 **Manual**: Uses a `Connector` to connect to a single address that is passed
 to `ManualSession::connect()`. Used to create an explicit connection to
 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.
 **SeedSync**: Creates a connection to the seed nodes specified in settings.
 Loops through all the configured seeds and tries to connect to them
 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
 # Settings
 
 
 On production-ready software, you would usually configure your node
 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
 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`
 `b`. If we pass `a` we will initialize an inbound node. If we pass `b`
 we will initialize an outbound node.
 we will initialize an outbound node.
@@ -19,14 +19,52 @@ This is a function that returns the settings to create Alice, an
 inbound node:
 inbound node:
 
 
 ```rust
 ```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
 This is a function that returns the settings to create Bob, an
 outbound node:
 outbound node:
 
 
 ```rust
 ```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
 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
 Now that we have initialized the network settings we can create an
 instance of the p2p network.
 instance of the p2p network.
@@ -8,12 +6,10 @@ instance of the p2p network.
 Add the following to `main()`:
 Add the following to `main()`:
 
 
 ```rust
 ```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.
 by dchat. For now, it will just hold a pointer to the p2p network.
 
 
 ```rust
 ```rust
@@ -33,19 +29,18 @@ takes an executor and runs three p2p methods, `p2p::start()`, `p2p::run()`,
 and `p2p::stop()`.
 and `p2p::stop()`.
 
 
 ```rust
 ```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?;
         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
 ## 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):
 This is [start()](https://github.com/darkrenaissance/darkfi/blob/master/src/net/p2p.rs#L129):
 
 
 ```rust
 ```rust
@@ -88,8 +83,12 @@ is received.
 
 
 ## Stop
 ## 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()` transmits a shutdown signal to all channels subscribed to the
 stop signal and safely shuts down the network.
 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
 ```rust
 {{#include ../../../../../example/dchat/src/main.rs::9}}
 {{#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
 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.
+