fixing conneciton state after a wifi disconnect
This commit is contained in:
@@ -38,6 +38,8 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
private var subscribeDiscoverySession: SubscribeDiscoverySession? = null
|
private var subscribeDiscoverySession: SubscribeDiscoverySession? = null
|
||||||
|
|
||||||
private val peerHandles = ConcurrentHashMap<String, PeerHandle>()
|
private val peerHandles = ConcurrentHashMap<String, PeerHandle>()
|
||||||
|
private val peerRoomMapping = ConcurrentHashMap<String, String>() // PeerHandle.toString() -> roomName
|
||||||
|
private var currentRoom: String? = null
|
||||||
|
|
||||||
// Replace callbacks with Flows
|
// Replace callbacks with Flows
|
||||||
private val _messageFlow = MutableSharedFlow<Triple<String, String, String>>()
|
private val _messageFlow = MutableSharedFlow<Triple<String, String, String>>()
|
||||||
@@ -111,6 +113,7 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun startHostMode(roomName: String) {
|
fun startHostMode(roomName: String) {
|
||||||
|
currentRoom = roomName
|
||||||
val config = PublishConfig.Builder()
|
val config = PublishConfig.Builder()
|
||||||
.setServiceName(SERVICE_NAME)
|
.setServiceName(SERVICE_NAME)
|
||||||
.setServiceSpecificInfo(roomName.toByteArray())
|
.setServiceSpecificInfo(roomName.toByteArray())
|
||||||
@@ -196,6 +199,7 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
|
|
||||||
// Store peer handle for this room
|
// Store peer handle for this room
|
||||||
peerHandles[roomName] = peerHandle
|
peerHandles[roomName] = peerHandle
|
||||||
|
currentRoom = roomName
|
||||||
|
|
||||||
// Send connection request to host
|
// Send connection request to host
|
||||||
Log.d(TAG, "Sending connection request to room: $roomName")
|
Log.d(TAG, "Sending connection request to room: $roomName")
|
||||||
@@ -203,7 +207,8 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
|
|
||||||
// Update peer activity when discovered
|
// Update peer activity when discovered
|
||||||
val peerId = peerHandle.toString()
|
val peerId = peerHandle.toString()
|
||||||
lastPeerActivity[peerId] = System.currentTimeMillis()
|
peerRoomMapping[peerId] = roomName
|
||||||
|
lastPeerActivity[roomName] = System.currentTimeMillis()
|
||||||
|
|
||||||
// Wait a bit for host to prepare, then connect
|
// Wait a bit for host to prepare, then connect
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
@@ -288,8 +293,19 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
|
|
||||||
override fun onLost(network: android.net.Network) {
|
override fun onLost(network: android.net.Network) {
|
||||||
Log.d(TAG, "onLost: Network lost for room: $roomName")
|
Log.d(TAG, "onLost: Network lost for room: $roomName")
|
||||||
// Clear peer handles when connection is lost
|
// Check if we still have active keep-alive for this room
|
||||||
|
val lastActivity = lastPeerActivity[roomName]
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
|
||||||
|
if (lastActivity != null && (currentTime - lastActivity) < KEEP_ALIVE_TIMEOUT_MS) {
|
||||||
|
Log.d(TAG, "Network lost but keep-alive still active for room: $roomName - ignoring disconnect")
|
||||||
|
// Don't disconnect if keep-alive is still active
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear peer handles when connection is truly lost
|
||||||
peerHandles.remove(roomName)
|
peerHandles.remove(roomName)
|
||||||
|
lastPeerActivity.remove(roomName)
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
_connectionFlow.emit(Pair(roomName, false))
|
_connectionFlow.emit(Pair(roomName, false))
|
||||||
}
|
}
|
||||||
@@ -358,8 +374,10 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
override fun onAvailable(network: android.net.Network) {
|
override fun onAvailable(network: android.net.Network) {
|
||||||
Log.d(TAG, "Client connected")
|
Log.d(TAG, "Client connected")
|
||||||
val peerId = peerHandle.toString()
|
val peerId = peerHandle.toString()
|
||||||
peerHandles[peerId] = peerHandle
|
val roomName = currentRoom ?: "host"
|
||||||
lastPeerActivity[peerId] = System.currentTimeMillis()
|
peerHandles[roomName] = peerHandle
|
||||||
|
peerRoomMapping[peerId] = roomName
|
||||||
|
lastPeerActivity[roomName] = System.currentTimeMillis()
|
||||||
if (!isResumed) {
|
if (!isResumed) {
|
||||||
isResumed = true
|
isResumed = true
|
||||||
continuation.resume(Result.success(Unit))
|
continuation.resume(Result.success(Unit))
|
||||||
@@ -391,7 +409,11 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
try {
|
try {
|
||||||
// Update peer activity on any message
|
// Update peer activity on any message
|
||||||
val peerId = peerHandle.toString()
|
val peerId = peerHandle.toString()
|
||||||
lastPeerActivity[peerId] = System.currentTimeMillis()
|
val roomName = peerRoomMapping[peerId] ?: currentRoom
|
||||||
|
|
||||||
|
if (roomName != null) {
|
||||||
|
lastPeerActivity[roomName] = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
|
||||||
val messageStr = String(message)
|
val messageStr = String(message)
|
||||||
val parts = messageStr.split("|", limit = 3)
|
val parts = messageStr.split("|", limit = 3)
|
||||||
@@ -468,23 +490,23 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
var messagesSent = 0
|
var messagesSent = 0
|
||||||
|
|
||||||
if (publishDiscoverySession != null && peerHandles.isNotEmpty()) {
|
if (publishDiscoverySession != null && peerHandles.isNotEmpty()) {
|
||||||
peerHandles.forEach { (peerId, peerHandle) ->
|
peerHandles.forEach { (roomName, peerHandle) ->
|
||||||
try {
|
try {
|
||||||
publishDiscoverySession?.sendMessage(peerHandle, messagesSent, message)
|
publishDiscoverySession?.sendMessage(peerHandle, messagesSent, message)
|
||||||
messagesSent++
|
messagesSent++
|
||||||
Log.d(TAG, "Sent keep-alive to peer: $peerId")
|
Log.d(TAG, "Sent keep-alive to room: $roomName")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Failed to send keep-alive to peer: $peerId", e)
|
Log.e(TAG, "Failed to send keep-alive to room: $roomName", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (subscribeDiscoverySession != null && peerHandles.isNotEmpty()) {
|
} else if (subscribeDiscoverySession != null && peerHandles.isNotEmpty()) {
|
||||||
peerHandles.forEach { (peerId, peerHandle) ->
|
peerHandles.forEach { (roomName, peerHandle) ->
|
||||||
try {
|
try {
|
||||||
subscribeDiscoverySession?.sendMessage(peerHandle, messagesSent, message)
|
subscribeDiscoverySession?.sendMessage(peerHandle, messagesSent, message)
|
||||||
messagesSent++
|
messagesSent++
|
||||||
Log.d(TAG, "Sent keep-alive to peer: $peerId")
|
Log.d(TAG, "Sent keep-alive to room: $roomName")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Failed to send keep-alive to peer: $peerId", e)
|
Log.e(TAG, "Failed to send keep-alive to room: $roomName", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -493,7 +515,12 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
private fun handleKeepAlive(peerHandle: PeerHandle, shouldReply: Boolean) {
|
private fun handleKeepAlive(peerHandle: PeerHandle, shouldReply: Boolean) {
|
||||||
// Update last activity for this peer
|
// Update last activity for this peer
|
||||||
val peerId = peerHandle.toString()
|
val peerId = peerHandle.toString()
|
||||||
lastPeerActivity[peerId] = System.currentTimeMillis()
|
val roomName = peerRoomMapping[peerId] ?: currentRoom
|
||||||
|
|
||||||
|
if (roomName != null) {
|
||||||
|
lastPeerActivity[roomName] = System.currentTimeMillis()
|
||||||
|
Log.d(TAG, "Updated keep-alive activity for room: $roomName")
|
||||||
|
}
|
||||||
|
|
||||||
// Send acknowledgment if requested
|
// Send acknowledgment if requested
|
||||||
if (shouldReply) {
|
if (shouldReply) {
|
||||||
@@ -513,25 +540,26 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
|
|
||||||
private fun checkPeerActivity() {
|
private fun checkPeerActivity() {
|
||||||
val currentTime = System.currentTimeMillis()
|
val currentTime = System.currentTimeMillis()
|
||||||
val inactivePeers = mutableListOf<String>()
|
val inactiveRooms = mutableListOf<String>()
|
||||||
|
|
||||||
lastPeerActivity.forEach { (peerId, lastActivity) ->
|
lastPeerActivity.forEach { (roomName, lastActivity) ->
|
||||||
if (currentTime - lastActivity > KEEP_ALIVE_TIMEOUT_MS) {
|
if (currentTime - lastActivity > KEEP_ALIVE_TIMEOUT_MS) {
|
||||||
Log.w(TAG, "Peer $peerId inactive for too long, considering disconnected")
|
Log.w(TAG, "Room $roomName inactive for too long, considering disconnected")
|
||||||
inactivePeers.add(peerId)
|
inactiveRooms.add(roomName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove inactive peers
|
// Remove inactive rooms
|
||||||
inactivePeers.forEach { peerId ->
|
inactiveRooms.forEach { roomName ->
|
||||||
lastPeerActivity.remove(peerId)
|
lastPeerActivity.remove(roomName)
|
||||||
peerHandles.remove(peerId)
|
peerHandles.remove(roomName)
|
||||||
}
|
|
||||||
|
|
||||||
// If all peers are disconnected, emit disconnection event
|
// Clean up peer room mapping
|
||||||
if (peerHandles.isEmpty() && lastPeerActivity.isNotEmpty()) {
|
peerRoomMapping.entries.removeIf { it.value == roomName }
|
||||||
|
|
||||||
|
// Emit disconnection event for this room
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
_connectionFlow.emit(Pair("", false))
|
_connectionFlow.emit(Pair(roomName, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -547,6 +575,8 @@ class WifiAwareManager(private val context: Context) {
|
|||||||
wifiAwareSession?.close()
|
wifiAwareSession?.close()
|
||||||
wifiAwareSession = null
|
wifiAwareSession = null
|
||||||
peerHandles.clear()
|
peerHandles.clear()
|
||||||
|
peerRoomMapping.clear()
|
||||||
|
currentRoom = null
|
||||||
// Don't cancel the coroutine scope - we need it for future operations
|
// Don't cancel the coroutine scope - we need it for future operations
|
||||||
Log.d(TAG, "WifiAwareManager stopped - session cleared for fresh start")
|
Log.d(TAG, "WifiAwareManager stopped - session cleared for fresh start")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,14 +72,7 @@ class ChatRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
addMessage(message)
|
addMessage(message)
|
||||||
|
|
||||||
// If we're receiving messages, we must be connected
|
// Don't change connection state based on messages - let WifiAwareManager handle it
|
||||||
if (_connectionState.value !is ConnectionState.Connected &&
|
|
||||||
_connectionState.value !is ConnectionState.Hosting) {
|
|
||||||
when (_connectionState.value) {
|
|
||||||
is ConnectionState.Hosting -> {} // Keep hosting state
|
|
||||||
else -> _connectionState.value = ConnectionState.Connected("Active")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
android.util.Log.e("ChatRepository", "Error collecting message flow", e)
|
android.util.Log.e("ChatRepository", "Error collecting message flow", e)
|
||||||
@@ -90,12 +83,20 @@ class ChatRepository @Inject constructor(
|
|||||||
repositoryScope.launch {
|
repositoryScope.launch {
|
||||||
try {
|
try {
|
||||||
wifiAwareManager.connectionFlow.collect { (roomName, isConnected) ->
|
wifiAwareManager.connectionFlow.collect { (roomName, isConnected) ->
|
||||||
|
android.util.Log.d("ChatRepository", "Connection flow update - room: $roomName, connected: $isConnected, current state: ${_connectionState.value}")
|
||||||
|
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
currentRoomName = roomName
|
currentRoomName = roomName
|
||||||
_connectionState.value = ConnectionState.Connected(roomName)
|
// Only change to connected if we're not already hosting
|
||||||
|
if (_connectionState.value !is ConnectionState.Hosting) {
|
||||||
|
_connectionState.value = ConnectionState.Connected(roomName)
|
||||||
|
}
|
||||||
loadMessagesFromDatabase(roomName)
|
loadMessagesFromDatabase(roomName)
|
||||||
} else {
|
} else {
|
||||||
_connectionState.value = ConnectionState.Disconnected
|
// Only disconnect if the room matches our current room
|
||||||
|
if (roomName.isEmpty() || roomName == currentRoomName) {
|
||||||
|
_connectionState.value = ConnectionState.Disconnected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Call the legacy callback if set
|
// Call the legacy callback if set
|
||||||
connectionCallback?.invoke(roomName, isConnected)
|
connectionCallback?.invoke(roomName, isConnected)
|
||||||
|
|||||||
Reference in New Issue
Block a user