libp2p-rs infoserver 实现

模块地址:https://github.com/netwarps/libp2p-rs/tree/master/infoservergit

上一篇文章的末尾有提到,会采用web server的方式提供相关的restful api,能够在外部观测网络收发包的状况。目前已设计完成,在这里简单分享一下设计过程。github

实现构想

设计Metric时,为了减小与swarm通讯的次数,咱们在control中放了一份metric的clone。对于api server来讲,咱们彻底能够借助control提供的metric相关操做方法,得到咱们想要获得的网络流量数据,以及当前链接的一些相关状况。web

框架介绍

Tide做为rust的一个web应用框架,实现了一系列相关的路由功能,能够很方便地构建API;同时,serde的序列化/反序列化功能,能帮助咱们将数据格式化成json类型,更容易阅读和解析。json

路由注册

以get方法为例,在Tide中,经过如下这种方式实现路由注册:api

server.at(path).get(method)

at方法和get方法以下所示:安全

// self为server对象
    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为Route对象
    pub fn get(&mut self, ep: impl Endpoint<State>) -> &mut Self {
        self.method(http_types::Method::Get, ep);
        self
    }

能够看到,method参数其实是一个impl Trait。
在这个实现了这个trait的类型中,有这样一种形式:restful

#[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())
    }
}

对应到咱们的代码中,泛型State为Control,Fn咱们能够实现为一个async的方法,传入参数是Request,返回值类型为tide::Result。网络

方法分析

以获取NetworkInfo的代码进行分析:闭包

  1. 从request中取出Control,因为下一步须要可变引用,因此这里要进行clone。
  2. 调用control的retrieve_info()获取NetworkInfo数据。
  3. 因为ConnectionInfo包含了PeerId,而PeerId底层的Multihash还没有支持serde,所以在这里新建了NetworkConnectionInfo这个struct,PeerId设置为String类型,便可实现serde的格式化操做。
  4. 迭代network_info的connect_info,获得的vector与其余数据组合生成NetworkConnectionStatus。
  5. 调用Body::from_json()将数据格式化成json,做为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)
    }

    接口列表

    目前所实现的接口有以下几个:

无参数接口
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

带参数接口
127.0.0.1:8999/peer/_
127.0.0.1:8999/protocol?protocol_id=_

其中,带参数的peer接口意为须要传递一个具体的PeerID。<br>
而ProtocolID则使用param的方式进行传递。

未解难点

在设计路由注册时,有尝试过这么一种方式:生成一个HashMap常量,key为path,value为method,统一管理全部的路由。执行new()方法的时候,迭代这个hashmap,将路由信息注册到server中。

这个方法的难点在于,咱们的method其实是一个返回值类型为future的闭包。假设以闭包的形式做为value,编译器会提示如下错误:

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

意思是impl Trait没法做为函数之外的返回值类型。

若是value以动态分派做为类型,意味着咱们须要以Box<dyn Endpoint<State>>做为value类型。对于HashMap而言,除非直接消耗掉,否则从中取出的数据都是引用类型的,而clone方法在此处彷佛也是行不通的,返回的仍然是一个Box的引用。目前所采用的路由注册方式,在代码的阅读上不太友好,后续考虑用其余方式进行优化。

部分效果展现

当前节点向某个目标节点发送字节数(out)和从目标节点获取的字节数(in)大小:
libp2p-rs infoserver 实现

当前节点使用/ipfs/id/1.0.0协议所发送(out)和接收(in)的数据包字节大小:
libp2p-rs infoserver 实现


Netwarps 由国内资深的云计算和分布式技术开发团队组成,该团队在金融、电力、通讯及互联网行业有很是丰富的落地经验。Netwarps 目前在深圳、北京均设立了研发中心,团队规模30+,其中大部分为具有十年以上开发经验的技术人员,分别来自互联网、金融、云计算、区块链以及科研机构等专业领域。Netwarps 专一于安全存储技术产品的研发与应用,主要产品有去中心化文件系统(DFS)、去中心化计算平台(DCP),致力于提供基于去中心化网络技术实现的分布式存储和分布式计算平台,具备高可用、低功耗和低网络的技术特色,适用于物联网、工业互联网等场景。公众号:Netwarps

相关文章
相关标签/搜索