模块地址:https://github.com/netwarps/l...
在上一篇文章的开端有提到,会采纳web server的形式提供相干的restful api,能够在内部观测网络收发包的状况。目前已设计实现,在这里简略分享一下设计过程。
实现构想
设计Metric时,为了缩小与swarm通信的次数,咱们在control中放了一份metric的clone。对于api server来说,咱们齐全能够借助control提供的metric相干操作方法,取得咱们想要失去的网络流量数据,以及以后连贯的一些相干状况。
框架介绍
Tide作为rust的一个web利用框架,实现了一系列相干的路由性能,能够很不便地构建API;同时,serde的序列化/反序列化性能,能帮忙咱们将数据格式化成json类型,更容易浏览和解析。
路由注册
以get办法为例,在Tide中,通过以下这种形式实现路由注册:
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的类型中,有这样一种模式:
#[async_trait]impl<State, F, Fut, Res> Endpoint<State> for Fwhere 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的代码进行剖析:
- 从request中取出Control,因为下一步须要可变援用,所以这里要进行clone。
- 调用control的retrieve_info()获取NetworkInfo数据。
- 因为ConnectionInfo蕴含了PeerId,而PeerId底层的Multihash尚未反对serde,因而在这里新建了NetworkConnectionInfo这个struct,PeerId设置为String类型,即可实现serde的格式化操作。
- 迭代network_info的connect_info,失去的vector与其余数据组合生成NetworkConnectionStatus。
- 调用Body::from_json()将数据格式化成json,作为body返回。
/// Get connection infoasync 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:8999127.0.0.1:8999/recv127.0.0.1:8999/send127.0.0.1:8999/peer127.0.0.1:8999/connection带参数接口127.0.0.1:8999/peer/_127.0.0.1:8999/protocol?protocol_id=_
其中,带参数的peer接口意为须要传递一个具体的PeerID。
而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)大小:
以后节点应用/ipfs/id/1.0.0协定所发送(out)和接管(in)的数据包字节大小:
Netwarps 由国内资深的云计算和分布式技术开发团队组成,该团队在金融、电力、通信及互联网行业有十分丰盛的落地教训。Netwarps 目前在深圳、北京均设立了研发核心,团队规模30+,其中大部分为具备十年以上开发教训的技术人员,别离来自互联网、金融、云计算、区块链以及科研机构等业余畛域。
Netwarps 专一于平安存储技术产品的研发与利用,次要产品有去中心化文件系统(DFS)、去中心化计算平台(DCP),致力于提供基于去中心化网络技术实现的分布式存储和分布式计算平台,具备高可用、低功耗和低网络的技术特点,实用于物联网、工业互联网等场景。
微信公众号:netwarps