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
|
|
@ -7,8 +7,8 @@ import '../i18n/strings.g.dart';
|
|||
import '../services/profile_cache.dart' show shortPubkey;
|
||||
import '../services/social_account_store.dart';
|
||||
import '../services/profile_store.dart';
|
||||
import '../services/social_connection.dart';
|
||||
import '../services/social_service.dart';
|
||||
import '../services/social_settings.dart';
|
||||
import 'qr_view.dart';
|
||||
import 'restart_widget.dart';
|
||||
import 'theme.dart';
|
||||
|
|
@ -19,7 +19,7 @@ import 'theme.dart';
|
|||
class ProfileScreen extends StatefulWidget {
|
||||
const ProfileScreen({
|
||||
required this.social,
|
||||
required this.settings,
|
||||
required this.connection,
|
||||
required this.profileStore,
|
||||
required this.accounts,
|
||||
this.trustNetworkEnabled = false,
|
||||
|
|
@ -27,7 +27,9 @@ class ProfileScreen extends StatefulWidget {
|
|||
});
|
||||
|
||||
final SocialService social;
|
||||
final SocialSettings settings;
|
||||
|
||||
/// The shared relay connection, for publishing your profile.
|
||||
final SocialConnection connection;
|
||||
final ProfileStore profileStore;
|
||||
final SocialAccountStore accounts;
|
||||
|
||||
|
|
@ -121,20 +123,16 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||
await widget.profileStore
|
||||
.save(name: _name.text, about: _about.text, g1: _g1.text);
|
||||
|
||||
// Best-effort publish to the network so peers see the name.
|
||||
final relays = await widget.settings.relayUrls();
|
||||
if (relays.isNotEmpty) {
|
||||
try {
|
||||
final session = await widget.social.openSession(relays);
|
||||
await session.profile.publish(
|
||||
name: _name.text.trim(),
|
||||
about: _about.text.trim(),
|
||||
g1: _g1.text.trim(),
|
||||
);
|
||||
await session.close();
|
||||
} catch (_) {
|
||||
// offline / unreachable — the local copy is saved regardless.
|
||||
}
|
||||
// Best-effort publish over the shared connection so peers see the name.
|
||||
try {
|
||||
final session = await widget.connection.session();
|
||||
await session?.profile.publish(
|
||||
name: _name.text.trim(),
|
||||
about: _about.text.trim(),
|
||||
g1: _g1.text.trim(),
|
||||
);
|
||||
} catch (_) {
|
||||
// offline / unreachable — the local copy is saved regardless.
|
||||
}
|
||||
if (!mounted) return;
|
||||
setState(() => _saving = false);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue