timeout actually works like its meant to

This commit is contained in:
Alex Janka 2024-03-23 08:32:00 +11:00
parent 7fdbb13ca4
commit c3eaf6ead6
5 changed files with 28 additions and 19 deletions

2
Cargo.lock generated
View file

@ -1143,7 +1143,7 @@ dependencies = [
[[package]] [[package]]
name = "homekit-exporter" name = "homekit-exporter"
version = "0.5.1" version = "0.5.2"
dependencies = [ dependencies = [
"clap", "clap",
"env_logger", "env_logger",

View file

@ -6,7 +6,7 @@ use ed25519_dalek::{Signer, Verifier};
use hkdf::Hkdf; use hkdf::Hkdf;
use sha2::Sha512; use sha2::Sha512;
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf, time::Duration};
use thiserror::Error; use thiserror::Error;
use x25519_dalek::{EphemeralSecret, PublicKey}; use x25519_dalek::{EphemeralSecret, PublicKey};
@ -24,6 +24,8 @@ mod homekit_http;
mod pairing_data; mod pairing_data;
mod tlv8; mod tlv8;
const METRIC_GATHER_TIMEOUT_SECS: u64 = 3;
pub fn load(pairing_data: PathBuf) -> Result<HashMap<String, PythonPairingData>, HomekitError> { pub fn load(pairing_data: PathBuf) -> Result<HashMap<String, PythonPairingData>, HomekitError> {
Ok(serde_json::from_str(&std::fs::read_to_string( Ok(serde_json::from_str(&std::fs::read_to_string(
pairing_data, pairing_data,
@ -294,7 +296,19 @@ impl DeviceConnection {
} }
pub async fn update_characteristics(&mut self) -> Result<(), HomekitError> { pub async fn update_characteristics(&mut self) -> Result<(), HomekitError> {
self.characteristics_request(true).await match tokio::time::timeout(
Duration::from_secs(METRIC_GATHER_TIMEOUT_SECS),
self.characteristics_request(true),
)
.await
{
Ok(r) => r,
Err(_) => {
log::warn!("failed to update characteristics");
self.socket = None;
Err(HomekitError::Timeout)
}
}
} }
async fn characteristics_request(&mut self, additional_data: bool) -> Result<(), HomekitError> { async fn characteristics_request(&mut self, additional_data: bool) -> Result<(), HomekitError> {
@ -385,10 +399,10 @@ pub enum HomekitError {
Utf8(#[from] std::string::FromUtf8Error), Utf8(#[from] std::string::FromUtf8Error),
#[error("device not found")] #[error("device not found")]
DeviceNotFound, DeviceNotFound,
#[error("timeout")]
Timeout(#[from] tokio::time::error::Elapsed),
#[error("discovery")] #[error("discovery")]
Discovery(#[from] DiscoveryError), Discovery(#[from] DiscoveryError),
#[error("timeout")]
Timeout,
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]

View file

@ -1,6 +1,6 @@
[package] [package]
name = "homekit-exporter" name = "homekit-exporter"
version = "0.5.1" version = "0.5.2"
edition = "2021" edition = "2021"
license = "Apache-2.0" license = "Apache-2.0"
description = "Prometheus exporter for HomeKit sensors" description = "Prometheus exporter for HomeKit sensors"

View file

@ -1,7 +1,7 @@
# Maintainer: Alex Janka <alex@alexjanka.com> # Maintainer: Alex Janka <alex@alexjanka.com>
pkgname=homekit-logger pkgname=homekit-logger
pkgver=0.5.1 pkgver=0.5.2
pkgrel=1 pkgrel=1
pkgdesc="Prometheus exporter for HomeKit sensors" pkgdesc="Prometheus exporter for HomeKit sensors"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')

View file

@ -1,6 +1,6 @@
use homekit_controller::{Data, DeviceConnection}; use homekit_controller::{Data, DeviceConnection};
use rocket::State; use rocket::State;
use std::{collections::HashMap, time::Duration}; use std::collections::HashMap;
use tokio::{sync::Mutex, task::JoinSet}; use tokio::{sync::Mutex, task::JoinSet};
use crate::MONITORED_CHARACTERISTICS; use crate::MONITORED_CHARACTERISTICS;
@ -15,8 +15,6 @@ pub fn launch(
.mount("/", routes![metrics]) .mount("/", routes![metrics])
} }
const METRIC_GATHER_TIMEOUT_SECS: u64 = 3;
#[get("/metrics")] #[get("/metrics")]
pub async fn metrics(state: &State<Mutex<HashMap<String, DeviceConnection>>>) -> Option<String> { pub async fn metrics(state: &State<Mutex<HashMap<String, DeviceConnection>>>) -> Option<String> {
let mut state = state.lock().await; let mut state = state.lock().await;
@ -27,11 +25,7 @@ pub async fn metrics(state: &State<Mutex<HashMap<String, DeviceConnection>>>) ->
let mut return_string = String::new(); let mut return_string = String::new();
let mut types_seen = Vec::new(); let mut types_seen = Vec::new();
match tokio::time::timeout(Duration::from_secs(METRIC_GATHER_TIMEOUT_SECS), connected.update_characteristics()).await{ connected.update_characteristics().await.ok()?;
Ok(r) => r.ok()?,
Err(_) => log::warn!("failed to update characteristics for {name}"),
}
for (aid, accessory) in &connected.accessories { for (aid, accessory) in &connected.accessories {
for service in accessory.services.values() { for service in accessory.services.values() {
@ -78,18 +72,19 @@ pub async fn metrics(state: &State<Mutex<HashMap<String, DeviceConnection>>>) ->
); );
} }
let mut s = String::new(); let mut types_string = String::new();
let mut values_string = String::new();
let mut shown_types = Vec::new(); let mut shown_types = Vec::new();
while let Some(Ok(Some((k, v, metrics, types)))) = set.join_next().await { while let Some(Ok(Some((k, v, metrics, types)))) = set.join_next().await {
state.insert(k, v); state.insert(k, v);
for c in types { for c in types {
if !shown_types.contains(&c) { if !shown_types.contains(&c) {
s.push_str(format!("# TYPE {} gauge\n", c).as_str()); types_string.push_str(format!("# TYPE {} gauge\n", c).as_str());
shown_types.push(c); shown_types.push(c);
} }
} }
s.push_str(&metrics); values_string.push_str(&metrics);
} }
Some(s) Some(format!("{types_string}{values_string}"))
} }