use log::{error, info, warn}; use mdns_sd::{ServiceDaemon, ServiceInfo}; use std::collections::HashMap; use crate::{hwinfo::PhysicalHost, local_presence::{PresenceError, SERVICE_NAME, VERSION}}; /// Advertises the agent's presence on the local network. /// /// This function is synchronous and non-blocking. It spawns a background Tokio task /// to handle the mDNS advertisement for the lifetime of the application. pub fn advertise(service_port: u16) -> Result<(), PresenceError> { let host_id = match PhysicalHost::gather() { Ok(host) => Some(host.host_uuid), Err(e) => { error!("Could not build physical host, harmony presence id will be unavailable : {e}"); None } }; let instance_name = format!("inventory-agent-{}", host_id.clone().unwrap_or("unknown".to_string())); let spawned_msg = format!("Spawned local presence advertisement task for '{instance_name}'."); tokio::spawn(async move { info!( "Local presence task started. Advertising as '{}'.", instance_name ); // The ServiceDaemon must live for the entire duration of the advertisement. // If it's dropped, the advertisement stops. let mdns = match ServiceDaemon::new() { Ok(daemon) => daemon, Err(e) => { warn!("Failed to create mDNS daemon: {}. Task shutting down.", e); return; } }; let mut props = HashMap::new(); if let Some(host_id) = host_id { props.insert("id".to_string(), host_id); } props.insert("version".to_string(), VERSION.to_string()); let service_info = ServiceInfo::new( SERVICE_NAME, &instance_name, &format!("{}.local.", instance_name), (), // Let the daemon determine the host IPs service_port, Some(props), ) .expect("ServiceInfo creation should not fail with valid inputs"); // The registration handle must also be kept alive. let _registration_handle = match mdns.register(service_info) { Ok(handle) => { info!("Service successfully registered on the local network."); handle } Err(e) => { warn!("Failed to register service: {}. Task shutting down.", e); return; } }; }); info!("{spawned_msg}"); Ok(()) }