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
|
|
@ -10,8 +10,8 @@ import '../di/injector.dart';
|
|||
import '../i18n/strings.g.dart';
|
||||
import '../services/message_store.dart';
|
||||
import '../services/profile_cache.dart';
|
||||
import '../services/social_connection.dart';
|
||||
import '../services/social_service.dart';
|
||||
import '../services/social_settings.dart';
|
||||
import '../services/trust_referents.dart';
|
||||
import '../services/unread_service.dart';
|
||||
import '../services/wot_settings.dart';
|
||||
|
|
@ -25,7 +25,7 @@ import 'theme.dart';
|
|||
class ChatScreen extends StatefulWidget {
|
||||
const ChatScreen({
|
||||
required this.social,
|
||||
required this.settings,
|
||||
required this.connection,
|
||||
required this.peerPubkey,
|
||||
this.messageStore,
|
||||
this.profileCache,
|
||||
|
|
@ -35,7 +35,9 @@ class ChatScreen extends StatefulWidget {
|
|||
});
|
||||
|
||||
final SocialService social;
|
||||
final SocialSettings settings;
|
||||
|
||||
/// The shared relay connection (one per identity), carrying messaging + trust.
|
||||
final SocialConnection connection;
|
||||
final String peerPubkey;
|
||||
|
||||
/// Optional persistence for chat history (keystore-backed); null in tests.
|
||||
|
|
@ -53,7 +55,6 @@ class ChatScreen extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _ChatScreenState extends State<ChatScreen> {
|
||||
SocialSession? _session;
|
||||
MessagesCubit? _messages;
|
||||
TrustCubit? _trust;
|
||||
bool _loading = true;
|
||||
|
|
@ -79,25 +80,14 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
}
|
||||
|
||||
Future<void> _init() async {
|
||||
// One session for this chat carries both messaging and trust (the shared-
|
||||
// connection shape). Offline (no relays / unreachable) → null transports.
|
||||
final relays = await widget.settings.relayUrls();
|
||||
SocialSession? session;
|
||||
if (relays.isNotEmpty) {
|
||||
try {
|
||||
session = await widget.social.openSession(relays);
|
||||
} catch (_) {
|
||||
session = null;
|
||||
}
|
||||
}
|
||||
// The shared connection carries both messaging and trust. Offline (not
|
||||
// connected / unreachable) → null transports and the screen degrades.
|
||||
final session = await widget.connection.session();
|
||||
final cachedName = await widget.profileCache?.name(widget.peerPubkey);
|
||||
final referents = await widget.trustReferents?.all() ?? const <String>{};
|
||||
final wotParams =
|
||||
await widget.wotSettings?.params() ?? WotParams.duniter;
|
||||
if (!mounted) {
|
||||
await session?.close();
|
||||
return;
|
||||
}
|
||||
if (!mounted) return; // shared session is owned by the connection, not us
|
||||
final self = widget.social.publicKeyHex;
|
||||
final messages = MessagesCubit(
|
||||
session?.messages,
|
||||
|
|
@ -114,7 +104,6 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
);
|
||||
unawaited(trust.load());
|
||||
setState(() {
|
||||
_session = session;
|
||||
_messages = messages;
|
||||
_trust = trust;
|
||||
_peerName = cachedName;
|
||||
|
|
@ -184,7 +173,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
unawaited(_unread?.markRead(widget.peerPubkey));
|
||||
_messages?.close();
|
||||
_trust?.close();
|
||||
_session?.close();
|
||||
// The session belongs to the shared connection — don't close it here.
|
||||
_input.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue