p2panda_net/iroh_mdns/api.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use std::sync::Arc;
4
5use ractor::ActorRef;
6use thiserror::Error;
7use tokio::sync::RwLock;
8
9use crate::address_book::AddressBook;
10use crate::iroh_endpoint::Endpoint;
11use crate::iroh_mdns::Builder;
12use crate::iroh_mdns::actor::{MdnsActorArgs, ToMdns};
13
14/// Resolve transport information for nearby nodes on the local-area network via multicast DNS
15/// (mDNS).
16///
17/// ## Example
18///
19/// ```rust
20/// # use std::error::Error;
21/// #
22/// # #[tokio::main]
23/// # async fn main() -> Result<(), Box<dyn Error>> {
24/// # use futures_util::StreamExt;
25/// # use p2panda_core::Hash;
26/// # use p2panda_net::iroh_mdns::MdnsDiscoveryMode;
27/// # use p2panda_net::{AddressBook, Discovery, Endpoint, MdnsDiscovery, Gossip};
28/// # let address_book = AddressBook::builder().spawn().await?;
29/// # let endpoint = Endpoint::builder(address_book.clone())
30/// # .spawn()
31/// # .await?;
32/// #
33/// let mdns = MdnsDiscovery::builder(address_book, endpoint)
34/// .mode(MdnsDiscoveryMode::Active)
35/// .spawn()
36/// .await?;
37/// #
38/// # Ok(())
39/// # }
40/// ```
41///
42/// ## Active vs. Passive Mode
43///
44/// mDNS Discovery is set to "passive" mode by default which allows you to resolve transport
45/// information for other nodes without leaking your own information. Set it to "active" mode using
46/// [`MdnsDiscoveryMode`](crate::iroh_mdns::MdnsDiscoveryMode) if you want to publish your IP
47/// address on the local-area network.
48#[derive(Clone)]
49pub struct MdnsDiscovery {
50 #[allow(unused)]
51 pub(super) args: MdnsActorArgs,
52 #[allow(unused)]
53 pub(super) inner: Arc<RwLock<Inner>>,
54}
55
56pub(super) struct Inner {
57 pub(super) actor_ref: Option<ActorRef<ToMdns>>,
58}
59
60impl MdnsDiscovery {
61 pub(crate) fn new(actor_ref: Option<ActorRef<ToMdns>>, args: MdnsActorArgs) -> Self {
62 Self {
63 args,
64 inner: Arc::new(RwLock::new(Inner { actor_ref })),
65 }
66 }
67
68 pub fn builder(address_book: AddressBook, endpoint: Endpoint) -> Builder {
69 Builder::new(address_book, endpoint)
70 }
71}
72
73impl Drop for Inner {
74 fn drop(&mut self) {
75 if let Some(actor_ref) = self.actor_ref.take() {
76 actor_ref.stop(None);
77 }
78 }
79}
80
81#[derive(Debug, Error)]
82pub enum MdnsDiscoveryError {
83 /// Spawning the internal actor failed.
84 #[error(transparent)]
85 ActorSpawn(#[from] ractor::SpawnErr),
86
87 /// Spawning the internal actor as a child actor of a supervisor failed.
88 #[cfg(feature = "supervisor")]
89 #[error(transparent)]
90 ActorLinkedSpawn(#[from] crate::supervisor::SupervisorError),
91
92 /// Messaging with internal actor via RPC failed.
93 #[error(transparent)]
94 ActorRpc(#[from] Box<ractor::RactorErr<ToMdns>>),
95}