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

相關文章
相關標籤/搜索