mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 06:05:21 +00:00
fix connection limits
This commit is contained in:
@@ -109,11 +109,19 @@ class BluetoothConnectionManager(
|
|||||||
}
|
}
|
||||||
// Connection caps: enforce on change
|
// Connection caps: enforce on change
|
||||||
connectionScope.launch {
|
connectionScope.launch {
|
||||||
dbg.maxConnectionsOverall.collect {
|
dbg.maxConnectionsOverall.collect { maxOverall ->
|
||||||
if (!isActive) return@collect
|
if (!isActive) return@collect
|
||||||
|
// 1. Enforce client limits (handled by tracker)
|
||||||
connectionTracker.enforceConnectionLimits()
|
connectionTracker.enforceConnectionLimits()
|
||||||
// Also enforce server side best-effort
|
|
||||||
serverManager.enforceServerLimit(dbg.maxServerConnections.value)
|
// 2. Enforce overall limit on server connections if needed
|
||||||
|
// (Tracker knows about all connections but can't disconnect servers directly)
|
||||||
|
val maxServer = dbg.maxServerConnections.value
|
||||||
|
val excessServers = connectionTracker.getExcessServerConnections(maxServer, maxOverall)
|
||||||
|
excessServers.forEach { device ->
|
||||||
|
Log.d(TAG, "Disconnecting server ${device.address} due to overall cap")
|
||||||
|
serverManager.disconnectDevice(device)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
connectionScope.launch {
|
connectionScope.launch {
|
||||||
@@ -123,9 +131,18 @@ class BluetoothConnectionManager(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
connectionScope.launch {
|
connectionScope.launch {
|
||||||
dbg.maxServerConnections.collect {
|
dbg.maxServerConnections.collect { maxServer ->
|
||||||
if (!isActive) return@collect
|
if (!isActive) return@collect
|
||||||
serverManager.enforceServerLimit(dbg.maxServerConnections.value)
|
// Enforce server specific limit
|
||||||
|
serverManager.enforceServerLimit(maxServer)
|
||||||
|
|
||||||
|
// Also check if this change puts us over the overall limit
|
||||||
|
val maxOverall = dbg.maxConnectionsOverall.value
|
||||||
|
val excessServers = connectionTracker.getExcessServerConnections(maxServer, maxOverall)
|
||||||
|
excessServers.forEach { device ->
|
||||||
|
Log.d(TAG, "Disconnecting server ${device.address} due to overall cap")
|
||||||
|
serverManager.disconnectDevice(device)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (_: Exception) { }
|
} catch (_: Exception) { }
|
||||||
|
|||||||
@@ -229,11 +229,17 @@ class BluetoothConnectionTracker(
|
|||||||
*/
|
*/
|
||||||
fun getConnectedDeviceCount(): Int = connectedDevices.size
|
fun getConnectedDeviceCount(): Int = connectedDevices.size
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if connection limit is reached
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* Check if connection limit is reached
|
* Check if connection limit is reached
|
||||||
*/
|
*/
|
||||||
fun isConnectionLimitReached(): Boolean {
|
fun isConnectionLimitReached(): Boolean {
|
||||||
return connectedDevices.size >= powerManager.getMaxConnections()
|
// Respect debug override if set
|
||||||
|
val dbg = try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance() } catch (_: Exception) { null }
|
||||||
|
val maxConnections = dbg?.maxConnectionsOverall?.value ?: powerManager.getMaxConnections()
|
||||||
|
return connectedDevices.size >= maxConnections
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,10 +250,9 @@ class BluetoothConnectionTracker(
|
|||||||
val dbg = try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance() } catch (_: Exception) { null }
|
val dbg = try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance() } catch (_: Exception) { null }
|
||||||
val maxOverall = dbg?.maxConnectionsOverall?.value ?: powerManager.getMaxConnections()
|
val maxOverall = dbg?.maxConnectionsOverall?.value ?: powerManager.getMaxConnections()
|
||||||
val maxClient = dbg?.maxClientConnections?.value ?: maxOverall
|
val maxClient = dbg?.maxClientConnections?.value ?: maxOverall
|
||||||
val maxServer = dbg?.maxServerConnections?.value ?: maxOverall
|
// Note: maxServer is handled by GattServerManager, but we need to respect overall limit here too
|
||||||
|
|
||||||
val clients = connectedDevices.values.filter { it.isClient }
|
val clients = connectedDevices.values.filter { it.isClient }
|
||||||
val servers = connectedDevices.values.filter { !it.isClient }
|
|
||||||
|
|
||||||
// Enforce client cap first (we can actively disconnect)
|
// Enforce client cap first (we can actively disconnect)
|
||||||
if (clients.size > maxClient) {
|
if (clients.size > maxClient) {
|
||||||
@@ -259,23 +264,57 @@ class BluetoothConnectionTracker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: server cap enforced in GattServerManager (we don't have server handle here)
|
// Re-check overall cap after client cleanup
|
||||||
|
|
||||||
// Enforce overall cap by disconnecting oldest client connections
|
|
||||||
if (connectedDevices.size > maxOverall) {
|
if (connectedDevices.size > maxOverall) {
|
||||||
Log.i(TAG, "Enforcing overall cap: ${connectedDevices.size} > $maxOverall")
|
Log.i(TAG, "Enforcing overall cap: ${connectedDevices.size} > $maxOverall")
|
||||||
val excess = connectedDevices.size - maxOverall
|
val excess = connectedDevices.size - maxOverall
|
||||||
val toDisconnect = connectedDevices.values
|
|
||||||
.filter { it.isClient } // only clients from here
|
// Prefer disconnecting clients first to satisfy overall cap
|
||||||
|
val clientsToDisconnect = connectedDevices.values
|
||||||
|
.filter { it.isClient }
|
||||||
.sortedBy { it.connectedAt }
|
.sortedBy { it.connectedAt }
|
||||||
.take(excess)
|
.take(excess)
|
||||||
toDisconnect.forEach { dc ->
|
|
||||||
|
clientsToDisconnect.forEach { dc ->
|
||||||
Log.d(TAG, "Disconnecting client ${dc.device.address} due to overall cap")
|
Log.d(TAG, "Disconnecting client ${dc.device.address} due to overall cap")
|
||||||
dc.gatt?.disconnect()
|
dc.gatt?.disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get excess server connections that should be disconnected to satisfy limits.
|
||||||
|
* This allows the Manager to coordinate server disconnects since Tracker doesn't control the server.
|
||||||
|
*/
|
||||||
|
fun getExcessServerConnections(maxServer: Int, maxOverall: Int): List<BluetoothDevice> {
|
||||||
|
val servers = connectedDevices.values.filter { !it.isClient }
|
||||||
|
val excessList = mutableListOf<BluetoothDevice>()
|
||||||
|
|
||||||
|
// 1. Check server specific limit
|
||||||
|
if (servers.size > maxServer) {
|
||||||
|
val excessCount = servers.size - maxServer
|
||||||
|
val toRemove = servers.sortedBy { it.connectedAt }.take(excessCount)
|
||||||
|
excessList.addAll(toRemove.map { it.device })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Check overall limit (considering we might have already removed some above)
|
||||||
|
// We need to count how many connections we will have after the above removals
|
||||||
|
val currentTotal = connectedDevices.size
|
||||||
|
val plannedRemovals = excessList.size
|
||||||
|
val projectedTotal = currentTotal - plannedRemovals
|
||||||
|
|
||||||
|
if (projectedTotal > maxOverall) {
|
||||||
|
val furtherExcess = projectedTotal - maxOverall
|
||||||
|
// We can only remove servers here. Clients are handled in enforceConnectionLimits.
|
||||||
|
// Filter out devices we already planned to remove
|
||||||
|
val remainingServers = servers.filter { s -> excessList.none { it.address == s.device.address } }
|
||||||
|
val toRemove = remainingServers.sortedBy { it.connectedAt }.take(furtherExcess)
|
||||||
|
excessList.addAll(toRemove.map { it.device })
|
||||||
|
}
|
||||||
|
|
||||||
|
return excessList
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up a specific device connection
|
* Clean up a specific device connection
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -49,16 +49,29 @@ class BluetoothGattServerManager(
|
|||||||
fun enforceServerLimit(maxServer: Int) {
|
fun enforceServerLimit(maxServer: Int) {
|
||||||
if (maxServer <= 0) return
|
if (maxServer <= 0) return
|
||||||
try {
|
try {
|
||||||
val subs = connectionTracker.getSubscribedDevices()
|
// Use connection tracker to get actual connected server devices
|
||||||
if (subs.size > maxServer) {
|
val servers = connectionTracker.getConnectedDevices().values.filter { !it.isClient }
|
||||||
val excess = subs.size - maxServer
|
if (servers.size > maxServer) {
|
||||||
subs.take(excess).forEach { d ->
|
val excess = servers.size - maxServer
|
||||||
try { gattServer?.cancelConnection(d) } catch (_: Exception) { }
|
// Disconnect oldest
|
||||||
|
servers.sortedBy { it.connectedAt }.take(excess).forEach { d ->
|
||||||
|
try { gattServer?.cancelConnection(d.device) } catch (_: Exception) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (_: Exception) { }
|
} catch (_: Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect a specific device (used by ConnectionManager to enforce overall limits)
|
||||||
|
*/
|
||||||
|
fun disconnectDevice(device: BluetoothDevice) {
|
||||||
|
try {
|
||||||
|
gattServer?.cancelConnection(device)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Error disconnecting device ${device.address}: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start GATT server
|
* Start GATT server
|
||||||
*/
|
*/
|
||||||
@@ -122,9 +135,10 @@ class BluetoothGattServerManager(
|
|||||||
|
|
||||||
// Try to cancel any active connections explicitly before closing
|
// Try to cancel any active connections explicitly before closing
|
||||||
try {
|
try {
|
||||||
val devices = connectionTracker.getSubscribedDevices()
|
// Disconnect ALL server connections
|
||||||
devices.forEach { d ->
|
val servers = connectionTracker.getConnectedDevices().values.filter { !it.isClient }
|
||||||
try { gattServer?.cancelConnection(d) } catch (_: Exception) { }
|
servers.forEach { d ->
|
||||||
|
try { gattServer?.cancelConnection(d.device) } catch (_: Exception) { }
|
||||||
}
|
}
|
||||||
} catch (_: Exception) { }
|
} catch (_: Exception) { }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user