Kaynağa Gözat

book/ dchat: EDIT1- clarified language and fixed errors

lunar-mining 4 yıl önce
ebeveyn
işleme
cb7702dd82

+ 2 - 1
doc/src/SUMMARY.md

@@ -30,7 +30,8 @@
     - [Deployment](learn/dchat/local-deployment/local-deployment.md)
       - [Getting started](learn/dchat/local-deployment/getting-started.md)
       - [Writing a daemon](learn/dchat/local-deployment/writing-a-daemon.md)
-      - [Inbound and outbound](learn/dchat/local-deployment/inbound-and-outbound.md)
+      - [Sessions](learn/dchat/local-deployment/sessions.md)
+      - [Settings](learn/dchat/local-deployment/settings.md)
       - [Error handling](learn/dchat/local-deployment/error-handling.md)
       - [Running the network](learn/dchat/local-deployment/creating-and-running.md)
       - [Seed node](learn/dchat/local-deployment/seed-node.md)

+ 16 - 12
doc/src/learn/dchat/creating-dchat/protocols.md

@@ -28,32 +28,36 @@ our custom protocol. In particular:
 
 1. The Message Subsystem
 
-MessageSubsystem is a generic publish/subscribe class that can
-dispatch any kind of message to a list of dispatchers. This is how we
-can send and receive custom messages on the p2p network.
+MessageSubsystem is a generic publish/subscribe class that contains
+a list of Message dispatchers. A new dispatcher is created for every
+Message type. These Message-specific dispatchers maintain a list of
+susbscribers that are subscribed to a particular message.
 
 2. Message Subscription
 
-A subscription to a message type. 
+A subscription to a specific Message type. Handles receiving messages
+on a subscription.
 
 3. Channel
 
 A channel is an async connection for communication between nodes. It is
 also a powerful interface that exposes methods to the Message Subsystem
-and implements message subscriptions.  Channel also contains a weak
-pointer to its parent, Session.
+and implements message subscriptions.
 
 4. The Protocol Registry 
 
-ProtocolRegistry takes any kind of generic protocol and initializes it. We
-use it through the method register() which passes a protocol constructor
-and a session bitflag which determines which sessions (outbound, inbound,
-or seed) will run our protocol.
+ProtocolRegistry is a registry of all protocols. We use it through the
+method register() which passes a protocol constructor and a session
+bitflag. The bitflag specifies which sessions the protocol is created
+for. The ProtocolRegistry then spawns new protocols for different channels
+depending on the session.
 
 5. ProtocolJobsManager
 
-An asynchronous job manager that spawns and stops tasks created by
-protocols across the network.
+An asynchronous job manager that spawns and stops tasks. Its main
+purpose is so a protocol can cleanly close all started jobs, through
+the function close_all_tasks().  This way if the connection between
+nodes is dropped and the channel closes, all protocols are also shutdown.
 
 6. ProtocolBase
 

+ 21 - 7
doc/src/learn/dchat/creating-dchat/register-protocol.md

@@ -8,8 +8,6 @@ register_protocol(). It will invoke the protocol_registry using the
 handle to the p2p network contained in the Dchat struct. It will then
 call register() on the registry and pass the ProtocolDchat constructor.
 
-Be sure to import Dchatmsg and ProtocolDchat so we can access their data.
-
 ```
 use crate::{dchatmsg::DchatmsgsBuffer, protocol_dchat::ProtocolDchat};
 
@@ -28,12 +26,28 @@ async fn register_protocol(&self, msgs: DchatmsgsBuffer) -> Result<()> {
 }
 ```
 
-We set the bitflag to SESSION_ALL to specify that this protocol should
-be performed by every session. We also use a closure to capture a pointer
-to Channel, which we pass into the ProtocolDchat constructor. This gives
-us access to the message subscriber methods.
+There's a lot going on here. register() takes a closure with two
+arguments, `channel` and `p2p`. We use `move` to capture these values. We
+then create an async closure that captures these values and the value
+`msgs` and use them to call ProtocolDchat::init() in the async block.
+
+The code would be expressed more simply as:
+
+```
+registry.register(net::SESSION_ALL, async move |channel, _p2p| {
+        ProtocolDchat::init(channel, msgs).await
+    })
+    .await;
+```
+
+However we cannot do this due to limitation with async closures. So
+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_ALL to specify that this
+protocol should be performed by every session. 
 
-Notice that register_protocol() requires a DchatmsgsBuffer that we send
+Also notice that register_protocol() requires a DchatmsgsBuffer that we send
 to the ProtocolDchat constructor. We'll create the DchatmsgsBuffer in
 main() and pass it to Dchat::new(). Let's add DchatmsgsBuffer to the
 Dchat struct definition first.

+ 0 - 2
doc/src/learn/dchat/local-deployment/creating-and-running.md

@@ -14,8 +14,6 @@ let p2p = net::P2p::new(settings?.into()).await;
 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.
 
-To accesss this we will need to add net to our imports, like so:
-
 ```
 use darkfi::net;
 

+ 21 - 110
doc/src/learn/dchat/local-deployment/inbound-and-outbound.md

@@ -1,120 +1,31 @@
-# Inbound and Outbound nodes
+# Sessions
 
-To create an instance of the p2p network, we must configure our p2p
-network settings into a type called net::Settings. These settings
-determine whether our node will be an outbound, inbound, manual or
-seed node.
-
-Inbound, outbound and seed nodes perform different roles on the p2p
+To deploy the p2p network, we need to configure two types of nodes:
+inbound and outbound. These nodes perform different roles on the p2p
 network. An inbound node receives connections. An outbound node makes
-connections. A seed node is used when connecting to the network: it is
-a special kind of inbound node that gets connected to, sends over a list
-of addresses and disconnects again.
+connections.
 
-The behavior of the different
-kinds of nodes is defined in what is called a
+The behavior of these nodes is defined in what is called a
 [Session](https://github.com/darkrenaissance/darkfi/blob/master/src/net/session/mod.rs#L93).
-Session is a trait that outbound, inbound, manual and seed nodes all
-implement. Session implementations expose methods such as stopping and
-starting a channel, accepting connections (inbound nodes) or making
-connections (outbound nodes).
-
-On production-ready software, you would usually configure your node
-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.
-
-Here's how that works. We define two methods called alice() and
-bob(). alice() returns the Settings that will create an inbound
-node. bob() return the Settings for an outbound node.
-
-We also implement logging that outputs to /tmp/alice.log and /tmp/bob.log
-so we can access the debug output of our nodes. We store this info in a
-log file because we don't want it interfering with our terminal UI when
-we eventually build it.
-
-This is a function that returns the settings to create Alice, an
-inbound node:
-
-```
-use simplelog::WriteLogger;
-use std::fs::File;
-
-use darkfi::{net::Settings, Result};
-use url::Url;
-
-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),
-        outbound_connections: 0,
-        manual_attempt_limit: 0,
-        seed_query_timeout_seconds: 8,
-        connect_timeout_seconds: 10,
-        channel_handshake_seconds: 4,
-        channel_heartbeat_seconds: 10,
-        outbound_retry_seconds: 1200,
-        external_addr: Some(ext_addr),
-        peers: Vec::new(),
-        seeds: vec![seed],
-        node_id: String::new(),
-    };
-
-    Ok(settings)
-}
-
-```
-
-This is a function that returns the settings to create Bob, an
-outbound node:
-
-```
-fn bob() -> Result<Settings> {
-    let log_level = simplelog::LevelFilter::Debug;
-    let log_config = simplelog::Config::default();
+There are four types of sessions: Manual, Inbound, Outbound and SeedSync.
 
-    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 oc = 5;
+There behavior is as follows: 
 
-    let settings = Settings {
-        inbound: None,
-        outbound_connections: oc,
-        manual_attempt_limit: 0,
-        seed_query_timeout_seconds: 8,
-        connect_timeout_seconds: 10,
-        channel_handshake_seconds: 4,
-        channel_heartbeat_seconds: 10,
-        outbound_retry_seconds: 1200,
-        external_addr: None,
-        peers: Vec::new(),
-        seeds: vec![seed],
-        node_id: String::new(),
-    };
+1. Inbound: Uses an Acceptor to accept connections on the inbound connect
+address configured in settings.
 
-    Ok(settings)
-}
-```
+2. Outbound: Starts a connect loop for every connect slot configured in
+settings. Establishes a connection using Connector.connect(): a method
+that takes an address returns a Channel.
 
-Both outbound and inbound nodes specify a seed address to connect to. The
-inbound node also specifies an external address and an inbound address:
-this is where it will receive connections. The outbound node specifies
-the number of outbound connection slots, which is the number of outbound
-connections the node will try to make.
+3. 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.
 
-These are the only settings we need to think about. For the rest, we
-use the network defaults.
+4. SeedSync: Creates a connection to the seed nodes specified in settings.
+Loops through all the configured seeds and tries to connect to them
+using a Connector. Either connects successfully, fails with an error or
+times out.
 
+To create an inbound and outbound node, we will need to configure them
+using a type called net::Settings.

+ 9 - 2
doc/src/learn/dchat/local-deployment/seed-node.md

@@ -49,8 +49,15 @@ It should output the following error:
 Error: NetworkOperationFailed
 ```
 
-That's because there is no seed node online for our nodes to connect
-to. Let's remedy that.
+That's because there is no seed node online for our nodes to connect to. A
+seed node is used when connecting to the network: it is a special kind
+of inbound node that gets connected to, sends over a list of addresses
+and disconnects again.  This behavior is defined in the ProtocolSeed.
+
+Everytime we run `p2p.start()` we attempt to connect to a seed using a
+SeedSyncSession.  If the SeedSyncSession fails, p2p.start() will fail,
+so without a seed node, our inbound and outbound nodes cannot establish
+a connection to the network. Let's remedy that.
 
 We have two options here. First, we could implement our own seed node.
 Alternatively, DarkFi maintains a master seed node called lilith that

+ 101 - 0
doc/src/learn/dchat/local-deployment/settings.md

@@ -0,0 +1,101 @@
+# Settings
+
+On production-ready software, you would usually configure your node
+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.
+
+Here's how that works. We define two methods called alice() and
+bob(). alice() returns the Settings that will create an inbound
+node. bob() return the Settings for an outbound node.
+
+We also implement logging that outputs to /tmp/alice.log and /tmp/bob.log
+so we can access the debug output of our nodes. We store this info in a
+log file because we don't want it interfering with our terminal UI when
+we eventually build it.
+
+This is a function that returns the settings to create Alice, an
+inbound node:
+
+```
+use simplelog::WriteLogger;
+use std::fs::File;
+
+use darkfi::{net::Settings, Result};
+use url::Url;
+
+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),
+        outbound_connections: 0,
+        manual_attempt_limit: 0,
+        seed_query_timeout_seconds: 8,
+        connect_timeout_seconds: 10,
+        channel_handshake_seconds: 4,
+        channel_heartbeat_seconds: 10,
+        outbound_retry_seconds: 1200,
+        external_addr: Some(ext_addr),
+        peers: Vec::new(),
+        seeds: vec![seed],
+        node_id: String::new(),
+    };
+
+    Ok(settings)
+}
+
+```
+
+This is a function that returns the settings to create Bob, an
+outbound node:
+
+```
+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 oc = 5;
+
+    let settings = Settings {
+        inbound: None,
+        outbound_connections: oc,
+        manual_attempt_limit: 0,
+        seed_query_timeout_seconds: 8,
+        connect_timeout_seconds: 10,
+        channel_handshake_seconds: 4,
+        channel_heartbeat_seconds: 10,
+        outbound_retry_seconds: 1200,
+        external_addr: None,
+        peers: Vec::new(),
+        seeds: vec![seed],
+        node_id: String::new(),
+    };
+
+    Ok(settings)
+}
+```
+
+Both outbound and inbound nodes specify a seed address to connect to. The
+inbound node also specifies an external address and an inbound address:
+this is where it will receive connections. The outbound node specifies
+the number of outbound connection slots, which is the number of outbound
+connections the node will try to make.
+
+These are the only settings we need to think about. For the rest, we
+use the network defaults.
+