style: rustfmt the Wake-on-LAN modules
ci / rust (push) Failing after 51s
ci / web (push) Successful in 53s
windows-host / package (push) Failing after 2m54s
apple / swift (push) Successful in 1m19s
ci / docs-site (push) Successful in 1m10s
android / android (push) Successful in 3m38s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m21s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 39s
windows / build (x86_64-pc-windows-msvc) (push) Failing after 41s
decky / build-publish (push) Successful in 13s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m11s
ci / bench (push) Successful in 4m48s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
release / apple (push) Successful in 8m47s
deb / build-publish (push) Successful in 9m26s
flatpak / build-publish (push) Successful in 4m44s
apple / screenshots (push) Successful in 5m56s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
docker / deploy-docs (push) Successful in 17s
ci / rust (push) Failing after 51s
ci / web (push) Successful in 53s
windows-host / package (push) Failing after 2m54s
apple / swift (push) Successful in 1m19s
ci / docs-site (push) Successful in 1m10s
android / android (push) Successful in 3m38s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m21s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 39s
windows / build (x86_64-pc-windows-msvc) (push) Failing after 41s
decky / build-publish (push) Successful in 13s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m11s
ci / bench (push) Successful in 4m48s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
release / apple (push) Successful in 8m47s
deb / build-publish (push) Successful in 9m26s
flatpak / build-publish (push) Successful in 4m44s
apple / screenshots (push) Successful in 5m56s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
docker / deploy-docs (push) Successful in 17s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -299,7 +299,11 @@ mod tests {
|
|||||||
mac: "aa:bb\u{1f}cc".into(),
|
mac: "aa:bb\u{1f}cc".into(),
|
||||||
};
|
};
|
||||||
let encoded = h.encode();
|
let encoded = h.encode();
|
||||||
assert_eq!(encoded.matches(FIELD_SEP).count(), 6, "exactly seven fields");
|
assert_eq!(
|
||||||
|
encoded.matches(FIELD_SEP).count(),
|
||||||
|
6,
|
||||||
|
"exactly seven fields"
|
||||||
|
);
|
||||||
assert!(!encoded.contains('\n') && !encoded.contains('\r'));
|
assert!(!encoded.contains('\n') && !encoded.contains('\r'));
|
||||||
let fields: Vec<&str> = encoded.split(FIELD_SEP).collect();
|
let fields: Vec<&str> = encoded.split(FIELD_SEP).collect();
|
||||||
assert_eq!(fields[0], "kinjected");
|
assert_eq!(fields[0], "kinjected");
|
||||||
|
|||||||
@@ -154,9 +154,11 @@ pub fn learn_mac(fp_hex: &str, addr: &str, port: u16, mac: &[String]) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut known = KnownHosts::load();
|
let mut known = KnownHosts::load();
|
||||||
let Some(h) = known.hosts.iter_mut().find(|h| {
|
let Some(h) = known
|
||||||
(!fp_hex.is_empty() && h.fp_hex == fp_hex) || (h.addr == addr && h.port == port)
|
.hosts
|
||||||
}) else {
|
.iter_mut()
|
||||||
|
.find(|h| (!fp_hex.is_empty() && h.fp_hex == fp_hex) || (h.addr == addr && h.port == port))
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if h.mac == mac {
|
if h.mac == mac {
|
||||||
|
|||||||
@@ -319,7 +319,10 @@ fn rebuild(state: &Rc<State>) {
|
|||||||
let online = adverts.values().any(|a| matches(k, a));
|
let online = adverts.values().any(|a| matches(k, a));
|
||||||
// Learn this host's wake MAC(s) from its live advert while it's online, so we can wake it
|
// Learn this host's wake MAC(s) from its live advert while it's online, so we can wake it
|
||||||
// once it sleeps and stops advertising (no-op / no disk write when unchanged).
|
// once it sleeps and stops advertising (no-op / no disk write when unchanged).
|
||||||
if let Some(a) = adverts.values().find(|a| matches(k, a) && !a.mac.is_empty()) {
|
if let Some(a) = adverts
|
||||||
|
.values()
|
||||||
|
.find(|a| matches(k, a) && !a.mac.is_empty())
|
||||||
|
{
|
||||||
crate::trust::learn_mac(&k.fp_hex, &k.addr, k.port, &a.mac);
|
crate::trust::learn_mac(&k.fp_hex, &k.addr, k.port, &a.mac);
|
||||||
}
|
}
|
||||||
let recent = most_recent.as_deref() == Some(k.fp_hex.as_str());
|
let recent = most_recent.as_deref() == Some(k.fp_hex.as_str());
|
||||||
@@ -505,7 +508,10 @@ fn saved_card(
|
|||||||
// Explicit "just wake it" (the tap-to-connect already auto-wakes an offline host).
|
// Explicit "just wake it" (the tap-to-connect already auto-wakes an offline host).
|
||||||
let mac = k.mac.clone();
|
let mac = k.mac.clone();
|
||||||
let addr = k.addr.clone();
|
let addr = k.addr.clone();
|
||||||
add("wake", Box::new(move || crate::wol::wake(&mac, addr.parse().ok())));
|
add(
|
||||||
|
"wake",
|
||||||
|
Box::new(move || crate::wol::wake(&mac, addr.parse().ok())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
overlay.insert_action_group("card", Some(&actions));
|
overlay.insert_action_group("card", Some(&actions));
|
||||||
|
|
||||||
|
|||||||
@@ -327,7 +327,8 @@ pub(crate) fn hosts_page(props: &HostsProps, cx: &mut RenderCx) -> Element {
|
|||||||
// Learn this host's wake MAC(s) from its live advert while it's online, so we can wake
|
// Learn this host's wake MAC(s) from its live advert while it's online, so we can wake
|
||||||
// it once it sleeps (no-op / no disk write when unchanged).
|
// it once it sleeps (no-op / no disk write when unchanged).
|
||||||
if let Some(a) = hosts.iter().find(|h| {
|
if let Some(a) = hosts.iter().find(|h| {
|
||||||
(h.fp_hex == k.fp_hex || (h.addr == k.addr && h.port == k.port)) && !h.mac.is_empty()
|
(h.fp_hex == k.fp_hex || (h.addr == k.addr && h.port == k.port))
|
||||||
|
&& !h.mac.is_empty()
|
||||||
}) {
|
}) {
|
||||||
crate::trust::learn_mac(&k.fp_hex, &k.addr, k.port, &a.mac);
|
crate::trust::learn_mac(&k.fp_hex, &k.addr, k.port, &a.mac);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,9 +129,11 @@ pub fn learn_mac(fp_hex: &str, addr: &str, port: u16, mac: &[String]) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut known = KnownHosts::load();
|
let mut known = KnownHosts::load();
|
||||||
let Some(h) = known.hosts.iter_mut().find(|h| {
|
let Some(h) = known
|
||||||
(!fp_hex.is_empty() && h.fp_hex == fp_hex) || (h.addr == addr && h.port == port)
|
.hosts
|
||||||
}) else {
|
.iter_mut()
|
||||||
|
.find(|h| (!fp_hex.is_empty() && h.fp_hex == fp_hex) || (h.addr == addr && h.port == port))
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if h.mac == mac {
|
if h.mac == mac {
|
||||||
|
|||||||
@@ -64,7 +64,10 @@ pub fn build_magic_packet(mac: Mac) -> [u8; 102] {
|
|||||||
/// could be opened or nothing could be sent at all.
|
/// could be opened or nothing could be sent at all.
|
||||||
pub fn send_magic_packet(macs: &[Mac], last_known_ip: Option<Ipv4Addr>) -> io::Result<()> {
|
pub fn send_magic_packet(macs: &[Mac], last_known_ip: Option<Ipv4Addr>) -> io::Result<()> {
|
||||||
if macs.is_empty() {
|
if macs.is_empty() {
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "no MAC addresses"));
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"no MAC addresses",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the target IP set: each interface's directed broadcast, the limited broadcast, and
|
// Build the target IP set: each interface's directed broadcast, the limited broadcast, and
|
||||||
@@ -100,7 +103,10 @@ pub fn send_magic_packet(macs: &[Mac], last_known_ip: Option<Ipv4Addr>) -> io::R
|
|||||||
if sent_any {
|
if sent_any {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "no magic packet could be sent"))
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
"no magic packet could be sent",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,9 +124,9 @@ fn broadcast_addrs() -> Vec<Ipv4Addr> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let if_addrs::IfAddr::V4(v4) = iface.addr {
|
if let if_addrs::IfAddr::V4(v4) = iface.addr {
|
||||||
let bcast = v4.broadcast.unwrap_or_else(|| {
|
let bcast = v4
|
||||||
Ipv4Addr::from(u32::from(v4.ip) | !u32::from(v4.netmask))
|
.broadcast
|
||||||
});
|
.unwrap_or_else(|| Ipv4Addr::from(u32::from(v4.ip) | !u32::from(v4.netmask)));
|
||||||
// Skip a degenerate 0.0.0.0 (unconfigured) and the all-ones limited broadcast we
|
// Skip a degenerate 0.0.0.0 (unconfigured) and the all-ones limited broadcast we
|
||||||
// already add unconditionally.
|
// already add unconditionally.
|
||||||
if !bcast.is_unspecified() && bcast != Ipv4Addr::BROADCAST {
|
if !bcast.is_unspecified() && bcast != Ipv4Addr::BROADCAST {
|
||||||
@@ -156,8 +162,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_mac_forms() {
|
fn parse_mac_forms() {
|
||||||
assert_eq!(parse_mac("aa:bb:cc:dd:ee:ff"), Some([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]));
|
assert_eq!(
|
||||||
assert_eq!(parse_mac("AA-BB-CC-DD-EE-FF"), Some([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]));
|
parse_mac("aa:bb:cc:dd:ee:ff"),
|
||||||
|
Some([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_mac("AA-BB-CC-DD-EE-FF"),
|
||||||
|
Some([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
|
||||||
|
);
|
||||||
assert_eq!(parse_mac("01:02:03:04:05:06"), Some([1, 2, 3, 4, 5, 6]));
|
assert_eq!(parse_mac("01:02:03:04:05:06"), Some([1, 2, 3, 4, 5, 6]));
|
||||||
assert_eq!(parse_mac("aa:bb:cc:dd:ee"), None); // too few
|
assert_eq!(parse_mac("aa:bb:cc:dd:ee"), None); // too few
|
||||||
assert_eq!(parse_mac("aa:bb:cc:dd:ee:ff:00"), None); // too many
|
assert_eq!(parse_mac("aa:bb:cc:dd:ee:ff:00"), None); // too many
|
||||||
|
|||||||
@@ -66,11 +66,17 @@ pub fn wake_macs(primary_ip: IpAddr) -> Vec<String> {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn warn_if_not_armed(primary_ip: IpAddr) {
|
pub fn warn_if_not_armed(primary_ip: IpAddr) {
|
||||||
let ifaces = if_addrs::get_if_addrs().unwrap_or_default();
|
let ifaces = if_addrs::get_if_addrs().unwrap_or_default();
|
||||||
let Some(iface) = ifaces.iter().find(|i| i.ip() == primary_ip).map(|i| i.name.clone()) else {
|
let Some(iface) = ifaces
|
||||||
|
.iter()
|
||||||
|
.find(|i| i.ip() == primary_ip)
|
||||||
|
.map(|i| i.name.clone())
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
match ethtool_wol_has_magic(&iface) {
|
match ethtool_wol_has_magic(&iface) {
|
||||||
Some(true) => tracing::info!(iface = %iface, "Wake-on-LAN armed (magic packet) on host NIC"),
|
Some(true) => {
|
||||||
|
tracing::info!(iface = %iface, "Wake-on-LAN armed (magic packet) on host NIC")
|
||||||
|
}
|
||||||
Some(false) => tracing::warn!(
|
Some(false) => tracing::warn!(
|
||||||
iface = %iface,
|
iface = %iface,
|
||||||
"Wake-on-LAN is NOT armed on this host's NIC — clients cannot wake it from sleep. \
|
"Wake-on-LAN is NOT armed on this host's NIC — clients cannot wake it from sleep. \
|
||||||
@@ -88,7 +94,10 @@ pub fn warn_if_not_armed(_primary_ip: IpAddr) {}
|
|||||||
/// (wake on MagicPacket). Returns `None` if ethtool is missing/failed or the field is absent.
|
/// (wake on MagicPacket). Returns `None` if ethtool is missing/failed or the field is absent.
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
fn ethtool_wol_has_magic(iface: &str) -> Option<bool> {
|
fn ethtool_wol_has_magic(iface: &str) -> Option<bool> {
|
||||||
let out = std::process::Command::new("ethtool").arg(iface).output().ok()?;
|
let out = std::process::Command::new("ethtool")
|
||||||
|
.arg(iface)
|
||||||
|
.output()
|
||||||
|
.ok()?;
|
||||||
if !out.status.success() {
|
if !out.status.success() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user