From e5a20c96654e246fe041d5236e2b5eb3a498d0cb Mon Sep 17 00:00:00 2001 From: andrekir Date: Sat, 18 Nov 2023 05:50:57 -0300 Subject: [PATCH] refactor: extract NsdManager methods --- .../com/geeksville/mesh/model/BTScanModel.kt | 8 --- .../repository/network/NetworkRepository.kt | 70 ++++--------------- .../mesh/repository/network/NsdManager.kt | 60 ++++++++++++++++ 3 files changed, 72 insertions(+), 66 deletions(-) create mode 100644 app/src/main/java/com/geeksville/mesh/repository/network/NsdManager.kt diff --git a/app/src/main/java/com/geeksville/mesh/model/BTScanModel.kt b/app/src/main/java/com/geeksville/mesh/model/BTScanModel.kt index 569c0c6e0..6e37d63e7 100644 --- a/app/src/main/java/com/geeksville/mesh/model/BTScanModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/BTScanModel.kt @@ -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() } diff --git a/app/src/main/java/com/geeksville/mesh/repository/network/NetworkRepository.kt b/app/src/main/java/com/geeksville/mesh/repository/network/NetworkRepository.kt index 7a4b000a2..ad457caa2 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/network/NetworkRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/network/NetworkRepository.kt @@ -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, private val connectivityManager: dagger.Lazy, ) : Logging { @@ -43,66 +47,16 @@ class NetworkRepository @Inject constructor( private val _resolvedList = MutableStateFlow>(emptyList()) val resolvedList: StateFlow> get() = _resolvedList - private val _networkDiscovery: Flow = callbackFlow { - val resolveQueue = Semaphore(1) - val hostsList = mutableListOf() - 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 { - return _networkDiscovery } companion object { diff --git a/app/src/main/java/com/geeksville/mesh/repository/network/NsdManager.kt b/app/src/main/java/com/geeksville/mesh/repository/network/NsdManager.kt new file mode 100644 index 000000000..c68a9104d --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/repository/network/NsdManager.kt @@ -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> = callbackFlow { + val serviceList = mutableListOf() + 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) +}