feat(clients): Wake-on-LAN in apple/linux/windows/android/decky
Each client learns a host's MAC from the mDNS `mac` TXT while it's awake, persists it on the saved-host record, and — when reconnecting to an offline host — sends a magic packet before connecting, plus an explicit "Wake host" action. Apple wraps the C-ABI; linux/windows call the core fn directly (linux also gains a --wake CLI mode); android via a new nativeWakeOnLan JNI export (the mDNS browse record gains a 7th mac field); decky shells out to the linux client's --wake before launching the stream. iOS/tvOS need the managed com.apple.developer.networking.multicast entitlement (pending Apple approval), so the wake path + UI are gated off via PunktfunkConnection.wakeOnLANAvailable and the entitlement is commented out — keeping iOS/tvOS releasable. MAC-learning stays active on every platform so it lights up the moment it's ungated. macOS works today. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,11 @@ pub struct KnownHost {
|
||||
/// most-recent card with the accent bar. `default` so pre-existing stores load.
|
||||
#[serde(default)]
|
||||
pub last_used: Option<u64>,
|
||||
/// Wake-on-LAN MAC(s) (`aa:bb:cc:dd:ee:ff`) learned from the host's mDNS `mac` TXT while it
|
||||
/// was online, so we can wake it once it sleeps and stops advertising. `default` so
|
||||
/// pre-existing stores load; empty until first learned.
|
||||
#[serde(default)]
|
||||
pub mac: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
@@ -115,6 +120,10 @@ impl KnownHosts {
|
||||
if entry.last_used.is_some() {
|
||||
h.last_used = entry.last_used;
|
||||
}
|
||||
// Likewise a trust-decision upsert (which carries no MAC) must not wipe learned MACs.
|
||||
if !entry.mac.is_empty() {
|
||||
h.mac = entry.mac;
|
||||
}
|
||||
} else {
|
||||
self.hosts.push(entry);
|
||||
}
|
||||
@@ -132,10 +141,31 @@ pub fn persist_host(name: &str, addr: &str, port: u16, fp_hex: &str, paired: boo
|
||||
fp_hex: fp_hex.to_string(),
|
||||
paired,
|
||||
last_used: None,
|
||||
mac: Vec::new(),
|
||||
});
|
||||
let _ = known.save();
|
||||
}
|
||||
|
||||
/// Learn/refresh a saved host's Wake-on-LAN MAC(s) from its live advert (called while the host
|
||||
/// is online, matched by fingerprint or address). No-op — and no disk write — when unchanged, so
|
||||
/// the hosts page can call it on every discovery tick without churning the store.
|
||||
pub fn learn_mac(fp_hex: &str, addr: &str, port: u16, mac: &[String]) {
|
||||
if mac.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut known = KnownHosts::load();
|
||||
let Some(h) = known.hosts.iter_mut().find(|h| {
|
||||
(!fp_hex.is_empty() && h.fp_hex == fp_hex) || (h.addr == addr && h.port == port)
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
if h.mac == mac {
|
||||
return;
|
||||
}
|
||||
h.mac = mac.to_vec();
|
||||
let _ = known.save();
|
||||
}
|
||||
|
||||
/// Stamp "now" as this host's last successful connect (drives the hosts page's
|
||||
/// most-recent accent). No-op when the fingerprint isn't stored.
|
||||
pub fn touch_last_used(fp_hex: &str) {
|
||||
|
||||
Reference in New Issue
Block a user