its at least better lol
This commit is contained in:
parent
2104a2f0b0
commit
43c76585bc
966
Cargo.lock
generated
966
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -19,6 +19,7 @@ hex = { version = "0.4", features = ["serde"] }
|
|||
http = "1.0"
|
||||
httparse = "1.8"
|
||||
tokio = { version = "1.36", features = ["net"] }
|
||||
zeroconf = "0.14"
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
mdns = "3.0.0"
|
||||
futures-util = "0.3.30"
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, RwLock},
|
||||
time::Duration,
|
||||
};
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
use chacha20poly1305::{
|
||||
aead::generic_array::GenericArray, AeadInPlace, ChaCha20Poly1305, KeyInit, Nonce,
|
||||
};
|
||||
use futures_util::{pin_mut, StreamExt};
|
||||
use http::{Method, Request};
|
||||
use mdns::RecordKind;
|
||||
use thiserror::Error;
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::TcpStream,
|
||||
};
|
||||
use zeroconf::{
|
||||
browser::TMdnsBrowser, event_loop::TEventLoop, txt_record::TTxtRecord, MdnsBrowser,
|
||||
ServiceDiscovery, ServiceType,
|
||||
time::timeout,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -49,46 +44,72 @@ impl SocketEncryption {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn discover(duration_seconds: u64) -> Result<Vec<ServiceDiscovery>, DiscoveryError> {
|
||||
let service_type = ServiceType::new("hap", "tcp")?;
|
||||
let mut browser = MdnsBrowser::new(service_type);
|
||||
const SERVICE_NAME: &str = "_hap._tcp.local";
|
||||
|
||||
let discovered: Arc<RwLock<Vec<ServiceDiscovery>>> = Arc::new(RwLock::new(Vec::new()));
|
||||
let d2 = discovered.clone();
|
||||
pub async fn discover(
|
||||
duration_seconds: u64,
|
||||
pairing_id: &str,
|
||||
) -> Result<(String, u16), DiscoveryError> {
|
||||
let stream = mdns::discover::all(SERVICE_NAME, Duration::from_secs(1))?.listen();
|
||||
|
||||
browser.set_service_discovered_callback(Box::new(move |r, _| {
|
||||
if let Ok(r) = r {
|
||||
discovered.write().unwrap().push(r)
|
||||
pin_mut!(stream);
|
||||
while let Ok(Some(Ok(response))) =
|
||||
timeout(Duration::from_secs(duration_seconds), stream.next()).await
|
||||
{
|
||||
if let Some(name) = response.additional.iter().find_map(|record| {
|
||||
if let RecordKind::TXT(v) = &record.kind {
|
||||
if v.contains(&format!("id={pairing_id}")) {
|
||||
return Some(record.name.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}) {
|
||||
log::info!("got name {name}");
|
||||
if let Some((target, port)) = response.additional.iter().find_map(|record| {
|
||||
if record.name == name {
|
||||
if let RecordKind::SRV {
|
||||
priority: _,
|
||||
weight: _,
|
||||
port,
|
||||
target,
|
||||
} = &record.kind
|
||||
{
|
||||
return Some((target.clone(), *port));
|
||||
}
|
||||
}
|
||||
None
|
||||
}) {
|
||||
if let Some(ip) = response.additional.iter().find_map(|record| {
|
||||
if record.name == target {
|
||||
if let RecordKind::A(ip) = record.kind {
|
||||
return Some(ip);
|
||||
}
|
||||
}
|
||||
None
|
||||
}) {
|
||||
return Ok((ip.to_string(), port));
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
let event_loop = browser.browse_services()?;
|
||||
event_loop.poll(Duration::from_secs(duration_seconds))?;
|
||||
// if let Some(addr) = addr {
|
||||
// println!("found cast device at {}", addr);
|
||||
// } else {
|
||||
// println!("cast device does not advertise address");
|
||||
// }
|
||||
}
|
||||
|
||||
let result = d2.read().unwrap().clone();
|
||||
Ok(result)
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn reconnect(pairing_id: &str) -> Result<TcpStream, HomekitError> {
|
||||
log::warn!("error connecting to device...");
|
||||
log::warn!("trying to find accessory ip/port via bonjour/mdns...");
|
||||
let discovered = discover(20).await?;
|
||||
if let Some((hostname, port)) = discovered
|
||||
.iter()
|
||||
.find(|d| {
|
||||
d.txt()
|
||||
.as_ref()
|
||||
.map(|t| t.get("id"))
|
||||
.is_some_and(|txt| txt.is_some_and(|id| id == pairing_id))
|
||||
})
|
||||
.map(|d| (d.host_name(), d.port()))
|
||||
{
|
||||
let socket = TcpStream::connect(format!("{hostname}:{port}")).await?;
|
||||
log::warn!("trying to find {pairing_id}'s ip/port via bonjour/mdns...");
|
||||
let (hostname, port) = discover(20, pairing_id).await?;
|
||||
log::info!("successfully found device at {hostname}:{port}");
|
||||
let socket = TcpStream::connect(format!("{hostname}:{port}")).await?;
|
||||
log::info!(" ...and connected!");
|
||||
Ok(socket)
|
||||
} else {
|
||||
Err(HomekitError::DeviceNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
impl AccessorySocket {
|
||||
|
@ -351,6 +372,6 @@ impl AccessorySocket {
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DiscoveryError {
|
||||
#[error("zeroconf")]
|
||||
Zeroconf(#[from] zeroconf::error::Error),
|
||||
#[error("mdns")]
|
||||
Mdns(#[from] mdns::Error),
|
||||
}
|
||||
|
|
|
@ -332,6 +332,8 @@ pub enum HomekitError {
|
|||
Discovery(#[from] DiscoveryError),
|
||||
#[error("device not found")]
|
||||
DeviceNotFound,
|
||||
#[error("timeout")]
|
||||
Timeout(#[from] tokio::time::error::Elapsed),
|
||||
}
|
||||
|
||||
impl From<TlvError> for HomekitError {
|
||||
|
|
|
@ -36,9 +36,12 @@ pub async fn metrics(state: &State<Mutex<HashMap<String, ConnectedDevice>>>) ->
|
|||
}
|
||||
s.push_str(
|
||||
format!(
|
||||
"{}{{accessory=\"{}.{}.{}\"}} {}\n",
|
||||
"{}{{hub=\"{}\",accessory=\"{}.{}\",service=\"{}.{}.{}\"}} {}\n",
|
||||
characteristic.characteristic_type,
|
||||
name,
|
||||
name,
|
||||
aid,
|
||||
name,
|
||||
aid,
|
||||
cid,
|
||||
match value {
|
||||
|
|
Loading…
Reference in a new issue