Fix event-listener gap in UdpTransport.connect() dropping late network events

Between cancelling the initial "available" subscription and attaching
the network-loss listener, no listener was attached to the broadcast
event stream for a brief window. Events landing in that gap (notably
a late SSID update, which real hardware without STA concurrency often
fires very close after "available") were silently lost since broadcast
streams don't buffer for late subscribers. Now uses one continuous
subscription for the whole connection lifetime instead.
This commit is contained in:
Constantin Leue
2026-08-06 22:23:44 +02:00
parent 7ff88c5435
commit 221c0552d5
2 changed files with 64 additions and 11 deletions
@@ -374,6 +374,42 @@ void main() {
transport.dispose();
});
test(
'a late-arriving SSID update immediately after "available" is not lost '
'(regression: connect() used to briefly detach its event listener '
'between the "available" and "network loss" subscriptions, dropping '
'any event that landed exactly in that gap - real hardware without '
'STA concurrency often fires the SSID update this close together)',
() async {
final fake = FakeMlrsNetworkController();
final transport = UdpTransport(
getHost: () async => null,
getPort: () async => 0,
getSsidPrefix: () async => 'mLRS-',
getRememberedSsid: () async => null,
rememberSsid: (ssid) async => fake.rememberedSsids.add(ssid),
networkController: fake,
);
final connectFuture = transport.connect();
await Future<void>.delayed(const Duration(milliseconds: 10));
// Android liefert die SSID bei WifiNetworkSpecifier-Netzen oft nicht
// im "available"-Ereignis selbst, sondern in einem unmittelbar
// (synchron im selben Event-Loop-Takt) nachfolgenden "ssid"-Ereignis -
// ohne SSID im ersten Ereignis nachgebildet, beide direkt
// hintereinander emittiert.
fake.emit(const MlrsNetworkAvailable());
fake.emit(const MlrsNetworkSsidUpdated('mLRS-5287 AP UDP'));
await connectFuture;
await Future<void>.delayed(const Duration(milliseconds: 10));
expect(transport.connectedSsid, 'mLRS-5287 AP UDP');
expect(fake.rememberedSsids, contains('mLRS-5287 AP UDP'));
transport.dispose();
},
);
test('connectedSsid is cleared on disconnect and network loss', () async {
final fake = FakeMlrsNetworkController();
final transport = await connectWithFake(