Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion zeroconf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ categories = [
]
documentation = "https://docs.rs/zeroconf"

[features]
default = ["avahi"]
avahi = ["dep:avahi-sys"]

[dependencies]
serde = { version = "1.0.188", features = ["derive"], optional = true }
derive-getters = "0.3.0"
Expand All @@ -34,7 +38,7 @@ serde_json = "1.0.107"
clap = { version = "4.4.4", features = ["derive"] }

[target.'cfg(unix)'.dependencies]
avahi-sys = "0.10.1"
avahi-sys = { version = "0.10.1", optional = true }

[target.'cfg(target_vendor = "apple")'.dependencies]
bonjour-sys = "0.3.0"
Expand Down
3 changes: 3 additions & 0 deletions zeroconf/src/avahi/browser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ pub struct AvahiMdnsBrowser {
}

impl TMdnsBrowser for AvahiMdnsBrowser {
type EventLoop = EventLoop;
type TxtRecord = TxtRecord;

fn new(service_type: ServiceType) -> Self {
Self {
client: None,
Expand Down
3 changes: 3 additions & 0 deletions zeroconf/src/avahi/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub struct AvahiMdnsService {
}

impl TMdnsService for AvahiMdnsService {
type EventLoop = EventLoop;
type TxtRecord = TxtRecord;

fn new(service_type: ServiceType, port: u16) -> Self {
let kind = avahi_util::format_service_type(&service_type);

Expand Down
3 changes: 3 additions & 0 deletions zeroconf/src/bonjour/browser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ pub struct BonjourMdnsBrowser {
}

impl TMdnsBrowser for BonjourMdnsBrowser {
type EventLoop = EventLoop;
type TxtRecord = TxtRecord;

fn new(service_type: ServiceType) -> Self {
Self {
service: Arc::default(),
Expand Down
3 changes: 3 additions & 0 deletions zeroconf/src/bonjour/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ pub struct BonjourMdnsService {
}

impl TMdnsService for BonjourMdnsService {
type EventLoop = EventLoop;
type TxtRecord = TxtRecord;

fn new(service_type: ServiceType, port: u16) -> Self {
Self {
service: Arc::default(),
Expand Down
25 changes: 17 additions & 8 deletions zeroconf/src/browser.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
//! Trait definition for cross-platform browser

use crate::{EventLoop, NetworkInterface, Result, ServiceType, TxtRecord};
use crate::prelude::{TEventLoop, TTxtRecord};
use crate::{NetworkInterface, Result, ServiceType};
use std::any::Any;
use std::sync::Arc;

/// Event from [`MdnsBrowser`] received by the `ServiceBrowserCallback`.
///
/// [`MdnsBrowser`]: type.MdnsBrowser.html
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BrowserEvent {
Add(ServiceDiscovery),
pub enum BrowserEvent<TxtRecord> {
Add(ServiceDiscovery<TxtRecord>),
Remove(ServiceRemoval),
}

/// Interface for interacting with underlying mDNS implementation service browsing capabilities.
pub trait TMdnsBrowser {
type EventLoop: TEventLoop;
type TxtRecord: TTxtRecord;

/// Creates a new `MdnsBrowser` that browses for the specified `kind` (e.g. `_http._tcp`)
fn new(service_type: ServiceType) -> Self;

Expand All @@ -31,7 +35,10 @@ pub trait TMdnsBrowser {
/// resolved or removed a service.
///
/// [`ServiceBrowserCallback`]: ../type.ServiceBrowserCallback.html
fn set_service_callback(&mut self, service_callback: Box<ServiceBrowserCallback>);
fn set_service_callback(
&mut self,
service_callback: Box<ServiceBrowserCallback<Self::TxtRecord>>,
);

/// 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`.
Expand All @@ -41,7 +48,7 @@ pub trait TMdnsBrowser {
fn context(&self) -> Option<&dyn Any>;

/// Starts the browser. Returns an `EventLoop` which can be called to keep the browser alive.
fn browse_services(&mut self) -> Result<EventLoop>;
fn browse_services(&mut self) -> Result<Self::EventLoop>;
}

/// Callback invoked from [`MdnsBrowser`] once a service has been discovered and resolved or
Expand All @@ -52,14 +59,16 @@ pub trait TMdnsBrowser {
/// * `context` - The optional user context passed through
///
/// [`MdnsBrowser`]: type.MdnsBrowser.html
pub type ServiceBrowserCallback = dyn Fn(Result<BrowserEvent>, Option<Arc<dyn Any>>);
pub type ServiceBrowserCallback<TxtRecord> =
dyn Fn(Result<BrowserEvent<TxtRecord>>, Option<Arc<dyn Any>>);

/// Represents a service that has been discovered by a [`MdnsBrowser`].
///
/// [`MdnsBrowser`]: type.MdnsBrowser.html
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Getters, Builder, BuilderDelegate, Clone, PartialEq, Eq)]
pub struct ServiceDiscovery {
// TODO: Restore derive(BuilderDelegate)
#[derive(Debug, Getters, Builder, Clone, PartialEq, Eq)]
pub struct ServiceDiscovery<TxtRecord> {
name: String,
service_type: ServiceType,
domain: String,
Expand Down
12 changes: 6 additions & 6 deletions zeroconf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ extern crate serde;
extern crate derive_builder;
#[macro_use]
extern crate zeroconf_macros;
#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", feature = "avahi"))]
extern crate avahi_sys;
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
extern crate bonjour_sys;
Expand Down Expand Up @@ -223,7 +223,7 @@ pub mod prelude;
pub mod service;
pub mod txt_record;

#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", feature = "avahi"))]
pub mod avahi;
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub mod bonjour;
Expand All @@ -234,29 +234,29 @@ pub use service::{ServiceRegisteredCallback, ServiceRegistration};
pub use service_type::*;

/// Type alias for the platform-specific mDNS browser implementation
#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", feature = "avahi"))]
pub type MdnsBrowser = avahi::browser::AvahiMdnsBrowser;
/// Type alias for the platform-specific mDNS browser implementation
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub type MdnsBrowser = bonjour::browser::BonjourMdnsBrowser;

/// Type alias for the platform-specific mDNS service implementation
#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", feature = "avahi"))]
pub type MdnsService = avahi::service::AvahiMdnsService;
/// Type alias for the platform-specific mDNS service implementation
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub type MdnsService = bonjour::service::BonjourMdnsService;

/// Type alias for the platform-specific structure responsible for polling the mDNS event loop
#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", feature = "avahi"))]
pub type EventLoop = avahi::event_loop::AvahiEventLoop;
/// Type alias for the platform-specific structure responsible for polling the mDNS event loop
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub type EventLoop = bonjour::event_loop::BonjourEventLoop;

/// Type alias for the platform-specific structure responsible for storing and accessing TXT
/// record data
#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", feature = "avahi"))]
pub type TxtRecord = avahi::txt_record::AvahiTxtRecord;
/// Type alias for the platform-specific structure responsible for storing and accessing TXT
/// record data
Expand Down
12 changes: 8 additions & 4 deletions zeroconf/src/service.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
//! Trait definition for cross-platform service.

use crate::{EventLoop, NetworkInterface, Result, ServiceType, TxtRecord};
use crate::prelude::{TEventLoop, TTxtRecord};
use crate::{NetworkInterface, Result, ServiceType};
use std::any::Any;
use std::sync::Arc;

/// Interface for interacting with underlying mDNS service implementation registration
/// capabilities.
pub trait TMdnsService {
type EventLoop: TEventLoop;
type TxtRecord: TTxtRecord;

/// Creates a new `MdnsService` with the specified `ServiceType` (e.g. `_http._tcp`) and `port`.
fn new(service_type: ServiceType, port: u16) -> Self;

Expand Down Expand Up @@ -45,10 +49,10 @@ pub trait TMdnsService {
fn host(&self) -> Option<&str>;

/// Sets the optional `TxtRecord` to register this service with.
fn set_txt_record(&mut self, txt_record: TxtRecord);
fn set_txt_record(&mut self, txt_record: Self::TxtRecord);

/// Returns the optional `TxtRecord` to register this service with.
fn txt_record(&self) -> Option<&TxtRecord>;
fn txt_record(&self) -> Option<&Self::TxtRecord>;

/// Sets the [`ServiceRegisteredCallback`] that is invoked when the service has been
/// registered.
Expand All @@ -65,7 +69,7 @@ pub trait TMdnsService {

/// Registers and start's the service. Returns an `EventLoop` which can be called to keep
/// the service alive.
fn register(&mut self) -> Result<EventLoop>;
fn register(&mut self) -> Result<Self::EventLoop>;
}

/// Callback invoked from [`MdnsService`] once it has successfully registered.
Expand Down
8 changes: 7 additions & 1 deletion zeroconf/src/txt_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,13 @@ impl Debug for TxtRecord {
}
}

#[cfg(test)]
#[cfg(all(
test,
any(
all(target_os = "linux", feature = "avahi"),
all(target_vendor = "apple", target_vendor = "pc"),
)
))]
mod tests {
use super::*;
use crate::TxtRecord;
Expand Down