p2panda_net/address_book/
api.rs1use std::collections::HashSet;
4use std::sync::Arc;
5
6use p2panda_discovery::address_book::{BoxedAddressBookStore, BoxedError};
7use ractor::{ActorRef, call, cast};
8use thiserror::Error;
9use tokio::sync::RwLock;
10
11use crate::address_book::Builder;
12use crate::address_book::actor::ToAddressBookActor;
13use crate::address_book::report::ConnectionOutcome;
14use crate::addrs::{NodeInfo, NodeInfoError, TransportInfo};
15use crate::watchers::{UpdatesOnly, WatcherReceiver};
16use crate::{NodeId, TopicId};
17
18#[derive(Clone)]
64pub struct AddressBook {
65 pub(super) inner: Arc<RwLock<Inner>>,
66}
67
68pub(super) struct Inner {
69 pub(super) actor_ref: Option<ActorRef<ToAddressBookActor>>,
70}
71
72impl AddressBook {
73 pub(crate) fn new(actor_ref: Option<ActorRef<ToAddressBookActor>>) -> Self {
74 Self {
75 inner: Arc::new(RwLock::new(Inner { actor_ref })),
76 }
77 }
78
79 pub fn builder() -> Builder {
80 Builder::new()
81 }
82
83 pub async fn node_info(&self, node_id: NodeId) -> Result<Option<NodeInfo>, AddressBookError> {
87 let inner = self.inner.read().await;
88 let result = call!(
89 inner.actor_ref.as_ref().expect("actor spawned in builder"),
90 ToAddressBookActor::NodeInfo,
91 node_id
92 )
93 .map_err(Box::new)?;
94 Ok(result)
95 }
96
97 pub async fn insert_node_info(&self, node_info: NodeInfo) -> Result<bool, AddressBookError> {
106 let inner = self.inner.read().await;
107 let result = call!(
108 inner.actor_ref.as_ref().expect("actor spawned in builder"),
109 ToAddressBookActor::InsertNodeInfo,
110 node_info
111 )
112 .map_err(Box::new)??;
113 Ok(result)
114 }
115
116 pub async fn insert_transport_info(
129 &self,
130 node_id: NodeId,
131 transport_info: TransportInfo,
132 ) -> Result<bool, AddressBookError> {
133 let inner = self.inner.read().await;
134 let result = call!(
135 inner.actor_ref.as_ref().expect("actor spawned in builder"),
136 ToAddressBookActor::InsertTransportInfo,
137 node_id,
138 transport_info
139 )
140 .map_err(Box::new)??;
141 Ok(result)
142 }
143
144 pub async fn node_infos_by_topics(
145 &self,
146 topics: impl IntoIterator<Item = TopicId>,
147 ) -> Result<Vec<NodeInfo>, AddressBookError> {
148 let inner = self.inner.read().await;
149 let result = call!(
150 inner.actor_ref.as_ref().expect("actor spawned in builder"),
151 ToAddressBookActor::NodeInfosByTopics,
152 topics.into_iter().collect()
153 )
154 .map_err(Box::new)?;
155 Ok(result)
156 }
157
158 pub async fn set_topics(
159 &self,
160 node_id: NodeId,
161 topics: impl IntoIterator<Item = TopicId>,
162 ) -> Result<(), AddressBookError> {
163 let inner = self.inner.read().await;
164 cast!(
165 inner.actor_ref.as_ref().expect("actor spawned in builder"),
166 ToAddressBookActor::SetTopics(node_id, topics.into_iter().collect())
167 )
168 .map_err(Box::new)?;
169 Ok(())
170 }
171
172 pub async fn add_topic(&self, node_id: NodeId, topic: TopicId) -> Result<(), AddressBookError> {
173 let inner = self.inner.read().await;
174 cast!(
175 inner.actor_ref.as_ref().expect("actor spawned in builder"),
176 ToAddressBookActor::AddTopic(node_id, topic)
177 )
178 .map_err(Box::new)?;
179 Ok(())
180 }
181
182 pub async fn remove_topic(
183 &self,
184 node_id: NodeId,
185 topic: TopicId,
186 ) -> Result<(), AddressBookError> {
187 let inner = self.inner.read().await;
188 cast!(
189 inner.actor_ref.as_ref().expect("actor spawned in builder"),
190 ToAddressBookActor::RemoveTopic(node_id, topic)
191 )
192 .map_err(Box::new)?;
193 Ok(())
194 }
195
196 pub async fn watch_node_info(
198 &self,
199 node_id: NodeId,
200 updates_only: UpdatesOnly,
201 ) -> Result<WatcherReceiver<Option<NodeInfo>>, AddressBookError> {
202 let inner = self.inner.read().await;
203 let result = call!(
204 inner.actor_ref.as_ref().expect("actor spawned in builder"),
205 ToAddressBookActor::WatchNodeInfo,
206 node_id,
207 updates_only
208 )
209 .map_err(Box::new)?;
210 Ok(result)
211 }
212
213 pub async fn watch_topic(
215 &self,
216 topic_id: TopicId,
217 updates_only: UpdatesOnly,
218 ) -> Result<WatcherReceiver<HashSet<NodeId>>, AddressBookError> {
219 let inner = self.inner.read().await;
220 let result = call!(
221 inner.actor_ref.as_ref().expect("actor spawned in builder"),
222 ToAddressBookActor::WatchTopic,
223 topic_id,
224 updates_only
225 )
226 .map_err(Box::new)?;
227 Ok(result)
228 }
229
230 pub async fn watch_node_topics(
232 &self,
233 node_id: NodeId,
234 updates_only: UpdatesOnly,
235 ) -> Result<WatcherReceiver<HashSet<TopicId>>, AddressBookError> {
236 let inner = self.inner.read().await;
237 let result = call!(
238 inner.actor_ref.as_ref().expect("actor spawned in builder"),
239 ToAddressBookActor::WatchNodeTopics,
240 node_id,
241 updates_only
242 )
243 .map_err(Box::new)?;
244 Ok(result)
245 }
246
247 pub async fn report(
251 &self,
252 node_id: NodeId,
253 connection_outcome: ConnectionOutcome,
254 ) -> Result<(), AddressBookError> {
255 let inner = self.inner.read().await;
256 cast!(
257 inner.actor_ref.as_ref().expect("actor spawned in builder"),
258 ToAddressBookActor::Report(node_id, connection_outcome)
259 )
260 .map_err(Box::new)?;
261 Ok(())
262 }
263
264 pub(crate) async fn store(
265 &self,
266 ) -> Result<BoxedAddressBookStore<NodeId, NodeInfo>, AddressBookError> {
267 let inner = self.inner.read().await;
268 let result = call!(
269 inner.actor_ref.as_ref().expect("actor spawned in builder"),
270 ToAddressBookActor::Store
271 )
272 .map_err(Box::new)?;
273 Ok(result)
274 }
275}
276
277impl Drop for Inner {
278 fn drop(&mut self) {
279 if let Some(actor_ref) = self.actor_ref.take() {
280 actor_ref.stop(None);
281 }
282 }
283}
284
285#[derive(Debug, Error)]
286pub enum AddressBookError {
287 #[error(transparent)]
289 ActorSpawn(#[from] ractor::SpawnErr),
290
291 #[cfg(feature = "supervisor")]
293 #[error(transparent)]
294 ActorLinkedSpawn(#[from] crate::supervisor::SupervisorError),
295
296 #[error(transparent)]
298 ActorRpc(#[from] Box<ractor::RactorErr<ToAddressBookActor>>),
299
300 #[error(transparent)]
302 Store(#[from] BoxedError),
303
304 #[error(transparent)]
306 NodeInfo(#[from] NodeInfoError),
307}