improve relay connection

master
gitea 2 months ago
parent d9a1da74fb
commit 74d82044f0

@ -836,32 +836,73 @@ class NostrService {
} }
// Attempt to connect to all added relays in parallel // Attempt to connect to all added relays in parallel
// Connections happen in the background - if they fail, relays will be auto-disabled // The connectRelay() method already maintains the connection via its internal listener
// We just need to wait for connections to be established
final connectionFutures = <Future<void>>[];
for (final relayUrl in addedRelayUrls) { for (final relayUrl in addedRelayUrls) {
try { connectionFutures.add(
// Connect in background - don't wait for it Future<void>(() async {
connectRelay(relayUrl).then((stream) {
// Connection successful - stream will be handled by existing connection logic
Logger.info('Successfully connected to NIP-05 relay: $relayUrl');
}).catchError((error) {
// Connection failed - relay will be auto-disabled by getRelays() logic
Logger.warning('Failed to connect to NIP-05 relay: $relayUrl - $error');
try { try {
setRelayEnabled(relayUrl, false); Logger.info('Connecting to NIP-05 relay: $relayUrl');
} catch (_) {
// Ignore errors // Connect to the relay - this sets up the connection and maintains it
// The stream is returned but we don't need to use it - the connection
// is maintained by the internal listener in connectRelay()
await connectRelay(relayUrl).timeout(
const Duration(seconds: 5),
onTimeout: () {
throw Exception('Connection timeout');
},
);
// Wait for connection to be confirmed
// The service marks connection as established after 500ms if no errors occur
// or when the first message is received
// We'll wait up to 2 seconds, checking every 200ms
bool connected = false;
for (int i = 0; i < 10; i++) {
await Future.delayed(const Duration(milliseconds: 200));
final relay = _relays.firstWhere(
(r) => r.url == relayUrl,
orElse: () => throw Exception('Relay not found'),
);
if (relay.isConnected) {
connected = true;
Logger.info('Successfully connected to NIP-05 relay: $relayUrl');
break;
}
}
if (!connected) {
// Connection didn't establish within timeout - disable the relay
Logger.warning('Connection not established for NIP-05 relay: $relayUrl within 2 seconds - disabling');
try {
disconnectRelay(relayUrl);
setRelayEnabled(relayUrl, false);
} catch (_) {
// Ignore errors
}
}
// Note: We don't need to maintain a subscription to the stream here
// The connectRelay() method already has a listener that maintains the connection
// The stream is stored in _messageControllers and will remain active
} catch (e) {
// Connection failed - disable the relay
Logger.warning('Failed to connect to NIP-05 relay: $relayUrl - $e');
try {
disconnectRelay(relayUrl);
setRelayEnabled(relayUrl, false);
} catch (_) {
// Ignore errors
}
} }
}); }),
} catch (e) { );
// Connection attempt failed - disable the relay
Logger.warning('Failed to connect to NIP-05 relay: $relayUrl - $e');
try {
setRelayEnabled(relayUrl, false);
} catch (_) {
// Ignore errors
}
}
} }
// Wait for all connection attempts to complete (or timeout)
await Future.wait(connectionFutures, eagerError: false);
Logger.info('Replaced ${existingRelays.length} relay(s) with $addedCount preferred relay(s) from NIP-05: $nip05 (all enabled and connecting)'); Logger.info('Replaced ${existingRelays.length} relay(s) with $addedCount preferred relay(s) from NIP-05: $nip05 (all enabled and connecting)');
return addedCount; return addedCount;

@ -5,6 +5,7 @@ import '../../core/logger.dart';
import '../../core/exceptions/session_exception.dart'; import '../../core/exceptions/session_exception.dart';
import '../../core/service_locator.dart'; import '../../core/service_locator.dart';
import '../local/local_storage_service.dart'; import '../local/local_storage_service.dart';
import '../local/models/item.dart';
import '../sync/sync_engine.dart'; import '../sync/sync_engine.dart';
import '../firebase/firebase_service.dart'; import '../firebase/firebase_service.dart';
import '../nostr/nostr_service.dart'; import '../nostr/nostr_service.dart';
@ -365,8 +366,29 @@ class SessionService {
Future<void> _clearUserData(String userId) async { Future<void> _clearUserData(String userId) async {
try { try {
// Clear all data from local storage if it's the current user's storage // Clear all data from local storage if it's the current user's storage
// But preserve app_settings (user-independent settings)
if (_currentUser?.id == userId) { if (_currentUser?.id == userId) {
// Save app_settings before clearing
Item? appSettings;
try {
appSettings = await _localStorage.getItem('app_settings');
} catch (e) {
// If we can't read it, that's okay - it might not exist
Logger.debug('Could not read app_settings before clearing: $e');
}
// Clear all data
await _localStorage.clearAllData(); await _localStorage.clearAllData();
// Restore app_settings if it existed
if (appSettings != null) {
try {
await _localStorage.insertItem(appSettings);
Logger.debug('Preserved app_settings during logout');
} catch (e) {
Logger.warning('Failed to restore app_settings after logout: $e');
}
}
} }
// Delete user-specific recipes database file // Delete user-specific recipes database file

@ -353,85 +353,91 @@ class _RelayListItem extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: Padding( child: Padding(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Column( child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Relay URL and status // Status indicator
Row( Container(
children: [ width: 10,
// Status indicator height: 10,
// Enabled means connected - if it's enabled but not connected, it should be disabled decoration: BoxDecoration(
Container( shape: BoxShape.circle,
width: 12, color: relay.isConnected && relay.isEnabled
height: 12, ? Colors.green
decoration: BoxDecoration( : Colors.grey,
shape: BoxShape.circle, ),
color: relay.isConnected && relay.isEnabled ),
? Colors.green const SizedBox(width: 8),
: Colors.grey, // URL and status text
), Expanded(
), child: Column(
const SizedBox(width: 8), crossAxisAlignment: CrossAxisAlignment.start,
Expanded( mainAxisSize: MainAxisSize.min,
child: Text( children: [
Text(
relay.url, relay.url,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13,
fontSize: 14, fontWeight: FontWeight.w500,
), ),
overflow: TextOverflow.ellipsis,
maxLines: 1,
), ),
), const SizedBox(height: 2),
], Text(
), relay.isConnected && relay.isEnabled
const SizedBox(height: 8), ? 'Connected'
// Status text : 'Disabled',
// Enabled means connected - if it's enabled but not connected, it should be disabled style: TextStyle(
Text( fontSize: 11,
relay.isConnected && relay.isEnabled color: relay.isConnected && relay.isEnabled
? 'Connected' ? Colors.green
: 'Disabled', : Colors.grey,
style: TextStyle( ),
fontSize: 12, ),
color: relay.isConnected && relay.isEnabled ],
? Colors.green
: Colors.grey,
), ),
), ),
const SizedBox(height: 12), const SizedBox(width: 8),
// Action buttons // Toggle switch
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.min,
children: [ children: [
// Toggle switch Text(
Row( relay.isEnabled ? 'ON' : 'OFF',
children: [ style: TextStyle(
Text( fontSize: 11,
relay.isEnabled ? 'On' : 'Off', fontWeight: FontWeight.w500,
style: TextStyle( color: relay.isEnabled
fontSize: 12, ? Colors.green
color: Colors.grey[600], : Colors.grey[600],
), ),
),
const SizedBox(width: 4),
Switch(
value: relay.isEnabled,
onChanged: (_) => onToggle(),
),
],
), ),
const SizedBox(width: 8), const SizedBox(width: 4),
// Remove button Transform.scale(
IconButton( scale: 0.8,
icon: const Icon(Icons.delete, size: 20), child: Switch(
color: Colors.red, value: relay.isEnabled,
tooltip: 'Remove', onChanged: (_) => onToggle(),
onPressed: onRemove, ),
), ),
], ],
), ),
const SizedBox(width: 4),
// Remove button
IconButton(
icon: const Icon(Icons.delete, size: 18),
color: Colors.red,
tooltip: 'Remove',
onPressed: onRemove,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(
minWidth: 32,
minHeight: 32,
),
),
], ],
), ),
), ),

Loading…
Cancel
Save

Powered by TurnKey Linux.