v0.8.19
This commit is contained in:
@@ -1,8 +1,27 @@
|
||||
async fn lock_poll_zone_operations(state: &AppState, device_id: &str) -> Result<Vec<tokio::sync::OwnedMutexGuard<()>>, AppError> {
|
||||
let mut zone_ids: Vec<String> = state.db.list_zones()?.into_iter()
|
||||
.filter(|zone| zone.device_id == device_id)
|
||||
.map(|zone| zone.id)
|
||||
.collect();
|
||||
zone_ids.sort();
|
||||
zone_ids.dedup();
|
||||
let mut guards = Vec::with_capacity(zone_ids.len());
|
||||
for zone_id in zone_ids {
|
||||
guards.push(state.lock_zone_operation(&zone_id).await);
|
||||
}
|
||||
Ok(guards)
|
||||
}
|
||||
|
||||
pub async fn poll_one(state: &AppState, device_id: &str) -> Result<Device, AppError> {
|
||||
// Polling can update zone ownership when it detects physical/pilot control. Acquire
|
||||
// the same zone -> device lock order used by thermostat/manual actions so those writes
|
||||
// cannot race and overwrite a fresh override or hand-back state.
|
||||
let _zone_guards = lock_poll_zone_operations(state, device_id).await?;
|
||||
let _device_guard = state.lock_device_operation(device_id).await;
|
||||
poll_one_locked(state, device_id).await
|
||||
}
|
||||
|
||||
// Caller must hold the device lock and every current zone lock associated with this device.
|
||||
async fn poll_one_locked(state: &AppState, device_id: &str) -> Result<Device, AppError> {
|
||||
let mut device = state.db.get_device(device_id)?
|
||||
.ok_or_else(|| AppError::NotFound(format!("device {device_id}")))?;
|
||||
@@ -26,12 +45,26 @@ pub(crate) async fn poll_all(state: &AppState) -> Result<()> {
|
||||
.map(|device| device.id)
|
||||
.collect();
|
||||
for device_id in device_ids {
|
||||
let _zone_guards = lock_poll_zone_operations(state, &device_id).await?;
|
||||
let _device_guard = state.lock_device_operation(&device_id).await;
|
||||
let _ = poll_one_locked(state, &device_id).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Poll all enabled devices when the caller already holds the corresponding zone and device locks.
|
||||
/// Used by configuration import so no command/poll can interleave with the replacement.
|
||||
pub(crate) async fn poll_all_locked(state: &AppState) -> Result<()> {
|
||||
let device_ids: Vec<String> = state.db.list_devices()?.into_iter()
|
||||
.filter(|device| device.enabled)
|
||||
.map(|device| device.id)
|
||||
.collect();
|
||||
for device_id in device_ids {
|
||||
let _ = poll_one_locked(state, &device_id).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn poll_device(state: &AppState, device: &mut Device) {
|
||||
if device.simulated {
|
||||
simulate_tick(device);
|
||||
|
||||
Reference in New Issue
Block a user