概述
前言:
本文以floodsub为例,讨论如何在libp2p-rs上开发新协议,详细代码请查看源码。
实现两个trait
在libp2p-rs中,swarm提供了两个trait:
- Notifiee用于接收swarm的通知,当有新的连接创建或者连接关闭时,swarm会调用connected()或者disconnected();
- ProtocolHandler用于读写协议的数据,协议协商成功后,swarm会调用handle()。
/// Notifiee is an trait for an object wishing to receive notifications from swarm
pub trait Notifiee {
/// called when a connection opened
fn connected(&mut self, _conn: &mut Connection) {}
/// called when a connection closed
fn disconnected(&mut self, _conn: &mut Connection) {}
}
/// Common trait for upgrades that can be applied on inbound substreams, outbound substreams,
/// or both.
/// Possible upgrade on a connection or substream.
#[async_trait]
pub trait ProtocolHandler: UpgradeInfo + Notifiee {
/// After we have determined that the remote supports one of the protocols we support, this
/// method is called to start handling the inbound. Swarm will start invoking this method
/// in a newly spawned task.
///
/// The `info` is the identifier of the protocol, as produced by `protocol_info`.
async fn handle(&mut self, stream: Substream, info: <Self as UpgradeInfo>::Info) -> Result<(), Box<dyn Error>>;
/// This is to provide a clone method for the trait object.
fn box_clone(&self) -> IProtocolHandler;
}
floodsub handler实现Notifiee和ProtocolHandler
#[derive(Clone)]
pub struct Handler {
incoming_tx: mpsc::UnboundedSender<RPC>,
new_peer: mpsc::UnboundedSender<PeerEvent>,
}
impl Handler {
pub(crate) fn new(incoming_tx: mpsc::UnboundedSender<RPC>, new_peer: mpsc::UnboundedSender<PeerEvent>) -> Self {
Handler { incoming_tx, new_peer }
}
}
impl UpgradeInfo for Handler {
type Info = &'static [u8];
fn protocol_info(&self) -> Vec<Self::Info> {
vec![FLOOD_SUB_ID]
}
}
impl Notifiee for Handler {
fn connected(&mut self, conn: &mut Connection) {
let peer_id = conn.remote_peer();
let mut new_peers = self.new_peer.clone();
task::spawn(async move {
let _ = new_peers.send(PeerEvent::NewPeer(peer_id)).await;
});
}
}
#[async_trait]
impl ProtocolHandler for Handler {
async fn handle(&mut self, mut stream: Substream, _info: <Self as UpgradeInfo>::Info) -> Result<(), Box<dyn Error>> {
loop {
/* recv, decode and send to msg process mainloop */
self.incoming_tx.send(rpc).await.map_err(|_| FloodsubDecodeError::ProtocolExit)?;
}
}
fn box_clone(&self) -> IProtocolHandler {
Box::new(self.clone())
}
}
注册到swarm
let floodsub = FloodSub::new(FloodsubConfig::new(local_peer_id));
let handler = floodsub.handler();
let mut swarm = Swarm::new(local_key.public()).with_protocol(Box::new(handler))
还需要做什么
简单的协议,比如echo,那么所有事情都在ProtocolHandler.handle()中处理即可,到这里就结束了。
稍微复杂的协议,比如floodsub,最好将swarm的通知和收到的数据,发送到消息处理主循环进行处理,实时更新状态;
impl floodsub {
pub fn start(mut self, control: Swarm_Control) {
self.control = Some(control);
// well, self 'move' explicitly,
let mut floodsub = self;
task::spawn(async move {
let _ = floodsub.process_loop().await;
});
}
/// Message Process Loop.
pub async fn process_loop(&mut self) -> Result<()> {
loop {
select! {
cmd = self.peer_rx.next() => {
self.handle_peer_event(cmd).await;
}
rpc = self.incoming_rx.next() => {
self.handle_incoming_rpc(rpc).await?;
}
cmd = self.control_rx.next() => {
self.on_control_command(cmd).await?;
}
sub = self.cancel_rx.next() => {
self.un_subscribe(sub).await?;
}
}
}
}
}
从上面可以看到,floodsub消息处理主循环运行在一个task里面,start()时需要将self传递进去,因此后续的发布订阅等操作只能通过channel发消息,这就是control和handler包裹channel的原因。
#[derive(Clone)]
pub struct Control {
config: FloodsubConfig,
control_sender: mpsc::UnboundedSender<ControlCommand>,
}
impl Control {
/// Subscribe to messages on a given topic.
pub async fn subscribe(&mut self, topic: Topic) -> Option<Subscription> {
let (tx, rx) = oneshot::channel();
self.control_sender
.send(ControlCommand::Subscribe(topic, tx))
.await
.expect("control send subscribe");
rx.await.expect("Subscribe")
}
}
当新的连接创建时,floodsub会主动创建流,协商通过后向对方发送本节点感兴趣的topic。因此这里需要swarm的control。
self.control.as_mut().unwrap().new_stream(pid, vec![FLOOD_SUB_ID]).await;
总结
在libp2p-rs上面开发简单的协议,只需要两步,对于稍微复杂的协议,需要handler和control这类包裹channel的结构,将消息发送到协议消息处理主循环,以驱动整个协议的运转,完成特定的功能。
最后
以上就是大方抽屉为你收集整理的在libp2p-rs上开发新协议实现两个trait注册到swarm还需要做什么总结的全部内容,希望文章能够帮你解决在libp2p-rs上开发新协议实现两个trait注册到swarm还需要做什么总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复