From 174a2bc76770e03e1fb450e737a879ef2a67e1a7 Mon Sep 17 00:00:00 2001 From: Strycher Date: Wed, 24 Jun 2026 14:43:13 -0400 Subject: [PATCH] feat(#108): log broker-pool fetch lifecycle to the shared file log getBrokers logs request-sent, header count, and completed-with-N-brokers-in-Xms or failed-after-Xms (frames + expected count) via FileLogService. A tester Share-logs capture then shows in plain text whether the broker pool load succeeds, stalls, or times out - which the raw BLE frames cannot reveal. Behaviour unchanged (parse-once refactor; all 13 service tests green). Co-Authored-By: Claude Opus 4.8 --- lib/services/observer_config_service.dart | 32 +++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/services/observer_config_service.dart b/lib/services/observer_config_service.dart index 7025481..35ed00f 100644 --- a/lib/services/observer_config_service.dart +++ b/lib/services/observer_config_service.dart @@ -14,6 +14,7 @@ import 'package:flutter/foundation.dart'; import '../connector/meshcore_connector.dart'; import '../connector/observer_config_client.dart'; import '../models/observer_config.dart'; +import 'file_log_service.dart'; class ObserverConfigService extends ChangeNotifier { ObserverConfigService(this._connector); @@ -203,14 +204,23 @@ class ObserverConfigService extends ChangeNotifier { return BrokerConfig.fromWireFields(slot, kv); } + void _logBroker(String msg) => FileLogService.instance.write( + '${DateTime.now().toIso8601String()} [INFO/Broker] $msg', + ); + /// Read the broker pool (paginated START → KV → END). Null on a stall or /// error. The completion deadline is an INACTIVITY watchdog re-armed on every /// frame — a large pool streams field-by-field and outlasts any single fixed /// deadline, so only a genuine stall (no frame for [timeout]) fails (#103). + /// The fetch lifecycle is logged to the shared file log (#108) so a tester's + /// Share-logs capture shows in plain text where a pool load succeeds or fails. Future?> getBrokers() { return _serialized(() async { + final started = DateTime.now(); final decoder = BrokerListDecoder(); final completer = Completer>(); + var frames = 0; + int? expected; Timer? idle; void armIdle() { idle?.cancel(); @@ -226,14 +236,32 @@ class ObserverConfigService extends ChangeNotifier { final sub = _connector.receivedFrames.listen((f) { if (f.isEmpty || f[0] != ObserverConfigClient.respConfig) return; armIdle(); // re-arm: a steadily-streaming dump must never time out. - final list = decoder.add(ObserverConfigClient.parse(f)); + final r = ObserverConfigClient.parse(f); + if (r is ConfigBrokersStart) { + expected = r.count; + _logBroker('pool GET: header — ${r.count} brokers'); + } + frames++; + final list = decoder.add(r); if (list != null && !completer.isCompleted) completer.complete(list); }); try { await _connector.sendFrame(ObserverConfigClient.buildBrokers()); + _logBroker('pool GET: request sent'); armIdle(); // initial deadline: if the device never replies at all. - return await completer.future; + final list = await completer.future; + _logBroker( + 'pool GET: COMPLETED ${list.length} brokers ' + '(header said ${expected ?? "?"}) in ' + '${DateTime.now().difference(started).inMilliseconds}ms, $frames frames', + ); + return list; } catch (e) { + _logBroker( + 'pool GET: FAILED after ' + '${DateTime.now().difference(started).inMilliseconds}ms ' + '($frames frames, header said ${expected ?? "?"}) — $e', + ); _setError('broker list failed: $e'); return null; } finally {