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(); } /// Derive subnet broadcast from an IP address (e.g., 192.168.1.100 → 192.168.1.255). static String? _subnetBroadcast(String? ip) { if (ip == null || ip.isEmpty) return null; final parts = ip.split('.'); if (parts.length != 4) return null; return '${parts[0]}.${parts[1]}.${parts[2]}.255'; } /// Send a Wake-on-LAN packet for the given MAC address. /// Broadcasts to 255.255.255.255 and subnet broadcast derived from localHost. /// Sends on ports 7 and 9 for maximum compatibility. static Future wake(String macAddress, {String? localHost}) 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; final targets = [ InternetAddress('255.255.255.255'), ]; // Add subnet broadcast derived from localHost final subnet = _subnetBroadcast(localHost); if (subnet != null) { try { targets.add(InternetAddress(subnet)); } catch (_) {} } // Send to all targets on both common WoL ports for (final addr in targets) { socket.send(packet, addr, 9); socket.send(packet, addr, 7); } // Repeat for reliability for (var i = 0; i < 3; i++) { await Future.delayed(const Duration(milliseconds: 100)); for (final addr in targets) { socket.send(packet, addr, 9); } } socket.close(); } }