Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions app/src/main/java/com/bitchat/android/nostr/NostrGeohashService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ class NostrGeohashService(
coroutineScope.launch {
val nostrRelayManager = NostrRelayManager.getInstance(application)

// Set up network error callback to display system messages
NostrRelayManager.setNetworkErrorCallback { errorMessage ->
// Display network error as a system message in chat
val systemMessage = BitchatMessage(
sender = "system",
content = errorMessage,
timestamp = Date(),
isRelay = false
)
messageManager.addMessage(systemMessage)
}

// Connect to relays
nostrRelayManager.connect()

Expand Down Expand Up @@ -153,6 +165,9 @@ class NostrGeohashService(

// 2) Clear all subscription tracking and caches
relayManager.clearAllSubscriptions()

// Clear network error callback
NostrRelayManager.clearNetworkErrorCallback()

// 3) Clear Nostr identity (npub/private) and geohash identity cache/seed
try {
Expand Down Expand Up @@ -206,6 +221,27 @@ class NostrGeohashService(
}
}

/**
* Clean up the service and release resources
* Should be called when the service is no longer needed
*/
fun cleanup() {
try {
// Clear the network error callback
NostrRelayManager.clearNetworkErrorCallback()

// Cancel any running jobs
geohashSamplingJob?.cancel()
geohashSamplingJob = null
geoParticipantsTimer?.cancel()
geoParticipantsTimer = null

Log.d(TAG, "NostrGeohashService cleaned up")
} catch (e: Exception) {
Log.e(TAG, "Error during cleanup: ${e.message}")
}
}

/**
* Initialize location channel state
*/
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/com/bitchat/android/nostr/NostrRelayManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,39 @@ class NostrRelayManager private constructor() {
val shared = NostrRelayManager()

private const val TAG = "NostrRelayManager"
private const val NETWORK_ERROR_MESSAGE = "Network unreachable. Please ensure the device is connected and has all necessary permissions."

// Network error callback for reporting failures to UI
@Volatile
private var networkErrorCallback: ((String) -> Unit)? = null
@Volatile
private var hasReportedNetworkError = false

/**
* Set callback for network error reporting
* Throws IllegalStateException if a callback is already set
*/
fun setNetworkErrorCallback(callback: (String) -> Unit) {
if (networkErrorCallback != null) {
throw IllegalStateException("Network error callback already set. Only one service instance should be active.")
}
networkErrorCallback = callback
}

/**
* Clear the network error callback (should be called when service is destroyed)
*/
fun clearNetworkErrorCallback() {
networkErrorCallback = null
hasReportedNetworkError = false
}

/**
* Reset network error flag (e.g., when network comes back)
*/
fun resetNetworkErrorFlag() {
hasReportedNetworkError = false
}

/**
* Get instance for Android compatibility (context-aware calls)
Expand Down Expand Up @@ -644,8 +677,18 @@ class NostrRelayManager private constructor() {
val relay = relaysList.find { it.url == relayUrl }
relay?.messagesSent = (relay?.messagesSent ?: 0) + 1
updateRelaysList()
// Reset error flag on successful send
hasReportedNetworkError = false
} else {
Log.e(TAG, "❌ Failed to send event to $relayUrl: WebSocket send failed")

// Check if all relays are disconnected (likely network issue)
if (connections.isEmpty() || relaysList.none { it.isConnected }) {
if (!hasReportedNetworkError) {
hasReportedNetworkError = true
networkErrorCallback?.invoke(NETWORK_ERROR_MESSAGE)
}
}
}
} catch (e: Exception) {
Log.e(TAG, "❌ Failed to send event to $relayUrl: ${e.message}")
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/bitchat/android/ui/ChatViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ class ChatViewModel(

override fun onCleared() {
super.onCleared()
// Clean up NostrGeohashService
nostrGeohashService.cleanup()
// Note: Mesh service lifecycle is now managed by MainActivity
}

Expand Down