quic-p2p 0.2.0

Peer-to-peer networking library using QUIC
Documentation
// Copyright 2019 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under the MIT license <LICENSE-MIT
// http://opensource.org/licenses/MIT> or the Modified BSD license <LICENSE-BSD
// https://opensource.org/licenses/BSD-3-Clause>, at your option. This file may not be copied,
// modified, or distributed except according to those terms. Please review the Licences for the
// specific language governing permissions and limitations relating to use of the SAFE Network
// Software.

//! Bootstrap node which acts as a relay for other client nodes. It collects the info of multiple
//! client nodes and relays it to all remaining connected nodes, hence allows them all to connect
//! with each other.
//!
//! Usage:
//! ```
//! $ RUST_LOG=bootstrap_node=info cargo run --example bootstrap_node -- --expected_conns 1 --ip
//! "127.0.0.1"
//! ```

#[macro_use]
extern crate log;
#[macro_use]
extern crate unwrap;
#[macro_use]
extern crate serde_derive;

mod common;
use bincode;
use bytes::Bytes;
use common::Rpc;
use crossbeam_channel as mpmc;
use env_logger;
use quic_p2p::{Builder, Config, Event, Peer};
use serde_json;
use std::collections::HashMap;
use std::io;
use structopt::StructOpt;

/// Configuration for the bootstrap node
#[derive(Serialize, Deserialize, StructOpt)]
pub struct BootstrapNodeConfig {
    /// A number of expected connections.
    /// Once this number is reached, we'll send a list of all connections to every connected peer.
    #[structopt(short, long)]
    expected_conns: usize,
    #[structopt(flatten)]
    quic_p2p_opts: Config,
}

fn main() -> Result<(), io::Error> {
    env_logger::init();

    // Initialise configuration
    let bootstrap_node_config = BootstrapNodeConfig::from_args();

    // Initialise QuicP2p
    let (ev_tx, ev_rx) = mpmc::unbounded();

    let mut qp2p = unwrap!(Builder::new(ev_tx)
        .with_config(bootstrap_node_config.quic_p2p_opts)
        .build());

    let our_conn_info = unwrap!(qp2p.our_connection_info());
    info!("QuicP2p started on {}", our_conn_info.peer_addr);

    println!(
        "Our connection info:\n{}\n",
        unwrap!(serde_json::to_string(&our_conn_info)),
    );

    let expected_connections = bootstrap_node_config.expected_conns;
    let mut connected_peers = HashMap::new();
    let mut test_triggered = false;

    for event in ev_rx.iter() {
        match event {
            Event::ConnectedTo { peer } => {
                let peer_addr = match &peer {
                    Peer::Node { node_info } => node_info.peer_addr,
                    Peer::Client { .. } => panic!("In this example only Node peers are expected"),
                };
                let _ = connected_peers.insert(peer_addr, peer);
                if connected_peers.len() == expected_connections && !test_triggered {
                    info!(
                        "{} connections collected, triggering the test",
                        expected_connections
                    );
                    let contacts: Vec<_> = connected_peers.values().cloned().collect();
                    let msg = Bytes::from(unwrap!(bincode::serialize(&Rpc::StartTest(contacts))));
                    for peer in connected_peers.values() {
                        // qp2p.send(Peer::Node { node_info: peer.clone() }, msg.clone());
                        // TODO: Demo tokens properly. Currently just putting 0 here.
                        // TODO: Also handle receiving `SentUserMessage` event
                        qp2p.send(peer.clone(), msg.clone(), 0);
                    }
                    test_triggered = true;
                } else if connected_peers.len() >= expected_connections {
                    error!("More than expected connections received");
                }
            }
            event => warn!("Unexpected event: {:?}", event),
        }
    }

    Ok(())
}