This commit is contained in:
Mateusz Gruszczyński
2026-09-18 12:26:48 +02:00
parent 8d96ad2d38
commit 00cbe975bb
21 changed files with 231 additions and 106 deletions
+30 -10
View File
@@ -2,13 +2,18 @@ fn normalize_local_discovery_mac(value: &str) -> String {
value.replace([':', '-'], "").trim().to_ascii_uppercase()
}
fn local_discovery_candidate(device: &Device, already_added: bool) -> LocalDiscoveryCandidate {
fn local_discovery_candidate(
device: &Device,
already_added: bool,
protocol_locked: bool,
) -> LocalDiscoveryCandidate {
LocalDiscoveryCandidate {
name: device.name.clone(),
mac: device.mac.clone(),
ip: device.ip.clone(),
port: device.port,
protocol_version: device.protocol_version,
protocol_locked,
model: device.model.clone(),
firmware: device.firmware.clone(),
already_added,
@@ -24,11 +29,16 @@ fn device_from_local_discovery(candidate: LocalDiscoveryCandidate) -> Result<Dev
.ip
.parse::<IpAddr>()
.map_err(|_| AppError::BadRequest(format!("invalid IP address for {mac}")))?;
if !matches!(candidate.protocol_version, 1 | 2) {
if candidate.protocol_version > 2 {
return Err(AppError::BadRequest(format!(
"invalid protocol version for {mac}"
)));
}
if candidate.protocol_locked && candidate.protocol_version == 0 {
return Err(AppError::BadRequest(format!(
"locked discovery protocol is missing for {mac}"
)));
}
let model = candidate.model.trim().to_string();
let fallback_model = if model.is_empty() { "GREE" } else { &model };
@@ -151,7 +161,11 @@ async fn scan_discovery(
for device in discovered {
let mac = normalize_local_discovery_mac(&device.mac);
let already_added = state.db.get_device_by_mac(&mac)?.is_some();
candidates.push(local_discovery_candidate(&device, already_added));
candidates.push(local_discovery_candidate(
&device,
already_added,
protocol_version != 0,
));
}
state.log(
@@ -188,6 +202,7 @@ async fn add_discovered_devices(
let mut skipped = Vec::new();
for candidate in request.devices {
let protocol_locked = candidate.protocol_locked;
let mut device = device_from_local_discovery(candidate)?;
let _device_guard = state.lock_device_operation(&device.id).await;
if state.db.get_device_by_mac(&device.mac)?.is_some() {
@@ -195,13 +210,17 @@ async fn add_discovered_devices(
continue;
}
match state
.providers
.local()
.client()
.bind_exact(&device, device.protocol_version)
.await
{
let client = state.providers.local().client();
let bind_result = if protocol_locked {
client.bind_exact(&device, device.protocol_version).await
} else {
// Auto discovery only provides a protocol hint. Try that generation
// first, fall back to the other one, and persist the protocol that
// actually completes binding.
client.bind(&device).await
};
match bind_result {
Ok(bound) => {
device.key = Some(bound.key);
device.protocol_version = bound.protocol_version;
@@ -217,6 +236,7 @@ async fn add_discovered_devices(
json!({
"device_id": device.id,
"protocol_version": device.protocol_version,
"protocol_locked": protocol_locked,
}),
);
}