Signed-off-by: Walker Crouse <walker.crouse@coop.co.uk>
This commit is contained in:
Walker Crouse 2020-09-28 22:25:46 -04:00
parent e0fea5b812
commit 954e749b82
6 changed files with 54 additions and 24 deletions

View File

@ -1,3 +1,5 @@
//! Trait definition for cross-platform browser
use crate::{EventLoop, NetworkInterface, Result, ServiceDiscoveredCallback}; use crate::{EventLoop, NetworkInterface, Result, ServiceDiscoveredCallback};
use std::any::Any; use std::any::Any;

View File

@ -1,3 +1,5 @@
//! Low level interface for interacting with `AvahiStringList`.
use crate::ffi::c_str; use crate::ffi::c_str;
use avahi_sys::{ use avahi_sys::{
avahi_free, avahi_string_list_add_pair, avahi_string_list_copy, avahi_string_list_equal, avahi_free, avahi_string_list_add_pair, avahi_string_list_copy, avahi_string_list_equal,
@ -9,18 +11,36 @@ use libc::{c_char, c_void};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ptr; use std::ptr;
/// Wraps the `AvahiStringList` pointer from the raw Avahi bindings.
///
/// `zeroconf::TxtRecord` provides the cross-platform bindings for this functionality.
#[derive(Debug)] #[derive(Debug)]
pub struct ManagedAvahiStringList(*mut AvahiStringList); pub struct ManagedAvahiStringList(*mut AvahiStringList);
impl ManagedAvahiStringList { impl ManagedAvahiStringList {
/// Creates a new empty TXT record
pub fn new() -> Self { pub fn new() -> Self {
Self(unsafe { avahi_string_list_new(ptr::null()) }) Self(unsafe { avahi_string_list_new(ptr::null()) })
} }
/// Delegate function for [`avahi_string_list_add_pair()`].
///
/// # Safety
/// This function is unsafe because it provides no guarantees about the given pointers that are
/// dereferenced.
///
/// [`avahi_string_list_add_pair()`]: https://avahi.org/doxygen/html/strlst_8h.html#a72e1b0f724f0c29b5e3c8792f385223f
pub unsafe fn add_pair(&mut self, key: *const c_char, value: *const c_char) { pub unsafe fn add_pair(&mut self, key: *const c_char, value: *const c_char) {
self.0 = avahi_string_list_add_pair(self.0, key, value); self.0 = avahi_string_list_add_pair(self.0, key, value);
} }
/// Delegate function for [`avahi_string_list_find()`]. Returns a new `AvahiStringListNode`.
///
/// # Safety
/// This function is unsafe because it provides no guarantees about the given pointers that are
/// dereferenced.
///
/// [`avahi_string_list_find()`]: https://avahi.org/doxygen/html/strlst_8h.html#aafc54c009a2a1608b517c15a7cf29944
pub unsafe fn find(&mut self, key: *const c_char) -> Option<AvahiStringListNode> { pub unsafe fn find(&mut self, key: *const c_char) -> Option<AvahiStringListNode> {
let node = avahi_string_list_find(self.0, key); let node = avahi_string_list_find(self.0, key);
if !node.is_null() { if !node.is_null() {
@ -30,17 +50,24 @@ impl ManagedAvahiStringList {
} }
} }
pub fn head(&mut self) -> AvahiStringListNode { /// Delegate function for [`avahi_string_list_length()`].
AvahiStringListNode::new(self.0) ///
} /// [`avahi_string_list_length()`]: https://avahi.org/doxygen/html/strlst_8h.html#a806c571b338e882390a180b1360c1456
pub fn length(&self) -> u32 { pub fn length(&self) -> u32 {
unsafe { avahi_string_list_length(self.0) } unsafe { avahi_string_list_length(self.0) }
} }
/// Delegate function for [`avahi_string_list_to_string()`].
///
/// [`avahi_string_list_to_string()`]: https://avahi.org/doxygen/html/strlst_8h.html#a5c4b9ab709f22f7741c165ca3756a78b
pub fn to_string(&self) -> AvahiString { pub fn to_string(&self) -> AvahiString {
unsafe { avahi_string_list_to_string(self.0).into() } unsafe { avahi_string_list_to_string(self.0).into() }
} }
/// Returns the first node in the list.
pub fn head(&mut self) -> AvahiStringListNode {
AvahiStringListNode::new(self.0)
}
} }
impl Clone for ManagedAvahiStringList { impl Clone for ManagedAvahiStringList {
@ -69,6 +96,9 @@ impl Drop for ManagedAvahiStringList {
} }
} }
/// Represents a node or sub-list in an `AvahiStringList`. This struct is similar to it's parent,
/// but it does not free the `AvahiStringList` once dropped and is bound to the lifetime of it's
/// parent.
#[derive(new)] #[derive(new)]
pub struct AvahiStringListNode<'a> { pub struct AvahiStringListNode<'a> {
list: *mut AvahiStringList, list: *mut AvahiStringList,
@ -76,6 +106,7 @@ pub struct AvahiStringListNode<'a> {
} }
impl<'a> AvahiStringListNode<'a> { impl<'a> AvahiStringListNode<'a> {
/// Returns the next node in the list, or `None` if last node.
pub fn next(self) -> Option<AvahiStringListNode<'a>> { pub fn next(self) -> Option<AvahiStringListNode<'a>> {
let next = unsafe { avahi_string_list_get_next(self.list) }; let next = unsafe { avahi_string_list_get_next(self.list) };
if next.is_null() { if next.is_null() {
@ -85,6 +116,7 @@ impl<'a> AvahiStringListNode<'a> {
} }
} }
/// Returns the `AvahiPair` for this list.
pub fn get_pair(&mut self) -> AvahiPair { pub fn get_pair(&mut self) -> AvahiPair {
let mut key: *mut c_char = ptr::null_mut(); let mut key: *mut c_char = ptr::null_mut();
let mut value: *mut c_char = ptr::null_mut(); let mut value: *mut c_char = ptr::null_mut();
@ -98,6 +130,7 @@ impl<'a> AvahiStringListNode<'a> {
} }
} }
/// Represents a key-value pair in an `AvahiStringList`.
#[derive(new, Getters)] #[derive(new, Getters)]
pub struct AvahiPair { pub struct AvahiPair {
key: AvahiString, key: AvahiString,
@ -105,10 +138,13 @@ pub struct AvahiPair {
value_size: usize, value_size: usize,
} }
/// Represents a string value returned by `AvahiStringList`. The underlying `*mut c_char` is freed
/// using the appropriate Avahi function.
#[derive(new)] #[derive(new)]
pub struct AvahiString(*mut c_char); pub struct AvahiString(*mut c_char);
impl AvahiString { impl AvahiString {
/// Returns this `AvahiStr` as a `&str` or `None` if null.
pub fn as_str(&self) -> Option<&str> { pub fn as_str(&self) -> Option<&str> {
if self.0.is_null() { if self.0.is_null() {
None None

View File

@ -2,6 +2,7 @@ use super::service_ref::{
BrowseServicesParams, GetAddressInfoParams, ManagedDNSServiceRef, ServiceResolveParams, BrowseServicesParams, GetAddressInfoParams, ManagedDNSServiceRef, ServiceResolveParams,
}; };
use super::{bonjour_util, constants}; use super::{bonjour_util, constants};
use crate::browser::TMdnsBrowser;
use crate::builder::BuilderDelegate; use crate::builder::BuilderDelegate;
use crate::ffi::{self, c_str, AsRaw, FromRaw}; use crate::ffi::{self, c_str, AsRaw, FromRaw};
use crate::{EventLoop, NetworkInterface, Result}; use crate::{EventLoop, NetworkInterface, Result};
@ -23,10 +24,8 @@ pub struct BonjourMdnsBrowser {
context: *mut BonjourBrowserContext, context: *mut BonjourBrowserContext,
} }
impl BonjourMdnsBrowser { impl TMdnsBrowser for BonjourMdnsBrowser {
/// Creates a new `BonjourMdnsBrowser` that browses for the specified `kind` fn new(kind: &str) -> Self {
/// (e.g. `_http._tcp`).
pub fn new(kind: &str) -> Self {
Self { Self {
service: Arc::default(), service: Arc::default(),
kind: c_string!(kind), kind: c_string!(kind),
@ -35,33 +34,22 @@ impl BonjourMdnsBrowser {
} }
} }
/// Sets the network interface on which to browse for services on. fn set_network_interface(&mut self, interface: NetworkInterface) {
///
/// Most applications will want to use the default value `NetworkInterface::Unspec` to browse
/// on all available interfaces.
pub fn set_network_interface(&mut self, interface: NetworkInterface) {
self.interface_index = bonjour_util::interface_index(interface); self.interface_index = bonjour_util::interface_index(interface);
} }
/// Sets the [`ServiceDiscoveredCallback`] that is invoked when the browser has discovered and fn set_service_discovered_callback(
/// resolved a service.
///
/// [`ServiceDiscoveredCallback`]: ../type.ServiceDiscoveredCallback.html
pub fn set_service_discovered_callback(
&self, &self,
service_discovered_callback: Box<ServiceDiscoveredCallback>, service_discovered_callback: Box<ServiceDiscoveredCallback>,
) { ) {
unsafe { (*self.context).service_discovered_callback = Some(service_discovered_callback) }; unsafe { (*self.context).service_discovered_callback = Some(service_discovered_callback) };
} }
/// Sets the optional user context to pass through to the callback. This is useful if you need fn set_context(&mut self, context: Box<dyn Any>) {
/// to share state between pre and post-callback. The context type must implement `Any`.
pub fn set_context(&mut self, context: Box<dyn Any>) {
unsafe { (*self.context).user_context = Some(Arc::from(context)) }; unsafe { (*self.context).user_context = Some(Arc::from(context)) };
} }
/// Starts the browser. Returns an `EventLoop` which can be called to keep the browser alive. fn browse_services(&mut self) -> Result<EventLoop> {
pub fn browse_services(&mut self) -> Result<EventLoop> {
debug!("Browsing services: {:?}", self); debug!("Browsing services: {:?}", self);
self.service.lock().unwrap().browse_services( self.service.lock().unwrap().browse_services(

View File

@ -1,4 +1,4 @@
//! Low level interface for interacting with `TXTRecordRef` //! Low level interface for interacting with `TXTRecordRef`.
use crate::Result; use crate::Result;
use bonjour_sys::{ use bonjour_sys::{

View File

@ -1,3 +1,5 @@
//! Crate prelude
pub use crate::browser::TMdnsBrowser; pub use crate::browser::TMdnsBrowser;
pub use crate::service::TMdnsService; pub use crate::service::TMdnsService;
pub use crate::txt_record::TTxtRecord; pub use crate::txt_record::TTxtRecord;

View File

@ -1,3 +1,5 @@
//! Trait definition for cross-platform service.
use crate::{EventLoop, NetworkInterface, Result, ServiceRegisteredCallback, TxtRecord}; use crate::{EventLoop, NetworkInterface, Result, ServiceRegisteredCallback, TxtRecord};
use std::any::Any; use std::any::Any;