gpt4 book ai didi

rust - 如何从派生的NetworkBehaviour发出SwarmEvent::Behaviour?

转载 作者:行者123 更新时间:2023-12-03 11:39:57 30 4
gpt4 key购买 nike

我正在寻找一种利用mDNS,floodsub和kademlia DHT的网络行为。到目前为止,我已经使所有这些服务都可以使用,但是还不能将这些服务的响应用于有意义的事情。

理想情况下,我将能够将来自行为过程事件的数据(例如将为Kad DHT实现的事件)输送到主Swarm poll循环中。例如,在我的情况下,我对表示通过sled数据库保留在磁盘上的图形的结构的引用。该结构的所有权存在于轮询群的方法中。收到KademliaEvent后,我将如何更新此图表(例如添加条目)?

我尝试过的解决方案:

  • 将数据结构的所有权移到我想更新为ClientBehavior结构的位置,这样我就可以通过self.my_data_structure.add(result); KademliaEvent方法中的inject_event
  • #[derive(NetworkBehaviour)]根本不喜欢这个
  • Graph只是一个结构,不会发出任何事件/实现NetworkBehaviour
  • 创建一个Context结构,该结构由deriveNetworkBehaviour组成,可用于在轮询方法和相应的inject_event方法之间来回传递响应
  • #[derive(NetworkBehaviour)]不能与Arc s/Mutex es
  • 一起使用

    这是我的NetworkBehavior的样子:

    /// A network behavior describing a client connected to a pub-sub compatible,
    /// optionally mDNS-compatible network. Such a "behavior" may be implemented for
    /// any libp2p transport, but any transport used with this behavior must implement
    /// asynchronous reading & writing capabilities.
    #[derive(NetworkBehaviour)]
    pub struct ClientBehavior<TSubstream: AsyncRead + AsyncWrite + Send + Unpin + 'static> {
    /// Some pubsub mechanism bound to the above transport
    pub floodsub: Floodsub<TSubstream>,

    /// Some mDNS service bound to the above transport
    pub mdns: Mdns<TSubstream>,

    /// Allow for the client to do some external discovery on the global network through a KAD DHT
    pub kad_dht: Kademlia<TSubstream, MemoryStore>,
    }

    我的Kademlia NetworkBehaviourEventProceess实现如下所示:

    impl<TSubstream: AsyncRead + AsyncWrite + Send + Unpin + 'static>
    NetworkBehaviourEventProcess<KademliaEvent> for ClientBehavior<TSubstream>
    {
    fn inject_event(&mut self, event: KademliaEvent) {
    // Some behavior logic, nothing special, really, just a bunch of matches
    // NOTE: this is when I'd want to update the `Graph`, since KademliaEvent will contain data that I need to put in the `Graph` instance
    }
    }

    以及如何生成 SwarmClientBehavior:

    // Initialize a new behavior for a client that we will generate in the not-so-distant future with the given peerId, alongside
    // an mDNS service handler as well as a floodsub instance targeted at the given peer
    let mut behavior = ClientBehavior {
    floodsub: Floodsub::new(self.peer_id.clone()),
    mdns: Mdns::new().await?,
    kad_dht: Kademlia::new(self.peer_id.clone(), store),
    };

    // Iterate through bootstrap addresses
    for bootstrap_peer in bootstrap_addresses {
    // NOTE: add_address is a method that isn't provided by #[derive(NetworkBehaviour)].
    // It's just a helper method I wrote that adds the peer to the Floodsub & DHT views.
    behavior.add_address(&bootstrap_peer.0, bootstrap_peer.1); // Add the bootstrap peer to the DHT
    }

    // Bootstrap the behavior's DHT
    behavior.kad_dht.bootstrap();

    // Note: here, `self` is a reference to a configuration struct holding a peer ID, and a keypair
    let mut swarm = Swarm::new(
    libp2p::build_tcp_ws_secio_mplex_yamux(self.keypair.clone())?,
    behavior,
    self.peer_id.clone(),
    ); // Initialize a swarm

    以及我如何轮询群:

    // NOTE: Here, `self` has ownership of the aforementioned `Graph` instance. I'd like to update this
    // instance from this block, or from the ClientBehavior itself--as long as I'm able to update it once a `KademliaEvent` is received.

    // Try to get the address we'll listen on
    if let Ok(addr) = format!("/ip4/0.0.0.0/tcp/{}", port).parse::<Multiaddr>() {
    // Try to tell the swarm to listen on this address, return an error if this doesn't work
    if let Err(e) = Swarm::listen_on(&mut swarm, addr.clone()) {
    // Convert the addr err into an io error
    let e: std::io::Error = io::ErrorKind::AddrNotAvailable.into();

    // Return an error
    return Err(e.into());
    };

    // Fetch the hash of the first transaction in the DAG from the network
    swarm
    .kad_dht
    .get_record(&Key::new(&sync::ROOT_TRANSACTION_KEY), Quorum::Majority);

    loop {
    // Poll the swarm
    match swarm.next_event().await {
    // NOTE: Initially, I was under the impression that I would be able to intercept
    // events from the ClientBehavior here. Yet, the below info! call is never reached.
    // This remains the case in libp2p example code that I have experimented with.
    SwarmEvent::Behaviour(e) => info!("idk: {:?}", e),

    _ => debug!("Some other event; this is handled specifically in the actual codebase, but for this question, all I really care about is the above behavior event."),
    };
    }
    }

    我是否只需要自己实现 NetworkBehaviour

    最佳答案

    您的问题有点晚了,但这也许会有所帮助:

    Moving ownership of the data structure I want to update to the ClientBehavior struct so I can just self.my_data_structure.add(result); from the KademliaEvent inject_event method

    • #[derive(NetworkBehaviour)] does NOT like this at all
    • Graph is just a struct, and doesn't emit any events / implement NetworkBehaviour

    documentation对此有以下说法:

    #[behaviour(ignore)] can be added on a struct field to disable generation of delegation to the fields which do not implement NetworkBehaviour.


    因为否则需要所有字段来实现NetworkBehaviour特性。
    那应该使它成为可行的解决方案。
    但是,无论哪种方式,如果您尝试修改超出Mdns范围的结构,我都相信¹,针对所有这些问题的最惯用的解决方案将是通过poll函数(返回 Poll::Ready(GenerateEvent(TOut)))发出自定义事件,然后您可以监听该事件通过另一个NetworkBehaviourEventProcess impl获取对应的结构,然后应修改该结构。
    类似于 libp2p-ping implementation使用VecDeque事件队列,然后在 poll()中传播该事件队列的方法,您可以在ClientBehaviour中有一个类似的队列(标记为 behaviour(ignore)]),追加到队列中,以 poll()发出事件,并在调用代码/等待中捕获该特定事件循环以某种方式?
    编辑: should also be able to extend the poll method允许以这种方式返回其他事件。
    ¹:我对rust-libp2p的能力还差强人意,并且到目前为止还没有足够的经验来说明事实,您的问题对我来说实际上是一个教程

    关于rust - 如何从派生的NetworkBehaviour发出SwarmEvent::Behaviour?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59812399/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com