From 8d5c8e85c6fb4fe75ca45f58bf46524d9f7e148f Mon Sep 17 00:00:00 2001 From: Alex Janka Date: Thu, 7 Mar 2024 09:44:34 +1100 Subject: [PATCH] lil reformatting + log changes --- homekit-controller/src/discovery.rs | 74 ++++++++++++++++++ homekit-controller/src/homekit_http.rs | 3 +- homekit-controller/src/lib.rs | 91 +++------------------- homekit-exporter/packaging/service/service | 2 +- homekit-exporter/src/main.rs | 16 ++-- 5 files changed, 97 insertions(+), 89 deletions(-) create mode 100644 homekit-controller/src/discovery.rs diff --git a/homekit-controller/src/discovery.rs b/homekit-controller/src/discovery.rs new file mode 100644 index 0000000..bf2e85d --- /dev/null +++ b/homekit-controller/src/discovery.rs @@ -0,0 +1,74 @@ +use crate::homekit_http::DiscoveryError; +use futures_util::{pin_mut, StreamExt}; +use mdns::RecordKind; +use std::{collections::HashMap, sync::Arc, time::Duration}; +use tokio::sync::RwLock; + +// (id, (ip, port)) +// id - from TXT record +// ip - from A record +// port - from SRV record +pub type MdnsDiscoveredList = Arc>>; + +pub fn spawn_discover_thread() -> Result { + let discovered = Arc::new(RwLock::new(HashMap::new())); + let r_discovered = discovered.clone(); + let stream = mdns::discover::all("_hap._tcp.local", Duration::from_secs(1))?.listen(); + tokio::task::spawn(async move { + pin_mut!(stream); + loop { + while let Some(Ok(response)) = stream.next().await { + let all = response + .answers + .iter() + .chain(response.additional.iter()) + .collect::>(); + if let Some((name, id)) = all.iter().find_map(|record| { + if let RecordKind::TXT(v) = &record.kind { + if let Some(id_string) = v.iter().find(|v| v.contains("id=")) { + let id = id_string[3..].to_string(); + return Some((record.name.clone(), id)); + } + } + None + }) { + if let Some((target, port)) = all.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) = all.iter().find_map(|record| { + if record.name == target { + if let RecordKind::A(ip) = record.kind { + return Some(ip); + } + } + None + }) { + let mut connections = discovered.write().await; + if !connections.get(&id).is_some_and(|(old_ip, old_port)| { + *old_ip == ip.to_string() && *old_port == port + }) { + log::info!( + "mdns: discovered {name} - id: {id}, ip: {ip}, port: {port}" + ); + connections.insert(id, (ip.to_string(), port)); + } + } + } + } + } + tokio::time::sleep(Duration::from_secs(5 * 60)).await; + } + }); + Ok(r_discovered) +} diff --git a/homekit-controller/src/homekit_http.rs b/homekit-controller/src/homekit_http.rs index ba8363d..d4ed392 100644 --- a/homekit-controller/src/homekit_http.rs +++ b/homekit-controller/src/homekit_http.rs @@ -15,9 +15,10 @@ use tokio::{ }; use crate::{ + discovery::MdnsDiscoveredList, pairing_data::{Accessory, ServiceCharacteristic}, tlv8::TlvEncode, - ConnectionError, HomekitError, MdnsDiscoveredList, + ConnectionError, HomekitError, }; pub(super) struct AccessorySocket { diff --git a/homekit-controller/src/lib.rs b/homekit-controller/src/lib.rs index fe16a5b..a766dc5 100644 --- a/homekit-controller/src/lib.rs +++ b/homekit-controller/src/lib.rs @@ -1,26 +1,26 @@ use chacha20poly1305::{ aead::generic_array::GenericArray, AeadInPlace, ChaCha20Poly1305, KeyInit, Nonce, }; + use ed25519_dalek::{Signer, Verifier}; -use futures_util::{pin_mut, StreamExt}; use hkdf::Hkdf; -use homekit_http::DiscoveryError; -use mdns::RecordKind; + use sha2::Sha512; -use std::{collections::HashMap, path::PathBuf, sync::Arc, time::Duration}; +use std::{collections::HashMap, path::PathBuf}; use thiserror::Error; -use tlv8::{HomekitState, TlvEncode, TlvError, TlvType}; -use tokio::sync::RwLock; use x25519_dalek::{EphemeralSecret, PublicKey}; -use pairing_data::{Accessory, PythonPairingData}; - -pub use crate::pairing_data::{CharacteristicType, Data, ServiceType}; +pub use crate::{ + discovery::{spawn_discover_thread, MdnsDiscoveredList}, + pairing_data::{CharacteristicType, Data, ServiceType}, +}; use crate::{ - homekit_http::AccessorySocket, - tlv8::{decode, TlvEncodableData}, + homekit_http::{AccessorySocket, DiscoveryError}, + pairing_data::{Accessory, PythonPairingData}, + tlv8::{decode, HomekitState, TlvEncodableData, TlvEncode, TlvError, TlvType}, }; +mod discovery; mod homekit_http; mod pairing_data; mod tlv8; @@ -60,75 +60,6 @@ impl PythonPairingData { } } -// (id, (ip, port)) -// id - from TXT record -// ip - from A record -// port - from SRV record -pub type MdnsDiscoveredList = Arc>>; - -pub fn spawn_discover_thread() -> Result { - let discovered = Arc::new(RwLock::new(HashMap::new())); - let r_discovered = discovered.clone(); - let stream = mdns::discover::all("_hap._tcp.local", Duration::from_secs(1))?.listen(); - tokio::task::spawn(async move { - pin_mut!(stream); - loop { - while let Some(Ok(response)) = stream.next().await { - let all = response - .answers - .iter() - .chain(response.additional.iter()) - .collect::>(); - if let Some((name, id)) = all.iter().find_map(|record| { - if let RecordKind::TXT(v) = &record.kind { - if let Some(id_string) = v.iter().find(|v| v.contains("id=")) { - let id = id_string[3..].to_string(); - return Some((record.name.clone(), id)); - } - } - None - }) { - if let Some((target, port)) = all.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) = all.iter().find_map(|record| { - if record.name == target { - if let RecordKind::A(ip) = record.kind { - return Some(ip); - } - } - None - }) { - let mut connections = discovered.write().await; - if !connections.get(&id).is_some_and(|(old_ip, old_port)| { - *old_ip == ip.to_string() && *old_port == port - }) { - log::info!( - "mdns: discovered {name} - id: {id}, ip: {ip}, port: {port}" - ); - connections.insert(id, (ip.to_string(), port)); - } - } - } - } - } - tokio::time::sleep(Duration::from_secs(5 * 60)).await; - } - }); - Ok(r_discovered) -} - struct DevicePairingData { accessory_pairing_id: String, accessory_ip: String, diff --git a/homekit-exporter/packaging/service/service b/homekit-exporter/packaging/service/service index 114975e..e81b1d4 100644 --- a/homekit-exporter/packaging/service/service +++ b/homekit-exporter/packaging/service/service @@ -7,7 +7,7 @@ StartLimitIntervalSec=0 Type=simple Restart=always RestartSec=10s -Environment="RUST_LOG=error,warn" +Environment="RUST_LOG=error,warn,mdns=off" Environment="LOG_TIMESTAMP=false" ExecStart=/usr/bin/homekit-exporter watch diff --git a/homekit-exporter/src/main.rs b/homekit-exporter/src/main.rs index 3bb6c34..a591cdb 100644 --- a/homekit-exporter/src/main.rs +++ b/homekit-exporter/src/main.rs @@ -75,7 +75,7 @@ async fn discover() -> Result<(), mdns::Error> { async fn init(pairing_data: PathBuf) -> Result, HomekitError> { let discovered = spawn_discover_thread()?; - tokio::time::sleep(Duration::from_secs(1)).await; + tokio::time::sleep(Duration::from_secs(2)).await; if pairing_data.is_file() { let devices = homekit_controller::load(pairing_data)?; let mut connected_devices = HashMap::new(); @@ -84,13 +84,15 @@ async fn init(pairing_data: PathBuf) -> Result let connected = loop { match v.connect(&discovered).await { Ok(v) => break Some(v), - Err(e) => log::error!("error connecting to {k}: {e:#?}"), + Err(e) => { + num += 1; + if num > 10 { + log::error!("error connecting to {k}: {e:?}"); + break None; + } + } } - num += 1; - if num > 10 { - break None; - } - tokio::time::sleep(Duration::from_millis(100)).await; + tokio::time::sleep(Duration::from_millis(250)).await; }; connected_devices.insert(k, connected.ok_or(HomekitError::DeviceNotFound)?); }