Skip to content

Commit 690494b

Browse files
myleshortonclaude
andcommitted
smc: gate arc draws on origin coords + accurate event type doc
Four Copilot findings: 1. replayCurrentPeers fired before _initOrigin completed — replayed arcs drew to GlobeCoordinates(0,0) and never got corrected. Moved the replay call into _initOrigin's continuation so it runs only AFTER origin coords are known. 2. _addPeer fell back to GlobeCoordinates(0,0) when _originCoords hadn't loaded yet, so real-time +1 events arriving during the origin-lookup window could still draw to (0,0). Added a null guard: if origin isn't resolved, skip the draw — the peer is still tracked in the notifier's _peerArcs map (source of truth), and replayCurrentPeers in _initOrigin's continuation picks it up. Reordered initState: subscribe FIRST so real-time events accumulate in _peerArcs while origin is loading, then call _initOrigin which finishes by calling replayCurrentPeers. With both changes there's no window where a peer is drawn without correct origin coords. 3. debugPrint comment claimed it 'avoids bringing in the appLogger' and that 'real impl can switch to slog' — but the file already uses appLogger, and slog isn't a Dart logger. Rewrote to describe the actual rationale: avoid escalating a single malformed wire event to a user-visible error toast in debug builds; keep the listener subscribed so subsequent well-formed events still arrive. 4. lantern-core's EventTypePeerConnection doc described it as samizdat-only with a {state, source} payload. Both donor protocols now emit on this event type with the unified {state, source, timestamp} payload (peer-share's marshal was bumped in the previous round to include timestamp). Updated the doc accordingly with source-format details for both protocols. dart analyze clean; Go build clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 24abae2 commit 690494b

2 files changed

Lines changed: 35 additions & 13 deletions

File tree

lantern-core/core.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,15 @@ const (
4040
EventTypeServerLocation EventType = "server-location"
4141
EventTypeConfig EventType = "config"
4242
EventTypeCountryCode EventType = "country-code"
43-
// EventTypePeerConnection signals a samizdat peer accept/close on the
44-
// local Share My Connection inbound. Message is JSON
45-
// {"state": +1|-1, "source": "ip:port"}; consumers extract the IP for
46-
// geo-lookup or rate-limit attribution.
43+
// EventTypePeerConnection signals a peer accept/close on the local
44+
// peer-share inbound. Both donor protocols emit this event type:
45+
// samizdat-over-UPnP "Share My Connection" and broflake
46+
// "Unbounded". Message is JSON
47+
// {"state": +1|-1, "source": "...", "timestamp": <unix-millis>}.
48+
// Source is "host:port" / "[host]:port" for SmC, bare consumer IP
49+
// for Unbounded. Consumers extract the IP for geo-lookup or
50+
// rate-limit attribution; timestamp is useful for ordering when
51+
// the event-bus dispatch is async.
4752
EventTypePeerConnection EventType = "peer-connection"
4853
// EventTypePeerStatus signals a peer.Client lifecycle phase change
4954
// (mapping_port → registering → verifying → serving on the way up,

lib/features/share_my_connection/share_my_connection.dart

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,12 @@ class ShareNotifier extends Notifier<ShareState> {
468468
);
469469
}
470470
} catch (e) {
471-
// Malformed event — log via dev print to avoid bringing in the
472-
// appLogger here. Real impl can switch to slog.
471+
// Malformed event — log without bringing down the listener.
472+
// debugPrint is intentional: appLogger.error would surface as
473+
// a user-visible error toast in some debug builds, and a
474+
// single bad event from the wire shouldn't escalate that
475+
// far. The listener stays subscribed so subsequent
476+
// well-formed events still arrive.
473477
debugPrint('share-my-connection: bad peer-connection event: $e');
474478
}
475479
});
@@ -854,16 +858,18 @@ class _GlobeViewState extends ConsumerState<_GlobeView> {
854858
if (!mounted) return;
855859
_applyTheme();
856860
};
857-
_initOrigin();
858-
// Subscribe BEFORE the replay call so we don't miss any concurrent
859-
// +1 events. The broadcast stream delivers synchronously when added,
860-
// but the replay events come from inside the same notifier so order
861-
// is preserved.
861+
// Subscribe FIRST so we don't miss any real-time +1 events while
862+
// _initOrigin is in flight. _addPeer guards on _originCoords —
863+
// events that arrive before origin lookup completes are still
864+
// tracked by the notifier's _peerArcs map (the source of truth);
865+
// _initOrigin's continuation calls replayCurrentPeers to draw
866+
// them with the now-known origin coords. Without this ordering,
867+
// arcs drew to GlobeCoordinates(0,0) and never got corrected.
862868
_eventSub = ref
863869
.read(shareProvider.notifier)
864870
.connectionEvents
865871
.listen(_handleEvent);
866-
ref.read(shareProvider.notifier).replayCurrentPeers();
872+
_initOrigin();
867873
}
868874

869875
@override
@@ -897,6 +903,11 @@ class _GlobeViewState extends ConsumerState<_GlobeView> {
897903
coordinates: coords,
898904
style: PointStyle(color: _originPointColor, size: 8),
899905
));
906+
// Origin coords are now known — draw any peers that connected
907+
// before (or during) the origin lookup. _addPeer's null-guard
908+
// skipped them earlier; replayCurrentPeers re-fires +1 events
909+
// for everything in _peerArcs.
910+
ref.read(shareProvider.notifier).replayCurrentPeers();
900911
}
901912

902913
void _handleEvent(UnboundedConnectionEvent event) {
@@ -928,14 +939,20 @@ class _GlobeViewState extends ConsumerState<_GlobeView> {
928939

929940
void _addPeer(UnboundedConnectionEvent event) {
930941
if (!mounted) return;
942+
// Origin not yet resolved — skip the draw rather than render an
943+
// arc to GlobeCoordinates(0, 0). The peer is still tracked in
944+
// the notifier's _peerArcs map, and _initOrigin's continuation
945+
// calls replayCurrentPeers once origin is known so anything
946+
// skipped here gets drawn with the correct destination.
947+
if (_originCoords == null) return;
931948
final coords = _jittered(event.coordinates!, event.workerIdx);
932949
// Arc direction is censored user → uncensored peer (us). The dash
933950
// animation flows from start to end, so the visual "travel" reads
934951
// as traffic arriving at our peer to escape censorship.
935952
_globeController.addPointConnection(PointConnection(
936953
id: 'conn_${event.workerIdx}',
937954
start: coords,
938-
end: _originCoords ?? const GlobeCoordinates(0, 0),
955+
end: _originCoords!,
939956
curveScale: .6,
940957
style: PointConnectionStyle(
941958
color: _arcColor,

0 commit comments

Comments
 (0)