use std::{
io,
os::raw::{
c_char,
c_void,
},
pin::Pin,
task::{
Context,
Poll,
},
};
use crate::{
cstr,
ffi,
inner,
interface::Interface,
};
type CallbackStream = crate::stream::ServiceStream<inner::OwnedService, BrowseResult>;
bitflags::bitflags! {
#[derive(Default)]
pub struct BrowsedFlags: ffi::DNSServiceFlags {
const MORE_COMING = ffi::FLAGS_MORE_COMING;
const ADD = ffi::FLAGS_ADD;
}
}
#[must_use = "streams do nothing unless polled"]
pub struct Browse {
stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>,
}
impl Browse {
pin_utils::unsafe_pinned!(stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>);
}
impl futures_core::Stream for Browse {
type Item = io::Result<BrowseResult>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.stream().poll_next(cx)
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct BrowseResult {
pub flags: BrowsedFlags,
pub interface: Interface,
pub service_name: String,
pub reg_type: String,
pub domain: String,
}
impl BrowseResult {
pub fn resolve(&self) -> crate::Resolve {
crate::resolve(
self.interface,
&self.service_name,
&self.reg_type,
&self.domain,
)
}
}
unsafe extern "C" fn browse_callback(
_sd_ref: ffi::DNSServiceRef,
flags: ffi::DNSServiceFlags,
interface_index: u32,
error_code: ffi::DNSServiceErrorType,
service_name: *const c_char,
reg_type: *const c_char,
reply_domain: *const c_char,
context: *mut c_void,
) {
CallbackStream::run_callback(context, error_code, || {
let service_name = cstr::from_cstr(service_name)?;
let reg_type = cstr::from_cstr(reg_type)?;
let reply_domain = cstr::from_cstr(reply_domain)?;
Ok(BrowseResult {
flags: BrowsedFlags::from_bits_truncate(flags),
interface: Interface::from_raw(interface_index),
service_name: service_name.to_string(),
reg_type: reg_type.to_string(),
domain: reply_domain.to_string(),
})
});
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct BrowseData<'a> {
pub interface: Interface,
pub domain: Option<&'a str>,
#[doc(hidden)]
pub _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
}
impl<'a> Default for BrowseData<'a> {
fn default() -> Self {
Self {
interface: Interface::default(),
domain: None,
_non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
}
}
}
fn _browse_extended(reg_type: &str, data: BrowseData<'_>) -> io::Result<Browse> {
crate::init();
let reg_type = cstr::CStr::from(®_type)?;
let domain = cstr::NullableCStr::from(&data.domain)?;
let stream = CallbackStream::new(move |sender| {
inner::OwnedService::browse(
0, data.interface.into_raw(),
®_type,
&domain,
Some(browse_callback),
sender,
)
})
.into();
Ok(Browse { stream })
}
#[doc(alias = "DNSServiceBrowse")]
pub fn browse_extended(reg_type: &str, data: BrowseData<'_>) -> Browse {
match _browse_extended(reg_type, data) {
Ok(r) => r,
Err(e) => Browse {
stream: Err(e).into(),
},
}
}
#[doc(alias = "DNSServiceBrowse")]
pub fn browse(reg_type: &str) -> Browse {
browse_extended(reg_type, BrowseData::default())
}