refactor(social): one shared relay connection per identity
Every feature (offers, messaging, trust, profile, the inbox listener) used to open its OWN RelayPool via social.openSession — several sockets to the same relays, more battery, and reconnection logic living only in the inbox listener. Add SocialConnection: ONE shared session per identity, lazily connected and reused by all. It watches connectivity — dropping the session when the network goes and reconnecting when it returns, announcing each change on a sessions stream so the inbox listener re-subscribes automatically. Callers get the session via connection.session() and never close it (the connection owns its lifecycle); recreated/disposed on an identity switch. - InboxService now consumes the shared connection (subscribes on its sessions stream) instead of owning its own socket + connectivity code. - createOffersCubit + the chat/market/profile screens use the shared connection; dead createMessagesCubit/createTrustCubit factories removed. - DI registers SocialConnection per identity; Bootstrap starts it (after the inbox subscribes); switchSocialAccount disposes + recreates it. Tests: SocialConnection lifecycle (reuse, concurrent connect, offline drop + reconnect, unreachable retry) with a fake opener + online stream; inbox test updated. nostr added as a dev_dependency for the channel fake.
This commit is contained in:
parent
e2b88b4f26
commit
bb4ee2fd89
19 changed files with 431 additions and 280 deletions
|
|
@ -18,6 +18,7 @@ import 'services/onboarding_store.dart';
|
|||
import 'services/profile_cache.dart';
|
||||
import 'services/profile_store.dart';
|
||||
import 'services/social_account_store.dart';
|
||||
import 'services/social_connection.dart';
|
||||
import 'services/social_service.dart';
|
||||
import 'services/social_settings.dart';
|
||||
import 'services/trust_referents.dart';
|
||||
|
|
@ -50,6 +51,7 @@ class TaneApp extends StatelessWidget {
|
|||
required this.onboarding,
|
||||
this.social,
|
||||
this.socialSettings,
|
||||
this.connection,
|
||||
this.location,
|
||||
this.outbox,
|
||||
this.messageStore,
|
||||
|
|
@ -69,6 +71,7 @@ class TaneApp extends StatelessWidget {
|
|||
showIntro,
|
||||
social,
|
||||
socialSettings,
|
||||
connection,
|
||||
location,
|
||||
outbox,
|
||||
messageStore,
|
||||
|
|
@ -94,6 +97,9 @@ class TaneApp extends StatelessWidget {
|
|||
final SocialService? social;
|
||||
final SocialSettings? socialSettings;
|
||||
|
||||
/// The shared relay connection (one per identity) reused by every feature.
|
||||
final SocialConnection? connection;
|
||||
|
||||
/// Optional device-location source for the market's "use my location".
|
||||
final CoarseLocationProvider? location;
|
||||
|
||||
|
|
@ -135,6 +141,7 @@ class TaneApp extends StatelessWidget {
|
|||
bool showIntro,
|
||||
SocialService? social,
|
||||
SocialSettings? socialSettings,
|
||||
SocialConnection? connection,
|
||||
CoarseLocationProvider? location,
|
||||
OfferOutbox? outbox,
|
||||
MessageStore? messageStore,
|
||||
|
|
@ -153,50 +160,49 @@ class TaneApp extends StatelessWidget {
|
|||
builder: (context, state) =>
|
||||
HomeScreen(marketEnabled: social != null),
|
||||
),
|
||||
if (social != null && socialSettings != null)
|
||||
if (social != null && socialSettings != null && connection != null)
|
||||
GoRoute(
|
||||
path: '/market',
|
||||
builder: (context, state) => MarketScreen(
|
||||
social: social,
|
||||
settings: socialSettings,
|
||||
connection: connection,
|
||||
location: location,
|
||||
outbox: outbox,
|
||||
),
|
||||
),
|
||||
if (social != null && socialSettings != null)
|
||||
if (social != null && connection != null)
|
||||
GoRoute(
|
||||
path: '/market/offer',
|
||||
builder: (context, state) {
|
||||
final offer = state.extra as Offer;
|
||||
return MarketOfferDetailScreen(
|
||||
offer: offer,
|
||||
social: social,
|
||||
settings: socialSettings,
|
||||
connection: connection,
|
||||
mine: offer.authorPubkeyHex == social.publicKeyHex,
|
||||
profileCache: profileCache,
|
||||
);
|
||||
},
|
||||
),
|
||||
if (social != null && socialSettings != null && messageStore != null)
|
||||
if (messageStore != null)
|
||||
GoRoute(
|
||||
path: '/messages',
|
||||
builder: (context, state) => ChatListScreen(
|
||||
store: messageStore,
|
||||
social: social,
|
||||
settings: socialSettings,
|
||||
connection: connection,
|
||||
profileCache: profileCache,
|
||||
inbox: inbox,
|
||||
),
|
||||
),
|
||||
if (social != null &&
|
||||
socialSettings != null &&
|
||||
connection != null &&
|
||||
profileStore != null &&
|
||||
socialAccounts != null)
|
||||
GoRoute(
|
||||
path: '/profile',
|
||||
builder: (context, state) => ProfileScreen(
|
||||
social: social,
|
||||
settings: socialSettings,
|
||||
connection: connection,
|
||||
profileStore: profileStore,
|
||||
accounts: socialAccounts,
|
||||
trustNetworkEnabled:
|
||||
|
|
@ -211,12 +217,12 @@ class TaneApp extends StatelessWidget {
|
|||
wotSettings: wotSettings,
|
||||
),
|
||||
),
|
||||
if (social != null && socialSettings != null)
|
||||
if (social != null && connection != null)
|
||||
GoRoute(
|
||||
path: '/chat/:pubkey',
|
||||
builder: (context, state) => ChatScreen(
|
||||
social: social,
|
||||
settings: socialSettings,
|
||||
connection: connection,
|
||||
peerPubkey: state.pathParameters['pubkey']!,
|
||||
messageStore: messageStore,
|
||||
profileCache: profileCache,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue