Implementation of libp2p RS infoserver

Time:2021-5-5

Module address:https://github.com/netwarps/l…

stayLast articleAt the end of, it is mentioned that web server will be used to provide relevant restful API, which can observe the situation of network receiving and sending. So far, the design has been completed. Let’s share the design process here.

Realize the idea

When designing metric, in order to reduce the number of communication with swarm, we put a metric clone in control. For API server, we can get the network traffic data we want to get and some relevant information about the current connection with the help of the metric related operation method provided by control.

Framework introduction

As a web application framework of rust, tide implements a series of related routing functions, and can easily build API; At the same time, serde’s serialization / deserialization function can help us format data into JSON type, which makes it easier to read and parse.

Route registration

Taking the get method as an example, in tide, route registration is implemented in the following way:

server.at(path).get(method)

The at method and get method are as follows:

//Self is the server object
    pub fn at<'a>(&'a mut self, path: &str) -> Route<'a, State> {
        let router = Arc::get_mut(&mut self.router)
            .expect("Registering routes is not possible after the Server has started");
        Route::new(router, path.to_owned())
    }

    //Self is the route object
    pub fn get(&mut self, ep: impl Endpoint<State>) -> &mut Self {
        self.method(http_types::Method::Get, ep);
        self
    }

As you can see, the method parameter is actually an impl trait.
In the type that implements the trait, there is such a form:

#[async_trait]
impl<State, F, Fut, Res> Endpoint<State> for F
where
    State: Clone + Send + Sync + 'static,
    F: Send + Sync + 'static + Fn(Request<State>) -> Fut,
    Fut: Future<Output = Result<Res>> + Send + 'static,
    Res: Into<Response> + 'static,
{
    async fn call(&self, req: Request<State>) -> crate::Result {
        let fut = (self)(req);
        let res = fut.await?;
        Ok(res.into())
    }
}

Corresponding to our code, the generic state is control and FN can be implemented as an async method. The incoming parameter is request and the return value type is tide:: result.

Method analysis

To obtain the code of networkinfo for analysis:

  1. Take out the control from the request. Since the variable reference is needed in the next step, we need to clone here.
  2. Call retrieve of control_ Info() to get the networkinfo data.
  3. becauseConnectionInfoIt contains peerid, but the underlying multihash of peerid does not support serde. Therefore, a new struct called networkconnectioninfo is created here. If peerid is set to string type, the format operation of serde can be realized.
  4. Iterative network_ Connect of info_ Info, the resulting vector is combined with other data to generate networkconnectionstatus.
  5. Call body:: from_ JSON () formats the data as JSON and returns it as body.
/// Get connection info
async fn get_connection_info(req: Request<Control>) -> tide::Result {
    let mut control = req.state().clone();

    let network_info = control.retrieve_networkinfo().await.map_err(|e| {
        log::error!("{:?}", e);
        tide::Error::new(500, e)
    })?;

    let mut connection_info = Vec::new();
    for item in network_info.connection_info.iter() {
        let info = NetworkConnectionInfo {
            la: item.la.to_vec(),
            ra: item.ra.to_vec(),
            local_peer_id: item.local_peer_id.to_string(),
            remote_peer_id: item.remote_peer_id.to_string(),
            num_inbound_streams: item.num_inbound_streams,
            num_outbound_streams: item.num_outbound_streams,
        };
        connection_info.push(info);
    }

    let network_connection_status = NetworkConnectionStatus {
        num_connections: network_info.num_connections,
        num_connections_pending: network_info.num_connections_pending,
        num_connections_established: network_info.num_connections_established,
        num_active_streams: network_info.num_active_streams,
        connection_info,
    };

    let result_body = Body::from_json(&ResponseBody {
        status: 0,
        message: "".to_string(),
        result: vec![serde_json::to_string(&network_connection_status).unwrap()],
    })?;
    let response = Response::builder(200).body(result_body).build();
    Ok(response)
}

Interface list

At present, the interfaces are as follows

Nonparametric interface
127.0.0.1:8999
127.0.0.1:8999/recv
127.0.0.1:8999/send
127.0.0.1:8999/peer
127.0.0.1:8999/connection

Interface with parameters
127.0.0.1:8999/peer/_
127.0.0.1:8999/protocol?protocol_id=_

Among them, the peer interface with parameters means that a specific peerid needs to be passed.

Protocolid is passed in the form of param.

Unsolved difficulties

When designing route registration, we have tried such a way: generate a HashMap constant with key as path and value as method to manage all routes in a unified way. When executing the new () method, iterate the HashMap and register the routing information to the server.

The difficulty of this method is that our method is actually a closure whose return value type is future. Assuming that the value is in the form of a closure, the compiler will prompt the following error:

`impl Trait` not allowed outside of function and inherent method return types

Impl trait cannot be a return value type other than a function.

If value is of dynamic dispatch type, it means that we need to use box < dyn endpoint < state > > as value type. For HashMap, unless it is consumed directly, the data extracted from it is of reference type. However, the clone method seems to be not feasible here, and the returned data is still a box reference. The current route registration method is not very friendly in code reading, so we will consider other methods for optimization later.

Partial effect display

The number of bytes (out) sent by the current node to a target node and the number of bytes (in) obtained from the target node are as follows:

Implementation of libp2p RS infoserver

Byte size of packets sent (out) and received (in) by the current node using / IPFs / ID / 1.0.0 protocol:

Implementation of libp2p RS infoserver


Netwarps is composed of domestic senior cloud computing and distributed technology development team, which has rich experience in finance, power, communication and Internet industries. At present, netwarps has set up R & D centers in Shenzhen and Beijing, with a team size of 30 +, most of which are technicians with more than 10 years of development experience, respectively from the Internet, finance, cloud computing, blockchain, scientific research institutions and other professional fields.
Netwarps focuses on the R & D and application of secure storage technology products. Its main products are decentralized file system (DFS) and decentralized computing platform (DCP). It is committed to providing distributed storage and distributed computing platform based on decentralized network technology. With the technical characteristics of high availability, low power consumption and low network, netwarps is suitable for the Internet of things Industrial Internet, etc.
WeChat official account: netwarps

Recommended Today

Analysis of super comprehensive MySQL statement locking (Part 1)

A series of articles: Analysis of super comprehensive MySQL statement locking (Part 1) Analysis of super comprehensive MySQL statement locking (Part 2) Analysis of super comprehensive MySQL statement locking (Part 2) Preparation in advance Build a system to store heroes of the Three KingdomsheroTable: CREATE TABLE hero ( number INT, name VARCHAR(100), country varchar(100), PRIMARY […]