import 'dart:io'; import 'dart:typed_data'; /// Wake-on-LAN magic packet sender. class WolService { WolService._(); /// Parse a MAC address string (colon or dash separated) to bytes. static List? _parseMac(String mac) { final cleaned = mac.replaceAll(RegExp(r'[:\-]'), ''); if (cleaned.length != 12) return null; final bytes = []; for (var i = 0; i < 12; i += 2) { final byte = int.tryParse(cleaned.substring(i, i + 2), radix: 16); if (byte == null) return null; bytes.add(byte); } return bytes; } /// Build the magic packet: 6x 0xFF followed by MAC address repeated 16 times. static Uint8List _buildPacket(List macBytes) { final packet = BytesBuilder(); // 6 bytes of 0xFF for (var i = 0; i < 6; i++) { packet.addByte(0xFF); } // MAC address repeated 16 times for (var i = 0; i < 16; i++) { packet.add(macBytes); } return packet.toBytes(); } /// Send a Wake-on-LAN packet for the given MAC address. /// Broadcasts to 255.255.255.255:9 and optionally to a subnet broadcast. static Future wake(String macAddress, {String? subnetBroadcast}) async { final macBytes = _parseMac(macAddress); if (macBytes == null) { throw ArgumentError('Invalid MAC address: $macAddress'); } final packet = _buildPacket(macBytes); final socket = await RawDatagramSocket.bind( InternetAddress.anyIPv4, 0, ); socket.broadcastEnabled = true; // Send to broadcast address final broadcastAddr = InternetAddress('255.255.255.255'); socket.send(packet, broadcastAddr, 9); // Also send to subnet broadcast if provided if (subnetBroadcast != null && subnetBroadcast.isNotEmpty) { try { final subnetAddr = InternetAddress(subnetBroadcast); socket.send(packet, subnetAddr, 9); } catch (_) { // Ignore invalid subnet broadcast address } } // Send a few extra packets for reliability await Future.delayed(const Duration(milliseconds: 100)); socket.send(packet, broadcastAddr, 9); await Future.delayed(const Duration(milliseconds: 100)); socket.send(packet, broadcastAddr, 9); socket.close(); } }