feat(clients): Wake-on-LAN in apple/linux/windows/android/decky
apple / swift (push) Successful in 1m7s
ci / rust (push) Failing after 49s
ci / web (push) Successful in 52s
audit / cargo-audit (push) Successful in 1m14s
windows-host / package (push) Failing after 2m58s
ci / docs-site (push) Successful in 1m5s
android / android (push) Successful in 4m7s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m15s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m15s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 48s
windows / build (x86_64-pc-windows-msvc) (push) Failing after 49s
ci / bench (push) Successful in 5m5s
decky / build-publish (push) Successful in 29s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
release / apple (push) Successful in 8m30s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
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
deb / build-publish (push) Has been cancelled
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
flatpak / build-publish (push) Has been cancelled
apple / screenshots (push) Has been cancelled
docker / deploy-docs (push) Successful in 19s
apple / swift (push) Successful in 1m7s
ci / rust (push) Failing after 49s
ci / web (push) Successful in 52s
audit / cargo-audit (push) Successful in 1m14s
windows-host / package (push) Failing after 2m58s
ci / docs-site (push) Successful in 1m5s
android / android (push) Successful in 4m7s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m15s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m15s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 48s
windows / build (x86_64-pc-windows-msvc) (push) Failing after 49s
ci / bench (push) Successful in 5m5s
decky / build-publish (push) Successful in 29s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
release / apple (push) Successful in 8m30s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
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
deb / build-publish (push) Has been cancelled
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
flatpak / build-publish (push) Has been cancelled
apple / screenshots (push) Has been cancelled
docker / deploy-docs (push) Successful in 19s
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:
@@ -67,6 +67,53 @@ func withOptionalCString<R>(_ s: String?, _ body: (UnsafePointer<CChar>?) -> R)
|
||||
return s.withCString { body($0) }
|
||||
}
|
||||
|
||||
public extension PunktfunkConnection {
|
||||
/// Whether the Wake-on-LAN broadcast path is usable on this platform/build. macOS can always
|
||||
/// broadcast (its App Sandbox network entitlements cover it). iOS/tvOS need the managed
|
||||
/// `com.apple.developer.networking.multicast` entitlement, which is GATED pending Apple's
|
||||
/// approval (see `Config/Punktfunk.entitlements`) — until it's granted, sending a broadcast is
|
||||
/// blocked by the OS, so the wake path + its UI are gated off there to avoid a dead action.
|
||||
/// The MAC-learning path stays active on every platform, so flipping this on once the
|
||||
/// entitlement lands makes wake work immediately. ON APPROVAL: change `#if os(macOS)` below to
|
||||
/// `true` for iOS/tvOS too (and uncomment the entitlement).
|
||||
static var wakeOnLANAvailable: Bool {
|
||||
#if os(macOS)
|
||||
return true
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Send a Wake-on-LAN magic packet to wake a sleeping host. `macs` are the host's NIC MAC(s)
|
||||
/// (`aa:bb:cc:dd:ee:ff`, learned from its mDNS `mac` TXT while awake); malformed entries are
|
||||
/// skipped. `lastKnownIP`, when set, is additionally unicast. The core broadcasts to every
|
||||
/// interface's subnet-directed broadcast + 255.255.255.255 on ports 9/7, repeated.
|
||||
///
|
||||
/// Returns true if at least one datagram went out. Does blocking sends — call OFF the main
|
||||
/// thread. On iOS/tvOS this requires the `com.apple.developer.networking.multicast` entitlement
|
||||
/// (broadcast is otherwise blocked by the OS); macOS needs only the existing network entitlements.
|
||||
@discardableResult
|
||||
static func wakeOnLAN(macs: [String], lastKnownIP: String? = nil) -> Bool {
|
||||
var bytes: [UInt8] = []
|
||||
var count = 0
|
||||
for mac in macs {
|
||||
let parts = mac.split(separator: ":")
|
||||
guard parts.count == 6 else { continue }
|
||||
let octets = parts.compactMap { UInt8($0, radix: 16) }
|
||||
guard octets.count == 6 else { continue }
|
||||
bytes.append(contentsOf: octets)
|
||||
count += 1
|
||||
}
|
||||
guard count > 0 else { return false }
|
||||
let rc: Int32 = bytes.withUnsafeBufferPointer { buf in
|
||||
withOptionalCString(lastKnownIP) { ip in
|
||||
punktfunk_wake_on_lan(buf.baseAddress, UInt(count), ip)
|
||||
}
|
||||
}
|
||||
return rc == statusOK
|
||||
}
|
||||
}
|
||||
|
||||
public final class PunktfunkConnection {
|
||||
private var handle: OpaquePointer?
|
||||
/// Set by close() before it contends for the plane locks: the pullers see it at their
|
||||
|
||||
Reference in New Issue
Block a user