diff --git a/README.md b/README.md index c29ecf1..eea7020 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ use std::any::Any; use std::sync::Arc; use std::time::Duration; use zeroconf::{MdnsBrowser, ServiceDiscovery}; +use zeroconf::prelude::*; fn main() { let mut browser = MdnsBrowser::new("_http._tcp"); diff --git a/examples/browser/src/main.rs b/examples/browser/src/main.rs index adbe309..7248169 100644 --- a/examples/browser/src/main.rs +++ b/examples/browser/src/main.rs @@ -2,6 +2,7 @@ use std::any::Any; use std::sync::Arc; use std::time::Duration; use zeroconf::{MdnsBrowser, ServiceDiscovery}; +use zeroconf::prelude::*; fn main() { let mut browser = MdnsBrowser::new("_http._tcp"); diff --git a/zeroconf/src/browser.rs b/zeroconf/src/browser.rs new file mode 100644 index 0000000..c07a71f --- /dev/null +++ b/zeroconf/src/browser.rs @@ -0,0 +1,29 @@ +use crate::{EventLoop, NetworkInterface, Result, ServiceDiscoveredCallback}; +use std::any::Any; + +pub trait TMdnsBrowser { + /// Creates a new `MdnsBrowser` that browses for the specified `kind` (e.g. `_http._tcp`) + fn new(kind: &str) -> Self; + + /// Sets the network interface on which to browse for services on. + /// + /// Most applications will want to use the default value `NetworkInterface::Unspec` to browse + /// on all available interfaces. + fn set_network_interface(&mut self, interface: NetworkInterface); + + /// Sets the [`ServiceDiscoveredCallback`] that is invoked when the browser has discovered and + /// resolved a service. + /// + /// [`ServiceDiscoveredCallback`]: ../type.ServiceDiscoveredCallback.html + fn set_service_discovered_callback( + &mut self, + service_discovered_callback: Box, + ); + + /// Sets the optional user context to pass through to the callback. This is useful if you need + /// to share state between pre and post-callback. The context type must implement `Any`. + fn set_context(&mut self, context: Box); + + /// Starts the browser. Returns an `EventLoop` which can be called to keep the browser alive. + fn browse_services(&mut self) -> Result; +} diff --git a/zeroconf/src/lib.rs b/zeroconf/src/lib.rs index 62185f6..4ed1f4d 100644 --- a/zeroconf/src/lib.rs +++ b/zeroconf/src/lib.rs @@ -22,50 +22,50 @@ //! use std::time::Duration; //! use zeroconf::{MdnsService, ServiceRegistration, TxtRecord}; //! use zeroconf::prelude::*; -//! +//! //! #[derive(Default, Debug)] //! pub struct Context { //! service_name: String, //! } -//! +//! //! fn main() { //! let mut service = MdnsService::new("_http._tcp", 8080); //! let mut txt_record = TxtRecord::new(); //! let context: Arc> = Arc::default(); -//! +//! //! txt_record.insert("foo", "bar").unwrap(); -//! +//! //! service.set_registered_callback(Box::new(on_service_registered)); //! service.set_context(Box::new(context)); //! service.set_txt_record(txt_record); -//! +//! //! let event_loop = service.register().unwrap(); -//! +//! //! loop { //! // calling `poll()` will keep this service alive //! event_loop.poll(Duration::from_secs(0)).unwrap(); //! } //! } -//! +//! //! fn on_service_registered( //! result: zeroconf::Result, //! context: Option>, //! ) { //! let service = result.unwrap(); -//! +//! //! println!("Service registered: {:?}", service); -//! +//! //! let context = context //! .as_ref() //! .unwrap() //! .downcast_ref::>>() //! .unwrap() //! .clone(); -//! +//! //! context.lock().unwrap().service_name = service.name().clone(); -//! +//! //! println!("Context: {:?}", context); -//! +//! //! // ... //! } //! ``` @@ -76,6 +76,7 @@ //! use std::sync::Arc; //! use std::time::Duration; //! use zeroconf::{MdnsBrowser, ServiceDiscovery}; +//! use zeroconf::prelude::*; //! //! fn main() { //! let mut browser = MdnsBrowser::new("_http._tcp"); @@ -138,10 +139,12 @@ mod interface; mod tests; mod txt_record; +pub mod browser; pub mod builder; pub mod error; pub mod ffi; pub mod prelude; +pub mod service; #[cfg(target_os = "linux")] pub mod linux; diff --git a/zeroconf/src/linux/browser.rs b/zeroconf/src/linux/browser.rs index 48cfd96..b1c3ff8 100644 --- a/zeroconf/src/linux/browser.rs +++ b/zeroconf/src/linux/browser.rs @@ -6,6 +6,7 @@ use super::raw_browser::{ManagedAvahiServiceBrowser, ManagedAvahiServiceBrowserP use super::resolver::{ ManagedAvahiServiceResolver, ManagedAvahiServiceResolverParams, ServiceResolverSet, }; +use crate::browser::TMdnsBrowser; use crate::builder::BuilderDelegate; use crate::ffi::{c_str, AsRaw, FromRaw}; use crate::Result; @@ -32,9 +33,8 @@ pub struct AvahiMdnsBrowser { context: *mut AvahiBrowserContext, } -impl AvahiMdnsBrowser { - /// Creates a new `AvahiMdnsBrowser` that browses for the specified `kind` (e.g. `_http._tcp`) - pub fn new(kind: &str) -> Self { +impl TMdnsBrowser for AvahiMdnsBrowser { + fn new(kind: &str) -> Self { Self { client: None, poll: None, @@ -45,33 +45,22 @@ impl AvahiMdnsBrowser { } } - /// Sets the network interface on which to browse for services on. - /// - /// 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) { + fn set_network_interface(&mut self, interface: NetworkInterface) { self.interface_index = avahi_util::interface_index(interface); } - /// Sets the [`ServiceDiscoveredCallback`] that is invoked when the browser has discovered and - /// resolved a service. - /// - /// [`ServiceDiscoveredCallback`]: ../type.ServiceDiscoveredCallback.html - pub fn set_service_discovered_callback( + fn set_service_discovered_callback( &mut self, service_discovered_callback: Box, ) { 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 - /// to share state between pre and post-callback. The context type must implement `Any`. - pub fn set_context(&mut self, context: Box) { + fn set_context(&mut self, context: Box) { unsafe { (*self.context).user_context = Some(Arc::from(context)) }; } - /// Starts the browser. Returns an `EventLoop` which can be called to keep the browser alive. - pub fn browse_services(&mut self) -> Result { + fn browse_services(&mut self) -> Result { debug!("Browsing services: {:?}", self); self.poll = Some(Arc::new(ManagedAvahiSimplePoll::new()?)); diff --git a/zeroconf/src/linux/service.rs b/zeroconf/src/linux/service.rs index 51612d1..83cdc1e 100644 --- a/zeroconf/src/linux/service.rs +++ b/zeroconf/src/linux/service.rs @@ -29,7 +29,6 @@ pub struct AvahiMdnsService { } impl AvahiMdnsService { - /// Creates a new `AvahiMdnsService` with the specified `kind` (e.g. `_http._tcp`) and `port`. pub fn new(kind: &str, port: u16) -> Self { Self { client: None, @@ -49,51 +48,30 @@ impl AvahiMdnsService { unsafe { (*self.context).name = Some(c_string!(name)) }; } - /// Sets the network interface to bind this service to. - /// - /// Most applications will want to use the default value `NetworkInterface::Unspec` to bind to - /// all available interfaces. pub fn set_network_interface(&mut self, interface: NetworkInterface) { unsafe { (*self.context).interface_index = avahi_util::interface_index(interface) }; } - /// Sets the domain on which to advertise the service. - /// - /// Most applications will want to use the default value of `ptr::null()` to register to the - /// default domain. pub fn set_domain(&mut self, _domain: &str) { todo!() } - /// Sets the SRV target host name. - /// - /// Most applications will want to use the default value of `ptr::null()` to use the machine's - // default host name. pub fn set_host(&mut self, _host: &str) { todo!() } - /// Sets the optional `TxtRecord` to register this service with. pub fn set_txt_record(&mut self, txt_record: TxtRecord) { self.txt_record = Some(txt_record); } - /// Sets the [`ServiceRegisteredCallback`] that is invoked when the service has been - /// registered. - /// - /// [`ServiceRegisteredCallback`]: ../type.ServiceRegisteredCallback.html pub fn set_registered_callback(&mut self, registered_callback: Box) { unsafe { (*self.context).registered_callback = Some(registered_callback) }; } - /// Sets the optional user context to pass through to the callback. This is useful if you need - /// to share state between pre and post-callback. The context type must implement `Any`. pub fn set_context(&mut self, context: Box) { unsafe { (*self.context).user_context = Some(Arc::from(context)) }; } - /// Registers and start's the service. Returns an `EventLoop` which can be called to keep - /// the service alive. pub fn register(&mut self) -> Result { debug!("Registering service: {:?}", self); diff --git a/zeroconf/src/linux/txt_record.rs b/zeroconf/src/linux/txt_record.rs index 2fbc7d0..2703681 100644 --- a/zeroconf/src/linux/txt_record.rs +++ b/zeroconf/src/linux/txt_record.rs @@ -8,6 +8,7 @@ use std::cell::UnsafeCell; pub struct AvahiTxtRecord(UnsafeCell); impl AvahiTxtRecord { + #[allow(clippy::mut_from_ref)] fn inner(&self) -> &mut ManagedAvahiStringList { unsafe { &mut *self.0.get() } } @@ -98,11 +99,7 @@ impl Iterator for Iter<'_> { type Item = (String, String); fn next(&mut self) -> Option { - if self.node.is_none() { - return None; - } - - let mut n = self.node.take().unwrap(); + let mut n = self.node.take()?; let pair = n.get_pair(); self.node = n.next(); diff --git a/zeroconf/src/macos/service.rs b/zeroconf/src/macos/service.rs index 545c227..3061fda 100644 --- a/zeroconf/src/macos/service.rs +++ b/zeroconf/src/macos/service.rs @@ -3,6 +3,7 @@ use super::{bonjour_util, constants}; use crate::builder::BuilderDelegate; use crate::ffi::c_str::{self, AsCChars}; use crate::ffi::{FromRaw, UnwrapOrNull}; +use crate::service::TMdnsService; use crate::{ EventLoop, NetworkInterface, Result, ServiceRegisteredCallback, ServiceRegistration, TxtRecord, }; @@ -26,10 +27,8 @@ pub struct BonjourMdnsService { context: *mut BonjourServiceContext, } -impl BonjourMdnsService { - /// Creates a new `BonjourMdnsService` with the specified `kind` (e.g. `_http._tcp`) and - /// `port`. - pub fn new(kind: &str, port: u16) -> Self { +impl TMdnsService for BonjourMdnsService { + fn new(kind: &str, port: u16) -> Self { Self { service: Arc::default(), kind: c_string!(kind), @@ -45,56 +44,35 @@ impl BonjourMdnsService { /// Sets the name to register this service under. If no name is set, Bonjour will /// automatically assign one (usually to the name of the machine). - pub fn set_name(&mut self, name: &str) { + fn set_name(&mut self, name: &str) { self.name = Some(c_string!(name)); } - /// Sets the network interface to bind this service to. - /// - /// Most applications will want to use the default value `NetworkInterface::Unspec` to bind to - /// all available interfaces. - pub fn set_network_interface(&mut self, interface: NetworkInterface) { + fn set_network_interface(&mut self, interface: NetworkInterface) { self.interface_index = bonjour_util::interface_index(interface); } - /// Sets the domain on which to advertise the service. - /// - /// Most applications will want to use the default value of `ptr::null()` to register to the - /// default domain. - pub fn set_domain(&mut self, domain: &str) { + fn set_domain(&mut self, domain: &str) { self.domain = Some(c_string!(domain)); } - /// Sets the SRV target host name. - /// - /// Most applications will want to use the default value of `ptr::null()` to use the machine's - // default host name. - pub fn set_host(&mut self, host: &str) { + fn set_host(&mut self, host: &str) { self.host = Some(c_string!(host)); } - /// Sets the optional `TxtRecord` to register this service with. - pub fn set_txt_record(&mut self, txt_record: TxtRecord) { + fn set_txt_record(&mut self, txt_record: TxtRecord) { self.txt_record = Some(txt_record); } - /// Sets the [`ServiceRegisteredCallback`] that is invoked when the service has been - /// registered. - /// - /// [`ServiceRegisteredCallback`]: ../type.ServiceRegisteredCallback.html - pub fn set_registered_callback(&mut self, registered_callback: Box) { + fn set_registered_callback(&mut self, registered_callback: Box) { unsafe { (*self.context).registered_callback = Some(registered_callback) }; } - /// Sets the optional user context to pass through to the callback. This is useful if you need - /// to share state between pre and post-callback. The context type must implement `Any`. - pub fn set_context(&mut self, context: Box) { + fn set_context(&mut self, context: Box) { unsafe { (*self.context).user_context = Some(Arc::from(context)) }; } - /// Registers and start's the service. Returns an `EventLoop` which can be called to keep - /// the service alive. - pub fn register(&mut self) -> Result { + fn register(&mut self) -> Result { debug!("Registering service: {:?}", self); let txt_len = self diff --git a/zeroconf/src/prelude.rs b/zeroconf/src/prelude.rs index 8280657..49386b1 100644 --- a/zeroconf/src/prelude.rs +++ b/zeroconf/src/prelude.rs @@ -1 +1,3 @@ +pub use crate::browser::TMdnsBrowser; +pub use crate::service::TMdnsService; pub use crate::txt_record::TTxtRecord; diff --git a/zeroconf/src/service.rs b/zeroconf/src/service.rs new file mode 100644 index 0000000..ba27408 --- /dev/null +++ b/zeroconf/src/service.rs @@ -0,0 +1,45 @@ +use crate::{EventLoop, NetworkInterface, Result, ServiceRegisteredCallback, TxtRecord}; +use std::any::Any; + +pub trait TMdnsService { + /// Creates a new `MdnsService` with the specified `kind` (e.g. `_http._tcp`) and `port`. + fn new(kind: &str, port: u16) -> Self; + + /// Sets the name to register this service under. + fn set_name(&mut self, name: &str); + + /// Sets the network interface to bind this service to. + /// + /// Most applications will want to use the default value `NetworkInterface::Unspec` to bind to + /// all available interfaces. + fn set_network_interface(&mut self, interface: NetworkInterface); + + /// Sets the domain on which to advertise the service. + /// + /// Most applications will want to use the default value of `ptr::null()` to register to the + /// default domain. + fn set_domain(&mut self, _domain: &str); + + /// Sets the SRV target host name. + /// + /// Most applications will want to use the default value of `ptr::null()` to use the machine's + /// default host name. + fn set_host(&mut self, _host: &str); + + /// Sets the optional `TxtRecord` to register this service with. + fn set_txt_record(&mut self, txt_record: TxtRecord); + + /// Sets the [`ServiceRegisteredCallback`] that is invoked when the service has been + /// registered. + /// + /// [`ServiceRegisteredCallback`]: ../type.ServiceRegisteredCallback.html + fn set_registered_callback(&mut self, registered_callback: Box); + + /// Sets the optional user context to pass through to the callback. This is useful if you need + /// to share state between pre and post-callback. The context type must implement `Any`. + fn set_context(&mut self, context: Box); + + /// Registers and start's the service. Returns an `EventLoop` which can be called to keep + /// the service alive. + fn register(&mut self) -> Result; +} diff --git a/zeroconf/src/tests/service_test.rs b/zeroconf/src/tests/service_test.rs index e86a159..fbbb33b 100644 --- a/zeroconf/src/tests/service_test.rs +++ b/zeroconf/src/tests/service_test.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::{MdnsBrowser, MdnsService}; use std::sync::{Arc, Mutex}; use std::time::Duration; diff --git a/zeroconf/src/tests/txt_record_test.rs b/zeroconf/src/tests/txt_record_test.rs index cc90040..e1ca2cc 100644 --- a/zeroconf/src/tests/txt_record_test.rs +++ b/zeroconf/src/tests/txt_record_test.rs @@ -59,8 +59,6 @@ fn iter_success() { fn keys_success() { super::setup(); - debug!("keys_success()"); - let mut record = TxtRecord::new(); record.insert("foo", "bar").unwrap(); record.insert("baz", "qux").unwrap(); @@ -76,8 +74,6 @@ fn keys_success() { fn values_success() { super::setup(); - debug!("values_success()"); - let mut record = TxtRecord::new(); record.insert("foo", "bar").unwrap(); record.insert("baz", "qux").unwrap(); diff --git a/zeroconf/src/txt_record.rs b/zeroconf/src/txt_record.rs index 1814dbb..85a0c12 100644 --- a/zeroconf/src/txt_record.rs +++ b/zeroconf/src/txt_record.rs @@ -80,7 +80,7 @@ impl PartialEq for TxtRecord { } } -// impl Eq for TxtRecord {} +impl Eq for TxtRecord {} impl Default for TxtRecord { fn default() -> Self {