new method to detect default network
This commit is contained in:
3 files changed
+69
-74
No files matched your search
@@ -11,6 +11,7 @@ import com.github.kr328.clash.service.data.ClashDatabase
|
||||
import com.github.kr328.clash.service.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
|
||||
class ClashService : BaseService() {
|
||||
companion object {
|
||||
@@ -20,6 +21,7 @@ class ClashService : BaseService() {
|
||||
var isServiceRunning = false
|
||||
}
|
||||
|
||||
private val loadLock = Mutex()
|
||||
private val service = this
|
||||
private lateinit var notification: ClashNotification
|
||||
private var stopReason: String? = null
|
||||
@@ -96,10 +98,13 @@ class ClashService : BaseService() {
|
||||
}
|
||||
|
||||
private suspend fun reloadProfile() {
|
||||
val active = ClashDatabase.getInstance(service).openClashProfileDao()
|
||||
.queryActiveProfile() ?: return stopSelf("Empty active profile")
|
||||
if ( !loadLock.tryLock() )
|
||||
return
|
||||
|
||||
try {
|
||||
val active = ClashDatabase.getInstance(service).openClashProfileDao()
|
||||
.queryActiveProfile() ?: return stopSelf("Empty active profile")
|
||||
|
||||
Clash.loadProfile(
|
||||
resolveProfile(active.id),
|
||||
resolveBase(active.id)
|
||||
@@ -115,6 +120,8 @@ class ClashService : BaseService() {
|
||||
broadcastProfileLoaded(this, active)
|
||||
} catch (e: Exception) {
|
||||
stopSelf("Load profile failure")
|
||||
} finally {
|
||||
loadLock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ class TunService : VpnService(), CoroutineScope by MainScope() {
|
||||
while (isActive) {
|
||||
val d = defaultNetworkChannel.receive()
|
||||
|
||||
Log.i("Network changed to ${d?.second}")
|
||||
|
||||
if ( d == null ) {
|
||||
setUnderlyingNetworks(null)
|
||||
continue
|
||||
|
||||
@@ -3,36 +3,27 @@ package com.github.kr328.clash.service.net
|
||||
|
||||
import android.content.Context
|
||||
import android.net.*
|
||||
import com.github.kr328.clash.core.utils.Log
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
|
||||
class DefaultNetworkChannel(val context: Context, scope: CoroutineScope) :
|
||||
CoroutineScope by scope, Channel<Pair<Network, LinkProperties>?> by Channel(Channel.CONFLATED) {
|
||||
private var currentNetwork: Network? = null
|
||||
private val detectDelayLock = Mutex()
|
||||
private val connectivity = context.getSystemService(ConnectivityManager::class.java)!!
|
||||
private val callback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
sendDefaultNetwork(true)
|
||||
}
|
||||
var current: Network? = null
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
sendDefaultNetwork(true)
|
||||
}
|
||||
|
||||
override fun onCapabilitiesChanged(
|
||||
network: Network,
|
||||
networkCapabilities: NetworkCapabilities
|
||||
) {
|
||||
if ( network == currentNetwork &&
|
||||
!networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) )
|
||||
sendDefaultNetwork(true)
|
||||
if ( current == network )
|
||||
offer(null)
|
||||
}
|
||||
|
||||
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
|
||||
if ( network == currentNetwork )
|
||||
sendDefaultNetwork(false)
|
||||
if ( linkProperties.routes.any { it.isDefaultRoute } ) {
|
||||
offer(network to linkProperties)
|
||||
current = network
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,59 +35,54 @@ class DefaultNetworkChannel(val context: Context, scope: CoroutineScope) :
|
||||
connectivity.unregisterNetworkCallback(callback)
|
||||
}
|
||||
|
||||
private fun sendDefaultNetwork(ignoreSameNetwork: Boolean) {
|
||||
if (detectDelayLock.tryLock()) {
|
||||
launch {
|
||||
delay(1000)
|
||||
|
||||
val network = detectDefaultNetwork()
|
||||
if ( ignoreSameNetwork && network == currentNetwork )
|
||||
return@launch
|
||||
|
||||
currentNetwork = network
|
||||
|
||||
val linkProperties = network?.let { connectivity.getLinkProperties(it) }
|
||||
|
||||
if ( network != null && linkProperties != null )
|
||||
send(network to linkProperties)
|
||||
else
|
||||
send(null)
|
||||
|
||||
detectDelayLock.unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun detectDefaultNetwork(): Network? = withContext(Dispatchers.Default) {
|
||||
return@withContext try {
|
||||
connectivity.allNetworks
|
||||
.asSequence()
|
||||
.mapNotNull { network ->
|
||||
connectivity.getNetworkCapabilities(network)?.let { it to network }
|
||||
}
|
||||
.filterNot {
|
||||
it.first.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
|
||||
!it.first.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
}
|
||||
.sortedBy {
|
||||
when {
|
||||
it.first.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> 0
|
||||
it.first.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> 1
|
||||
it.first.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> 2
|
||||
it.first.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> 3
|
||||
it.first.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> 4
|
||||
else -> 5
|
||||
} + if (it.first.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED))
|
||||
-1000
|
||||
else
|
||||
0
|
||||
}
|
||||
.map {
|
||||
it.second
|
||||
}
|
||||
.firstOrNull()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
// private fun sendDefaultNetwork() {
|
||||
// if (detectDelayLock.tryLock()) {
|
||||
// launch {
|
||||
// delay(1000)
|
||||
//
|
||||
// val network = detectDefaultNetwork()
|
||||
// val linkProperties = network?.let { connectivity.getLinkProperties(it) }
|
||||
//
|
||||
// if ( network != null && linkProperties != null )
|
||||
// send(network to linkProperties)
|
||||
// else
|
||||
// send(null)
|
||||
//
|
||||
// detectDelayLock.unlock()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private suspend fun detectDefaultNetwork(): Network? = withContext(Dispatchers.Default) {
|
||||
// return@withContext try {
|
||||
// connectivity.allNetworks
|
||||
// .asSequence()
|
||||
// .mapNotNull { network ->
|
||||
// connectivity.getNetworkCapabilities(network)?.let { it to network }
|
||||
// }
|
||||
// .filterNot {
|
||||
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
|
||||
// !it.first.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
// }
|
||||
// .sortedBy {
|
||||
// when {
|
||||
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> 0
|
||||
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> 1
|
||||
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> 2
|
||||
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> 3
|
||||
// it.first.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> 4
|
||||
// else -> 5
|
||||
// } + if (it.first.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED))
|
||||
// -1000
|
||||
// else
|
||||
// 0
|
||||
// }
|
||||
// .map {
|
||||
// it.second
|
||||
// }
|
||||
// .firstOrNull()
|
||||
// } catch (e: Exception) {
|
||||
// null
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Reference in new issue
Block a user