Я собираюсь написать поведение сети, использующее mDNS, floodsub и kademlia DHT. До сих пор я заставил каждую из этих служб работать, но не смог использовать ответы этих служб для чего-либо значимого.
В идеале, я бы смог передать данные, которые приходят из события процесса поведения, подобного тому, которое будет реализовано для Kad DHT, в основной Swarm poll
l oop. Например, в моем случае у меня есть ссылка на структуру, представляющую граф, который сохраняется на диске через базу данных sled
. Право собственности на эту структуру существует в методе, который опрашивает рой. Как мне go обновить этот график (например, добавить запись) при получении KademliaEvent
?
Решения, которые я пробовал:
- Перенос права собственности на данные структуру, которую я хочу обновить до структуры
ClientBehavior
, чтобы я мог просто self.my_data_structure.add(result);
из KademliaEvent
inject_event
метода #[derive(NetworkBehaviour)]
НЕ нравится это вообще Graph
является просто структурой и не генерирует никаких событий / реализаций NetworkBehaviour
- Создание
Context
структуры, которая derive
s NetworkBehaviour
и может использоваться для передачи ответ туда и обратно между методом опроса и соответствующим 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
}
}
и как я порождаю свой Swarm
и мой ClientBehavior
:
// 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
сам?