batman_robin/client.rs
1use super::Error;
2use crate::commands;
3use crate::model;
4use futures::stream::BoxStream;
5use validator::Validate;
6
7/// High-level client for interacting with the BATMAN-adv mesh network.
8///
9/// `Client` provides asynchronous methods to query and configure BATMAN-adv
10/// interfaces and settings via netlink.
11///
12/// Mesh-targeted methods take a [`model::MeshSelector`] by value. You can build
13/// selectors explicitly with [`model::MeshSelector::with_name`] or
14/// [`model::MeshSelector::with_ifindex`].
15///
16/// # Example
17///
18/// ```no_run
19/// use batman_robin::{Client, MeshSelector};
20///
21/// # async fn example() -> Result<(), batman_robin::Error> {
22/// let client = Client::new();
23/// let selector = MeshSelector::with_name("bat0");
24///
25/// let neighbors = client.neighbors(selector.clone()).await?;
26/// println!("{} neighbor entries", neighbors.len());
27/// # Ok(())
28/// # }
29/// ```
30#[derive(Clone)]
31pub struct Client;
32
33impl Default for Client {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl Client {
40 /// Creates a new instance of `Client`.
41 ///
42 /// # Example
43 ///
44 /// ```no_run
45 /// use batman_robin::Client;
46 ///
47 /// let client = Client::new();
48 /// let _ = client;
49 /// ```
50 pub fn new() -> Self {
51 Self {}
52 }
53
54 /// Resolves a `MeshSelector` into a concrete interface index.
55 ///
56 /// This method validates the selector first, then resolves by `ifindex` directly
57 /// when present or by interface `name` via `if_nametoindex`.
58 ///
59 /// # Arguments
60 /// * `selector` - Mesh selector (by name and/or ifindex).
61 ///
62 /// # Errors
63 /// Returns [`Error::Argument`] if validation fails.
64 /// Returns [`Error::Netlink`] if name resolution fails.
65 async fn selector_to_ifindex(&self, selector: model::MeshSelector) -> Result<u32, Error> {
66 selector
67 .validate()
68 .map_err(|err| Error::Argument(err.to_string()))?;
69
70 if let Some(ifindex) = selector.ifindex {
71 return Ok(ifindex);
72 }
73
74 if let Some(name) = selector.name {
75 return commands::if_nametoindex(name.as_str()).await.map_err(|_| {
76 Error::Netlink(format!(
77 "Error - interface '{}' is not present or not a batman-adv interface",
78 name
79 ))
80 });
81 }
82
83 Err(Error::Argument("Invalid selector".to_string()))
84 }
85
86 /// Resolves an `InterfaceSelector` into a concrete interface index.
87 ///
88 /// This method validates the selector first, then resolves by `ifindex` directly
89 /// when present or by interface `name` via `if_nametoindex`.
90 ///
91 /// # Arguments
92 /// * `selector` - Interface selector (by name and/or ifindex).
93 ///
94 /// # Errors
95 /// Returns [`Error::Argument`] if validation fails.
96 /// Returns [`Error::Netlink`] if name resolution fails.
97 async fn interface_selector_to_ifindex(
98 &self,
99 selector: model::InterfaceSelector,
100 ) -> Result<u32, Error> {
101 selector
102 .validate()
103 .map_err(|err| Error::Argument(err.to_string()))?;
104
105 if let Some(ifindex) = selector.ifindex {
106 return Ok(ifindex);
107 }
108
109 if let Some(name) = selector.name {
110 return commands::if_nametoindex(name.as_str()).await.map_err(|_| {
111 Error::Netlink(format!("Error - interface '{}' is not present", name))
112 });
113 }
114
115 Err(Error::Argument("Invalid selector".to_string()))
116 }
117
118 /// Retrieves the list of originators for the selected mesh interface.
119 ///
120 /// # Arguments
121 /// * `selector` - Mesh selector.
122 ///
123 /// # Example
124 ///
125 /// ```no_run
126 /// use batman_robin::{Client, MeshSelector};
127 ///
128 /// # async fn example() -> Result<(), batman_robin::Error> {
129 /// let client = Client::new();
130 /// let entries = client.originators(MeshSelector::with_name("bat0")).await?;
131 /// println!("{} originators", entries.len());
132 /// # Ok(())
133 /// # }
134 /// ```
135 #[tracing::instrument(skip(self))]
136 pub async fn originators(
137 &self,
138 selector: model::MeshSelector,
139 ) -> Result<Vec<model::Originator>, Error> {
140 let ifindex = self.selector_to_ifindex(selector).await?;
141 commands::get_originators(ifindex).await
142 }
143
144 /// Retrieves the list of gateways for the selected mesh interface.
145 ///
146 /// # Arguments
147 /// * `selector` - Mesh selector.
148 ///
149 /// # Example
150 ///
151 /// ```no_run
152 /// use batman_robin::{Client, MeshSelector};
153 ///
154 /// # async fn example() -> Result<(), batman_robin::Error> {
155 /// let client = Client::new();
156 /// let gateways = client.gateways(Some(MeshSelector::with_name("bat0"))).await?;
157 /// println!("{} gateways", gateways.len());
158 /// // Pass None to query gateways across all mesh interfaces:
159 /// let all = client.gateways(None).await?;
160 /// # Ok(())
161 /// # }
162 /// ```
163 #[tracing::instrument(skip(self))]
164 pub async fn gateways(
165 &self,
166 selector: Option<model::MeshSelector>,
167 ) -> Result<Vec<model::Gateway>, Error> {
168 let ifindex = if let Some(selector) = selector {
169 Some(self.selector_to_ifindex(selector).await?)
170 } else {
171 None
172 };
173 commands::get_gateways_list(ifindex).await
174 }
175
176 /// Subscribes to gateway change events for the selected mesh interface.
177 ///
178 /// # Arguments
179 /// * `selector` - Mesh selector.
180 ///
181 /// # Example
182 ///
183 /// ```no_run
184 /// use batman_robin::{Client, MeshSelector};
185 /// use futures::StreamExt;
186 ///
187 /// # async fn example() -> Result<(), batman_robin::Error> {
188 /// let client = Client::new();
189 /// let mut events = client
190 /// .subscribe_gateway_events(Some(MeshSelector::with_name("bat0")))
191 /// .await?;
192 ///
193 /// while let Some(event) = events.next().await {
194 /// println!("{:?}", event?);
195 /// }
196 /// # Ok(())
197 /// # }
198 /// ```
199 #[tracing::instrument(skip(self))]
200 pub async fn subscribe_gateway_events(
201 &self,
202 selector: Option<model::MeshSelector>,
203 ) -> Result<BoxStream<'static, Result<model::GatewayEvent, Error>>, Error> {
204 let ifindex = if let Some(selector) = selector {
205 Some(self.selector_to_ifindex(selector).await?)
206 } else {
207 None
208 };
209 commands::UeventListener::subscribe_events(ifindex).await
210 }
211
212 /// Gets current gateway mode and related configuration for the selected mesh interface.
213 ///
214 /// # Arguments
215 /// * `selector` - Mesh selector.
216 ///
217 /// # Example
218 ///
219 /// ```no_run
220 /// use batman_robin::{Client, MeshSelector};
221 ///
222 /// # async fn example() -> Result<(), batman_robin::Error> {
223 /// let client = Client::new();
224 /// let gw = client.get_gw_mode(MeshSelector::with_name("bat0")).await?;
225 /// println!("mode={:?}", gw.mode);
226 /// # Ok(())
227 /// # }
228 /// ```
229 #[tracing::instrument(skip(self))]
230 pub async fn get_gw_mode(
231 &self,
232 selector: model::MeshSelector,
233 ) -> Result<model::GatewayInfo, Error> {
234 let ifindex = self.selector_to_ifindex(selector).await?;
235 commands::get_gateway(ifindex).await
236 }
237
238 /// Sets gateway mode and optional parameters for the selected mesh interface.
239 ///
240 /// # Arguments
241 /// * `selector` - Mesh selector.
242 /// * `mode` - Gateway mode to apply.
243 /// * `down` - Optional downstream bandwidth parameter.
244 /// * `up` - Optional upstream bandwidth parameter.
245 /// * `sel_class` - Optional gateway selection class.
246 ///
247 /// # Errors
248 /// Returns [`Error`] if selector validation, selector resolution, or netlink write fails.
249 ///
250 /// # Example
251 ///
252 /// ```no_run
253 /// use batman_robin::{Client, GwMode, MeshSelector};
254 ///
255 /// # async fn example() -> Result<(), batman_robin::Error> {
256 /// let client = Client::new();
257 /// client
258 /// .set_gw_mode(
259 /// MeshSelector::with_name("bat0"),
260 /// GwMode::Client,
261 /// None,
262 /// None,
263 /// Some(20),
264 /// )
265 /// .await?;
266 /// # Ok(())
267 /// # }
268 /// ```
269 #[tracing::instrument(skip(self))]
270 pub async fn set_gw_mode(
271 &self,
272 selector: model::MeshSelector,
273 mode: model::GwMode,
274 down: Option<u32>,
275 up: Option<u32>,
276 sel_class: Option<u32>,
277 ) -> Result<(), Error> {
278 let ifindex = self.selector_to_ifindex(selector).await?;
279 commands::set_gateway(mode, down, up, sel_class, ifindex).await
280 }
281
282 /// Retrieves global translation table entries for the selected mesh interface.
283 ///
284 /// # Arguments
285 /// * `selector` - Mesh selector.
286 ///
287 /// # Example
288 ///
289 /// ```no_run
290 /// use batman_robin::{Client, MeshSelector};
291 ///
292 /// # async fn example() -> Result<(), batman_robin::Error> {
293 /// let client = Client::new();
294 /// let tg = client.transglobal(MeshSelector::with_name("bat0")).await?;
295 /// println!("{} global entries", tg.len());
296 /// # Ok(())
297 /// # }
298 /// ```
299 pub async fn transglobal(
300 &self,
301 selector: model::MeshSelector,
302 ) -> Result<Vec<model::TransglobalEntry>, Error> {
303 let ifindex = self.selector_to_ifindex(selector).await?;
304 commands::get_transglobal(ifindex).await
305 }
306
307 /// Retrieves local translation table entries for the selected mesh interface.
308 ///
309 /// # Arguments
310 /// * `selector` - Mesh selector.
311 ///
312 /// # Example
313 ///
314 /// ```no_run
315 /// use batman_robin::{Client, MeshSelector};
316 ///
317 /// # async fn example() -> Result<(), batman_robin::Error> {
318 /// let client = Client::new();
319 /// let tl = client.translocal(MeshSelector::with_name("bat0")).await?;
320 /// println!("{} local entries", tl.len());
321 /// # Ok(())
322 /// # }
323 /// ```
324 #[tracing::instrument(skip(self))]
325 pub async fn translocal(
326 &self,
327 selector: model::MeshSelector,
328 ) -> Result<Vec<model::TranslocalEntry>, Error> {
329 let ifindex = self.selector_to_ifindex(selector).await?;
330 commands::get_translocal(ifindex).await
331 }
332
333 /// Retrieves the list of neighbors for the selected mesh interface.
334 ///
335 /// # Arguments
336 /// * `selector` - Mesh selector.
337 ///
338 /// # Example
339 ///
340 /// ```no_run
341 /// use batman_robin::{Client, MeshSelector};
342 ///
343 /// # async fn example() -> Result<(), batman_robin::Error> {
344 /// let client = Client::new();
345 /// let neighbors = client.neighbors(MeshSelector::with_name("bat0")).await?;
346 /// println!("{} neighbors", neighbors.len());
347 /// # Ok(())
348 /// # }
349 /// ```
350 #[tracing::instrument(skip(self))]
351 pub async fn neighbors(
352 &self,
353 selector: model::MeshSelector,
354 ) -> Result<Vec<model::Neighbor>, Error> {
355 let ifindex = self.selector_to_ifindex(selector).await?;
356 commands::get_neighbors(ifindex).await
357 }
358
359 /// Retrieves the list of physical interfaces attached to the selected mesh interface.
360 ///
361 /// # Arguments
362 /// * `selector` - Mesh selector.
363 ///
364 /// # Example
365 ///
366 /// ```no_run
367 /// use batman_robin::{Client, MeshSelector};
368 ///
369 /// # async fn example() -> Result<(), batman_robin::Error> {
370 /// let client = Client::new();
371 /// let ifaces = client.interface_list(MeshSelector::with_name("bat0")).await?;
372 /// println!("{} attached interfaces", ifaces.len());
373 /// # Ok(())
374 /// # }
375 /// ```
376 #[tracing::instrument(skip(self))]
377 pub async fn interface_list(
378 &self,
379 selector: model::MeshSelector,
380 ) -> Result<Vec<model::Interface>, Error> {
381 let ifindex = self.selector_to_ifindex(selector).await?;
382 commands::get_interfaces(ifindex).await
383 }
384
385 /// Adds a physical interface to a selected mesh interface.
386 ///
387 /// # Arguments
388 /// * `selector` - Mesh selector identifying the target mesh interface.
389 /// * `interface_selector` - Interface selector for the physical interface to add.
390 ///
391 /// # Example
392 ///
393 /// ```no_run
394 /// use batman_robin::{Client, InterfaceSelector, MeshSelector};
395 ///
396 /// # async fn example() -> Result<(), batman_robin::Error> {
397 /// let client = Client::new();
398 /// client
399 /// .interface_add(
400 /// MeshSelector::with_name("bat0"),
401 /// InterfaceSelector::with_name("wlan0"),
402 /// )
403 /// .await?;
404 /// # Ok(())
405 /// # }
406 /// ```
407 pub async fn interface_add(
408 &self,
409 selector: model::MeshSelector,
410 interface_selector: model::InterfaceSelector,
411 ) -> Result<(), Error> {
412 let mesh_ifindex = self.selector_to_ifindex(selector).await?;
413 let iface_ifindex = self
414 .interface_selector_to_ifindex(interface_selector)
415 .await?;
416
417 commands::set_interface(iface_ifindex, Some(mesh_ifindex)).await
418 }
419
420 /// Removes a physical interface from any mesh interface.
421 ///
422 /// # Arguments
423 /// * `interface_selector` - Interface selector for the physical interface to remove.
424 ///
425 /// # Example
426 ///
427 /// ```no_run
428 /// use batman_robin::{Client, InterfaceSelector};
429 ///
430 /// # async fn example() -> Result<(), batman_robin::Error> {
431 /// let client = Client::new();
432 /// client
433 /// .interface_remove(InterfaceSelector::with_name("wlan0"))
434 /// .await?;
435 /// # Ok(())
436 /// # }
437 /// ```
438 #[tracing::instrument(skip(self))]
439 pub async fn interface_remove(
440 &self,
441 interface_selector: model::InterfaceSelector,
442 ) -> Result<(), Error> {
443 let iface_ifindex = self
444 .interface_selector_to_ifindex(interface_selector)
445 .await?;
446
447 commands::set_interface(iface_ifindex, None).await
448 }
449
450 /// Creates a new BATMAN-adv mesh interface with an optional routing algorithm and MAC address.
451 ///
452 /// # Arguments
453 /// * `mesh_if` - Name of the interface to create.
454 /// * `routing_algo` - Optional routing algorithm string.
455 /// * `mac_addr` - Optional hardware address. A random locally-administered address is
456 /// generated if `None` to avoid conflicts with other devices on the network.
457 ///
458 /// # Example
459 ///
460 /// ```no_run
461 /// use batman_robin::Client;
462 ///
463 /// # async fn example() -> Result<(), batman_robin::Error> {
464 /// let client = Client::new();
465 /// client.mesh_create("bat0", Some("BATMAN_V"), None).await?;
466 /// # Ok(())
467 /// # }
468 /// ```
469 #[tracing::instrument(skip(self))]
470 pub async fn mesh_create(
471 &self,
472 mesh_if: &str,
473 routing_algo: Option<&str>,
474 mac_addr: Option<macaddr::MacAddr6>,
475 ) -> Result<(), Error> {
476 commands::create_mesh(mesh_if, routing_algo, mac_addr).await
477 }
478
479 /// Lists BATMAN-adv mesh interfaces available on the host.
480 ///
481 /// This method returns interfaces whose kernel link kind is `batadv`.
482 /// It is useful to discover existing mesh interfaces before selecting one
483 /// for operations like neighbors, gateways, or interface management.
484 ///
485 /// # Returns
486 ///
487 /// Returns a vector of mesh interface names for every detected
488 /// BATMAN-adv mesh interface.
489 ///
490 /// # Example
491 ///
492 /// ```no_run
493 /// use batman_robin::Client;
494 ///
495 /// # async fn example() -> Result<(), batman_robin::Error> {
496 /// let client = Client::new();
497 /// let meshes = client.mesh_list().await?;
498 ///
499 /// for mesh in meshes {
500 /// println!("mesh={}", mesh);
501 /// }
502 /// # Ok(())
503 /// # }
504 /// ```
505 #[tracing::instrument(skip(self))]
506 pub async fn mesh_list(&self) -> Result<Vec<String>, Error> {
507 commands::list_meshes().await
508 }
509
510 /// Destroys a BATMAN-adv mesh interface selected by name or ifindex.
511 ///
512 /// # Arguments
513 /// * `selector` - Mesh selector.
514 ///
515 /// # Example
516 ///
517 /// ```no_run
518 /// use batman_robin::{Client, MeshSelector};
519 ///
520 /// # async fn example() -> Result<(), batman_robin::Error> {
521 /// let client = Client::new();
522 /// client.mesh_delete(MeshSelector::with_name("bat0")).await?;
523 /// # Ok(())
524 /// # }
525 /// ```
526 #[tracing::instrument(skip(self))]
527 pub async fn mesh_delete(&self, selector: model::MeshSelector) -> Result<(), Error> {
528 let ifindex = self.selector_to_ifindex(selector).await?;
529 commands::delete_mesh(ifindex).await
530 }
531
532 /// Counts the number of physical interfaces attached to the selected mesh interface.
533 ///
534 /// # Arguments
535 /// * `selector` - Mesh selector.
536 ///
537 /// # Example
538 ///
539 /// ```no_run
540 /// use batman_robin::{Client, MeshSelector};
541 ///
542 /// # async fn example() -> Result<(), batman_robin::Error> {
543 /// let client = Client::new();
544 /// let count = client.interfaces_count(MeshSelector::with_name("bat0")).await?;
545 /// println!("{count}");
546 /// # Ok(())
547 /// # }
548 /// ```
549 #[tracing::instrument(skip(self))]
550 pub async fn interfaces_count(&self, selector: model::MeshSelector) -> Result<u32, Error> {
551 let ifindex = self.selector_to_ifindex(selector).await?;
552 commands::count_interfaces(ifindex).await
553 }
554
555 /// Gets whether packet aggregation is enabled on the selected mesh interface.
556 ///
557 /// # Arguments
558 /// * `selector` - Mesh selector.
559 ///
560 /// # Example
561 ///
562 /// ```no_run
563 /// use batman_robin::{Client, MeshSelector};
564 ///
565 /// # async fn example() -> Result<(), batman_robin::Error> {
566 /// let client = Client::new();
567 /// let enabled = client.get_aggregation(MeshSelector::with_name("bat0")).await?;
568 /// println!("{enabled}");
569 /// # Ok(())
570 /// # }
571 /// ```
572 #[tracing::instrument(skip(self))]
573 pub async fn get_aggregation(&self, selector: model::MeshSelector) -> Result<bool, Error> {
574 let ifindex = self.selector_to_ifindex(selector).await?;
575 commands::get_aggregation(ifindex).await
576 }
577
578 /// Enables or disables packet aggregation on the selected mesh interface.
579 ///
580 /// # Arguments
581 /// * `selector` - Mesh selector.
582 /// * `val` - `true` to enable, `false` to disable.
583 ///
584 /// # Example
585 ///
586 /// ```no_run
587 /// use batman_robin::{Client, MeshSelector};
588 ///
589 /// # async fn example() -> Result<(), batman_robin::Error> {
590 /// let client = Client::new();
591 /// client
592 /// .set_aggregation(MeshSelector::with_name("bat0"), true)
593 /// .await?;
594 /// # Ok(())
595 /// # }
596 /// ```
597 #[tracing::instrument(skip(self))]
598 pub async fn set_aggregation(
599 &self,
600 selector: model::MeshSelector,
601 val: bool,
602 ) -> Result<(), Error> {
603 let ifindex = self.selector_to_ifindex(selector).await?;
604 commands::set_aggregation(ifindex, val).await
605 }
606
607 /// Gets whether AP isolation is enabled on the selected mesh interface.
608 ///
609 /// # Arguments
610 /// * `selector` - Mesh selector.
611 ///
612 /// # Example
613 ///
614 /// ```no_run
615 /// use batman_robin::{Client, MeshSelector};
616 ///
617 /// # async fn example() -> Result<(), batman_robin::Error> {
618 /// let client = Client::new();
619 /// let enabled = client
620 /// .get_ap_isolation(MeshSelector::with_name("bat0"))
621 /// .await?;
622 /// println!("{enabled}");
623 /// # Ok(())
624 /// # }
625 /// ```
626 #[tracing::instrument(skip(self))]
627 pub async fn get_ap_isolation(&self, selector: model::MeshSelector) -> Result<bool, Error> {
628 let ifindex = self.selector_to_ifindex(selector).await?;
629 commands::get_ap_isolation(ifindex).await
630 }
631
632 /// Enables or disables AP isolation on the selected mesh interface.
633 ///
634 /// # Arguments
635 /// * `selector` - Mesh selector.
636 /// * `val` - `true` to enable, `false` to disable.
637 ///
638 /// # Example
639 ///
640 /// ```no_run
641 /// use batman_robin::{Client, MeshSelector};
642 ///
643 /// # async fn example() -> Result<(), batman_robin::Error> {
644 /// let client = Client::new();
645 /// client
646 /// .set_ap_isolation(MeshSelector::with_name("bat0"), true)
647 /// .await?;
648 /// # Ok(())
649 /// # }
650 /// ```
651 #[tracing::instrument(skip(self))]
652 pub async fn set_ap_isolation(
653 &self,
654 selector: model::MeshSelector,
655 val: bool,
656 ) -> Result<(), Error> {
657 let ifindex = self.selector_to_ifindex(selector).await?;
658 commands::set_ap_isolation(ifindex, val).await
659 }
660
661 /// Gets whether bridge loop avoidance is enabled on the selected mesh interface.
662 ///
663 /// # Arguments
664 /// * `selector` - Mesh selector.
665 ///
666 /// # Example
667 ///
668 /// ```no_run
669 /// use batman_robin::{Client, MeshSelector};
670 ///
671 /// # async fn example() -> Result<(), batman_robin::Error> {
672 /// let client = Client::new();
673 /// let enabled = client
674 /// .get_bridge_loop_avoidance(MeshSelector::with_name("bat0"))
675 /// .await?;
676 /// println!("{enabled}");
677 /// # Ok(())
678 /// # }
679 /// ```
680 #[tracing::instrument(skip(self))]
681 pub async fn get_bridge_loop_avoidance(
682 &self,
683 selector: model::MeshSelector,
684 ) -> Result<bool, Error> {
685 let ifindex = self.selector_to_ifindex(selector).await?;
686 commands::get_bridge_loop_avoidance(ifindex).await
687 }
688
689 /// Enables or disables bridge loop avoidance on the selected mesh interface.
690 ///
691 /// # Arguments
692 /// * `selector` - Mesh selector.
693 /// * `val` - `true` to enable, `false` to disable.
694 ///
695 /// # Example
696 ///
697 /// ```no_run
698 /// use batman_robin::{Client, MeshSelector};
699 ///
700 /// # async fn example() -> Result<(), batman_robin::Error> {
701 /// let client = Client::new();
702 /// client
703 /// .set_bridge_loop_avoidance(MeshSelector::with_name("bat0"), true)
704 /// .await?;
705 /// # Ok(())
706 /// # }
707 /// ```
708 #[tracing::instrument(skip(self))]
709 pub async fn set_bridge_loop_avoidance(
710 &self,
711 selector: model::MeshSelector,
712 val: bool,
713 ) -> Result<(), Error> {
714 let ifindex = self.selector_to_ifindex(selector).await?;
715 commands::set_bridge_loop_avoidance(ifindex, val).await
716 }
717
718 /// Retrieves the system default routing algorithm for BATMAN-adv.
719 ///
720 /// # Errors
721 /// Returns [`Error`] if the value cannot be retrieved from kernel state.
722 ///
723 /// # Example
724 ///
725 /// ```no_run
726 /// use batman_robin::Client;
727 ///
728 /// # async fn example() -> Result<(), batman_robin::Error> {
729 /// let client = Client::new();
730 /// let algo = client.get_default_routing_algo().await?;
731 /// println!("{algo}");
732 /// # Ok(())
733 /// # }
734 /// ```
735 #[tracing::instrument(skip(self))]
736 pub async fn get_default_routing_algo(&self) -> Result<String, Error> {
737 commands::get_default_routing_algo().await
738 }
739
740 /// Retrieves all active routing algorithms currently in use and their interfaces.
741 ///
742 /// Returns a vector of `(interface_name, algorithm_name)`.
743 ///
744 /// # Example
745 ///
746 /// ```no_run
747 /// use batman_robin::Client;
748 ///
749 /// # async fn example() -> Result<(), batman_robin::Error> {
750 /// let client = Client::new();
751 /// let active = client.get_active_routing_algos().await?;
752 /// for (iface, algo) in active {
753 /// println!("{iface}: {algo}");
754 /// }
755 /// # Ok(())
756 /// # }
757 /// ```
758 #[tracing::instrument(skip(self))]
759 pub async fn get_active_routing_algos(&self) -> Result<Vec<(String, String)>, Error> {
760 commands::get_active_routing_algos().await
761 }
762
763 /// Retrieves all routing algorithms available on the system.
764 ///
765 /// # Example
766 ///
767 /// ```no_run
768 /// use batman_robin::Client;
769 ///
770 /// # async fn example() -> Result<(), batman_robin::Error> {
771 /// let client = Client::new();
772 /// let available = client.get_available_routing_algos().await?;
773 /// println!("{} available algos", available.len());
774 /// # Ok(())
775 /// # }
776 /// ```
777 #[tracing::instrument(skip(self))]
778 pub async fn get_available_routing_algos(&self) -> Result<Vec<String>, Error> {
779 commands::get_available_routing_algos().await
780 }
781
782 /// Sets the system default routing algorithm.
783 ///
784 /// # Arguments
785 /// * `algo` - Algorithm name to set as default.
786 ///
787 /// # Example
788 ///
789 /// ```no_run
790 /// use batman_robin::Client;
791 ///
792 /// # async fn example() -> Result<(), batman_robin::Error> {
793 /// let client = Client::new();
794 /// client.set_default_routing_algo("BATMAN_V").await?;
795 /// # Ok(())
796 /// # }
797 /// ```
798 #[tracing::instrument(skip(self))]
799 pub async fn set_default_routing_algo(&self, algo: &str) -> Result<(), Error> {
800 commands::set_default_routing_algo(algo).await
801 }
802}