v0.12.0-preety_code
This commit is contained in:
@@ -1,8 +1,17 @@
|
||||
impl GreeClient {
|
||||
/// protocol_filter: 0=auto/both, 1=ECB only, 2=GCM only.
|
||||
pub async fn discover(&self, broadcast: &str, duration: Duration, protocol_filter: u8, passes: u8) -> Result<Vec<Device>> {
|
||||
pub async fn discover(
|
||||
&self,
|
||||
broadcast: &str,
|
||||
duration: Duration,
|
||||
protocol_filter: u8,
|
||||
passes: u8,
|
||||
) -> Result<Vec<Device>> {
|
||||
let target = self.discovery_target(broadcast)?;
|
||||
let target_hint = match target { SocketAddr::V4(addr) => Some(*addr.ip()), SocketAddr::V6(_) => None };
|
||||
let target_hint = match target {
|
||||
SocketAddr::V4(addr) => Some(*addr.ip()),
|
||||
SocketAddr::V6(_) => None,
|
||||
};
|
||||
let socket = self.udp_socket(true, target_hint).await?;
|
||||
let local = socket.local_addr()?;
|
||||
let passes = passes.clamp(1, 10);
|
||||
@@ -17,7 +26,11 @@ impl GreeClient {
|
||||
);
|
||||
|
||||
let deadline = Instant::now() + duration;
|
||||
let interval = if passes > 1 { duration / passes as u32 } else { duration };
|
||||
let interval = if passes > 1 {
|
||||
duration / passes as u32
|
||||
} else {
|
||||
duration
|
||||
};
|
||||
let mut next_scan = Instant::now();
|
||||
let mut sent = 0_u8;
|
||||
let mut result = Vec::new();
|
||||
@@ -36,10 +49,14 @@ impl GreeClient {
|
||||
let wait = remaining.min(Duration::from_millis(250));
|
||||
match timeout(wait, socket.recv_from(&mut buffer)).await {
|
||||
Ok(Ok((size, source))) => {
|
||||
let Ok(value) = serde_json::from_slice::<Value>(&buffer[..size]) else { continue; };
|
||||
let Ok(value) = serde_json::from_slice::<Value>(&buffer[..size]) else {
|
||||
continue;
|
||||
};
|
||||
match self.parse_discovery(value, source) {
|
||||
Ok(Some(mut device)) => {
|
||||
if protocol_filter != 0 && device.protocol_version != protocol_filter { continue; }
|
||||
if protocol_filter != 0 && device.protocol_version != protocol_filter {
|
||||
continue;
|
||||
}
|
||||
let key = device.mac.to_ascii_lowercase();
|
||||
if seen.insert(key) {
|
||||
device.last_seen = Some(Utc::now());
|
||||
@@ -48,7 +65,9 @@ impl GreeClient {
|
||||
}
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(err) => tracing::debug!(source=%source, error=?err, "Ignoring undecodable discovery response"),
|
||||
Err(err) => {
|
||||
tracing::debug!(source=%source, error=?err, "Ignoring undecodable discovery response")
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Err(err)) => return Err(err.into()),
|
||||
@@ -69,46 +88,90 @@ impl GreeClient {
|
||||
} else {
|
||||
decrypt_v1(GENERIC_GREE_V1_KEY, pack)?
|
||||
};
|
||||
value = serde_json::from_slice::<Value>(&clear).context("invalid decrypted discovery JSON")?;
|
||||
value = serde_json::from_slice::<Value>(&clear)
|
||||
.context("invalid decrypted discovery JSON")?;
|
||||
} else if pack_value.is_object() {
|
||||
value = pack_value.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
let kind = value.get("t").and_then(Value::as_str).unwrap_or_default().to_ascii_lowercase();
|
||||
if kind != "dev" && kind != "scan" && value.get("mac").is_none() && value.get("cid").is_none() {
|
||||
let kind = value
|
||||
.get("t")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default()
|
||||
.to_ascii_lowercase();
|
||||
if kind != "dev"
|
||||
&& kind != "scan"
|
||||
&& value.get("mac").is_none()
|
||||
&& value.get("cid").is_none()
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
let mac = value.get("mac")
|
||||
let mac = value
|
||||
.get("mac")
|
||||
.or_else(|| value.get("cid"))
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default()
|
||||
.replace([':', '-'], "").to_ascii_uppercase();
|
||||
if mac.is_empty() { return Ok(None); }
|
||||
.replace([':', '-'], "")
|
||||
.to_ascii_uppercase();
|
||||
if mac.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let raw_model = value.get("model").or_else(|| value.get("series"))
|
||||
.and_then(Value::as_str).unwrap_or_default().trim().to_string();
|
||||
let model_type = value.get("ModelType")
|
||||
.and_then(|v| v.as_str().map(str::to_string).or_else(|| v.as_i64().map(|n| n.to_string())))
|
||||
let raw_model = value
|
||||
.get("model")
|
||||
.or_else(|| value.get("series"))
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
let model_type = value
|
||||
.get("ModelType")
|
||||
.and_then(|v| {
|
||||
v.as_str()
|
||||
.map(str::to_string)
|
||||
.or_else(|| v.as_i64().map(|n| n.to_string()))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let model = if !model_type.is_empty() && (raw_model.is_empty() || raw_model.eq_ignore_ascii_case("gree")) {
|
||||
let model = if !model_type.is_empty()
|
||||
&& (raw_model.is_empty() || raw_model.eq_ignore_ascii_case("gree"))
|
||||
{
|
||||
format!("GREE {model_type}")
|
||||
} else if raw_model.is_empty() {
|
||||
"GREE".to_string()
|
||||
} else {
|
||||
raw_model
|
||||
};
|
||||
let ver = value.get("ver").and_then(Value::as_str).unwrap_or_default().trim();
|
||||
let hid = value.get("hid").and_then(Value::as_str).unwrap_or_default().trim();
|
||||
let ver = value
|
||||
.get("ver")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default()
|
||||
.trim();
|
||||
let hid = value
|
||||
.get("hid")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default()
|
||||
.trim();
|
||||
let firmware = match (ver.is_empty(), hid.is_empty()) {
|
||||
(false, false) => format!("{ver} · {hid}"),
|
||||
(false, true) => ver.to_string(),
|
||||
(true, false) => hid.to_string(),
|
||||
(true, true) => String::new(),
|
||||
};
|
||||
let suffix = mac.chars().rev().take(4).collect::<String>().chars().rev().collect::<String>().to_ascii_uppercase();
|
||||
let name = value.get("name").and_then(Value::as_str)
|
||||
.map(str::trim).filter(|v| !v.is_empty())
|
||||
let suffix = mac
|
||||
.chars()
|
||||
.rev()
|
||||
.take(4)
|
||||
.collect::<String>()
|
||||
.chars()
|
||||
.rev()
|
||||
.collect::<String>()
|
||||
.to_ascii_uppercase();
|
||||
let name = value
|
||||
.get("name")
|
||||
.and_then(Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(str::to_string)
|
||||
.unwrap_or_else(|| format!("{model} {suffix}"));
|
||||
let now = Utc::now();
|
||||
@@ -117,7 +180,11 @@ impl GreeClient {
|
||||
mac,
|
||||
name,
|
||||
ip: source.ip().to_string(),
|
||||
port: if source.port() == 0 { 7000 } else { source.port() },
|
||||
port: if source.port() == 0 {
|
||||
7000
|
||||
} else {
|
||||
source.port()
|
||||
},
|
||||
protocol_version: detected_protocol,
|
||||
model,
|
||||
firmware,
|
||||
@@ -157,5 +224,4 @@ impl GreeClient {
|
||||
updated_at: now,
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user