refactor: extract NsdManager methods

This commit is contained in:
andrekir 2023-11-18 05:50:57 -03:00
parent f29d4e2309
commit e5a20c9665
3 changed files with 72 additions and 66 deletions

View file

@ -154,9 +154,6 @@ class BTScanModel @Inject constructor(
}
fun stopScan() {
// Stop Network Service Discovery (for TCP)
networkDiscovery?.cancel()
if (scanJob != null) {
debug("stopping scan")
try {
@ -170,14 +167,9 @@ class BTScanModel @Inject constructor(
} else _spinner.value = false
}
private var networkDiscovery: Job? = null
fun startScan(context: Context?) {
_spinner.value = true
// Start Network Service Discovery (find TCP devices)
networkDiscovery = networkRepository.networkDiscoveryFlow()
.launchIn(viewModelScope)
if (context != null) startCompanionScan(context) else startClassicScan()
}

View file

@ -5,19 +5,23 @@ import android.net.Network
import android.net.NetworkRequest
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.CoroutineDispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NetworkRepository @Inject constructor(
dispatchers: CoroutineDispatchers,
processLifecycle: Lifecycle,
private val nsdManagerLazy: dagger.Lazy<NsdManager?>,
private val connectivityManager: dagger.Lazy<ConnectivityManager>,
) : Logging {
@ -43,66 +47,16 @@ class NetworkRepository @Inject constructor(
private val _resolvedList = MutableStateFlow<List<NsdServiceInfo>>(emptyList())
val resolvedList: StateFlow<List<NsdServiceInfo>> get() = _resolvedList
private val _networkDiscovery: Flow<NsdServiceInfo> = callbackFlow {
val resolveQueue = Semaphore(1)
val hostsList = mutableListOf<NsdServiceInfo>()
val discoveryListener = object : NsdManager.DiscoveryListener {
override fun onDiscoveryStarted(serviceType: String) {
debug("Service discovery started: $serviceType")
}
override fun onServiceFound(service: NsdServiceInfo) {
debug("Service discovery success: $service")
if (service.serviceName.contains(SERVICE_NAME)) {
val resolveListener = object : NsdManager.ResolveListener {
override fun onServiceResolved(service: NsdServiceInfo) {
debug("Resolve Succeeded: $service")
hostsList.add(service)
_resolvedList.value = hostsList
trySend(service)
}
override fun onResolveFailed(service: NsdServiceInfo, errorCode: Int) {
debug("Resolve failed: $service - Error code: $errorCode")
}
}
// one resolveService at a time to avoid: Error Code 3: Failure Already active
launch {
try {
resolveQueue.acquire()
nsdManagerLazy.get()?.resolveService(service, resolveListener)
} finally {
resolveQueue.release()
}
}
} else {
debug("Not our Service - Name: ${service.serviceName}, Type: ${service.serviceType}")
init {
processLifecycle.coroutineScope.launch(dispatchers.default) {
nsdManagerLazy.get()?.let { manager ->
manager.discoverServices(SERVICE_TYPE).collect { serviceList ->
_resolvedList.value = serviceList
.filter { it.serviceName == SERVICE_NAME }
.mapNotNull { manager.resolveService(it) }
}
}
override fun onServiceLost(service: NsdServiceInfo) {
debug("Service lost: $service")
}
override fun onDiscoveryStopped(serviceType: String) {
debug("Discovery stopped: $serviceType")
}
override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
debug("Start Discovery failed: Error code: $errorCode")
}
override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
debug("Stop Discovery failed: Error code: $errorCode")
}
}
nsdManagerLazy.get()
?.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
awaitClose { nsdManagerLazy.get()?.stopServiceDiscovery(discoveryListener) }
}
fun networkDiscoveryFlow(): Flow<NsdServiceInfo> {
return _networkDiscovery
}
companion object {

View file

@ -0,0 +1,60 @@
package com.geeksville.mesh.repository.network
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
internal fun NsdManager.discoverServices(
serviceType: String,
protocolType: Int = NsdManager.PROTOCOL_DNS_SD,
): Flow<List<NsdServiceInfo>> = callbackFlow {
val serviceList = mutableListOf<NsdServiceInfo>()
val discoveryListener = object : NsdManager.DiscoveryListener {
override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
cancel("Start Discovery failed: Error code: $errorCode")
}
override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
cancel("Stop Discovery failed: Error code: $errorCode")
}
override fun onDiscoveryStarted(serviceType: String) {
}
override fun onDiscoveryStopped(serviceType: String) {
close()
}
override fun onServiceFound(serviceInfo: NsdServiceInfo) {
serviceList += serviceInfo
trySend(serviceList)
}
override fun onServiceLost(serviceInfo: NsdServiceInfo) {
serviceList -= serviceInfo
trySend(serviceList)
}
}
discoverServices(serviceType, protocolType, discoveryListener)
awaitClose { stopServiceDiscovery(discoveryListener) }
}
internal suspend fun NsdManager.resolveService(
serviceInfo: NsdServiceInfo,
): NsdServiceInfo? = suspendCancellableCoroutine { continuation ->
val listener = object : NsdManager.ResolveListener {
override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
continuation.resume(null)
}
override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
continuation.resume(serviceInfo)
}
}
resolveService(serviceInfo, listener)
}