start method
Starts the transport, advertising self under appId.
Implementation
@override
Future<void> start({required NodeId self, required String appId}) async {
if (_started) throw StateError('LanTransport already started');
_started = true;
_self = self;
_serviceType = '_passnote-$appId._tcp';
// 1. WebSocket server on an ephemeral port. Remote-fed input: a request
// that fails mid-handling is dropped, never an unhandled async error.
final server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
_wsServer = server;
server.listen(_handleHttpRequest, onError: (Object _) {});
// 2. Advertise this node over mDNS. A platform that refuses multicast (a
// missing entitlement or local-network permission) must not crash the
// app: the transport stays up without discovery — the failure mode the
// platform-setup guide documents — and a [DiscoveryUnavailable] event
// tells the app why no peers will appear.
await _advertise(self, server.port);
// 3. Browse for peers immediately and on an interval. Only the mDNS
// query itself runs guarded (see [_discover]); dialing and socket
// handling keep normal error propagation, like the accepting side.
unawaited(_browse());
_discoveryTimer =
Timer.periodic(_discoveryInterval, (_) => unawaited(_browse()));
}