From bb51a38474b35cb76eae168b3dfa3ca303a3dcd2 Mon Sep 17 00:00:00 2001 From: arm64v8a <48624112+arm64v8a@users.noreply.github.com> Date: Sat, 18 Mar 2023 16:46:19 +0900 Subject: [PATCH] implement front proxy & landing proxy --- .../2.json | 24 +++++--- .../java/io/nekohasekai/sagernet/Constants.kt | 3 +- .../io/nekohasekai/sagernet/bg/BaseService.kt | 17 +++++- .../sagernet/bg/SagerConnection.kt | 1 + .../sagernet/bg/ServiceNotification.kt | 3 + .../sagernet/database/DataStore.kt | 10 +++- .../sagernet/database/ProxyGroup.kt | 3 +- .../nekohasekai/sagernet/fmt/ConfigBuilder.kt | 29 +++++---- .../sagernet/ui/GroupSettingsActivity.kt | 59 ++++++++++++++----- .../sagernet/widget/OutboundPreference.kt | 2 +- app/src/main/res/values/arrays.xml | 10 ++++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/group_preferences.xml | 8 ++- 13 files changed, 124 insertions(+), 46 deletions(-) diff --git a/app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/2.json b/app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/2.json index 7a87689..1322923 100644 --- a/app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/2.json +++ b/app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/2.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 2, - "identityHash": "062104587ad7088bb9926683389e995d", + "identityHash": "937a517378a0cb35dc1f8bd181683882", "entities": [ { "tableName": "proxy_groups", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL)", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)", "fields": [ { "fieldPath": "id", @@ -61,13 +61,19 @@ "columnName": "frontProxy", "affinity": "INTEGER", "notNull": true + }, + { + "fieldPath": "landingProxy", + "columnName": "landingProxy", + "affinity": "INTEGER", + "notNull": true } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [], "foreignKeys": [] @@ -222,10 +228,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -324,10 +330,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [], "foreignKeys": [] @@ -336,7 +342,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '062104587ad7088bb9926683389e995d')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '937a517378a0cb35dc1f8bd181683882')" ] } } \ No newline at end of file diff --git a/app/src/main/java/io/nekohasekai/sagernet/Constants.kt b/app/src/main/java/io/nekohasekai/sagernet/Constants.kt index cf42b23..cd85081 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/Constants.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/Constants.kt @@ -127,13 +127,14 @@ object Key { const val ROUTE_SOURCE = "routeSource" const val ROUTE_PROTOCOL = "routeProtocol" const val ROUTE_OUTBOUND = "routeOutbound" - const val ROUTE_OUTBOUND_RULE = "routeOutboundRule" const val ROUTE_PACKAGES = "routePackages" const val GROUP_NAME = "groupName" const val GROUP_TYPE = "groupType" const val GROUP_ORDER = "groupOrder" const val GROUP_IS_SELECTOR = "groupIsSelector" + const val GROUP_FRONT_PROXY = "groupFrontProxy" + const val GROUP_LANDING_PROXY = "groupLandingProxy" const val GROUP_SUBSCRIPTION = "groupSubscription" const val SUBSCRIPTION_LINK = "subscriptionLink" diff --git a/app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt b/app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt index 4681068..c4b1e0c 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt @@ -13,6 +13,7 @@ import io.nekohasekai.sagernet.aidl.ISagerNetService import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback import io.nekohasekai.sagernet.bg.proto.ProxyInstance import io.nekohasekai.sagernet.database.DataStore +import io.nekohasekai.sagernet.database.ProxyEntity import io.nekohasekai.sagernet.database.SagerDatabase import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.plugin.PluginManager @@ -149,14 +150,24 @@ class BaseService { } if (canReloadSelector()) { var tag = "" + var ent: ProxyEntity? = null data.proxy!!.config.trafficMap.forEach { (t, list) -> - if (list.map { it.id }.contains(DataStore.selectedProxy)) { - tag = t + for (it in list) { + if (it.id == DataStore.selectedProxy) { + ent = it + tag = t + break + } } } - if (tag.isNotBlank()) { + if (tag.isNotBlank() && ent != null) { val success = data.proxy!!.box.selectOutbound(tag) Logs.d("selectOutbound $tag $success") + runOnDefaultDispatcher { + data.binder.broadcast { + it.stateChanged(-1, ent!!.displayName(), null) + } + } } return } diff --git a/app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt b/app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt index 5bce1dd..623b646 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt @@ -53,6 +53,7 @@ class SagerConnection(private var listenForDeath: Boolean = false) : ServiceConn private val serviceCallback = object : ISagerNetServiceCallback.Stub() { override fun stateChanged(state: Int, profileName: String?, msg: String?) { + if (state < 0) return // skip private val s = BaseService.State.values()[state] DataStore.serviceState = s val callback = callback ?: return diff --git a/app/src/main/java/io/nekohasekai/sagernet/bg/ServiceNotification.kt b/app/src/main/java/io/nekohasekai/sagernet/bg/ServiceNotification.kt index 37b66dd..cae6891 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/bg/ServiceNotification.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/bg/ServiceNotification.kt @@ -89,6 +89,9 @@ class ServiceNotification( } override fun stateChanged(state: Int, profileName: String?, msg: String?) { + if (state == -1) { + builder.setContentTitle(profileName) + } } override fun missingPlugin(profileName: String?, pluginName: String?) { diff --git a/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt b/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt index e9aabec..2b451a2 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt @@ -85,11 +85,11 @@ object DataStore : OnPreferenceDataStoreChangeListener { var nightTheme by configurationStore.stringToInt(Key.NIGHT_THEME) var serviceMode by configurationStore.string(Key.SERVICE_MODE) { Key.MODE_VPN } -// var domainStrategy by configurationStore.string(Key.DOMAIN_STRATEGY) { "AsIs" } + // var domainStrategy by configurationStore.string(Key.DOMAIN_STRATEGY) { "AsIs" } var trafficSniffing by configurationStore.boolean(Key.TRAFFIC_SNIFFING) { true } var resolveDestination by configurationStore.boolean(Key.RESOLVE_DESTINATION) -// var tcpKeepAliveInterval by configurationStore.stringToInt(Key.TCP_KEEP_ALIVE_INTERVAL) { 15 } + // var tcpKeepAliveInterval by configurationStore.stringToInt(Key.TCP_KEEP_ALIVE_INTERVAL) { 15 } var mtu by configurationStore.stringToInt(Key.MTU) { 9000 } var bypassLan by configurationStore.boolean(Key.BYPASS_LAN) @@ -225,9 +225,13 @@ object DataStore : OnPreferenceDataStoreChangeListener { var routeSource by profileCacheStore.string(Key.ROUTE_SOURCE) var routeProtocol by profileCacheStore.string(Key.ROUTE_PROTOCOL) var routeOutbound by profileCacheStore.stringToInt(Key.ROUTE_OUTBOUND) - var routeOutboundRule by profileCacheStore.long(Key.ROUTE_OUTBOUND_RULE) + var routeOutboundRule by profileCacheStore.long(Key.ROUTE_OUTBOUND + "Long") var routePackages by profileCacheStore.string(Key.ROUTE_PACKAGES) + var frontProxy by profileCacheStore.long(Key.GROUP_FRONT_PROXY + "Long") + var landingProxy by profileCacheStore.long(Key.GROUP_LANDING_PROXY + "Long") + var frontProxyTmp by profileCacheStore.stringToInt(Key.GROUP_FRONT_PROXY) + var landingProxyTmp by profileCacheStore.stringToInt(Key.GROUP_LANDING_PROXY) var serverConfig by profileCacheStore.string(Key.SERVER_CONFIG) diff --git a/app/src/main/java/io/nekohasekai/sagernet/database/ProxyGroup.kt b/app/src/main/java/io/nekohasekai/sagernet/database/ProxyGroup.kt index 5f7f753..27c1060 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/database/ProxyGroup.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/database/ProxyGroup.kt @@ -20,7 +20,8 @@ data class ProxyGroup( var subscription: SubscriptionBean? = null, var order: Int = GroupOrder.ORIGIN, var isSelector: Boolean = false, - var frontProxy: Long = 0L + var frontProxy: Long = -1L, + var landingProxy: Long = -1L ) : Serializable() { @Transient diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt b/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt index f8720bf..aa6800a 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt @@ -96,8 +96,7 @@ fun buildConfig( val group = SagerDatabase.groupDao.getById(proxy.groupId) var optionsToMerge = "" - fun ProxyEntity.resolveChain(): MutableList { - val frontProxy = group?.frontProxy?.let { SagerDatabase.proxyDao.getById(it) } + fun ProxyEntity.resolveChainInternal(): MutableList { val bean = requireBean() if (bean is ChainBean) { val beans = SagerDatabase.proxyDao.getEntities(bean.proxies) @@ -105,20 +104,24 @@ fun buildConfig( val beanList = ArrayList() for (proxyId in bean.proxies) { val item = beansMap[proxyId] ?: continue - beanList.addAll(item.resolveChain()) - } - return if (frontProxy == null) { - beanList.asReversed() - } else { - beanList.add(0, frontProxy) - beanList.asReversed() + beanList.addAll(item.resolveChainInternal()) } + return beanList.asReversed() } - return if (frontProxy == null) { - mutableListOf(this) - } else { - mutableListOf(this, frontProxy) + return mutableListOf(this) + } + + fun ProxyEntity.resolveChain(): MutableList { + val frontProxy = group?.frontProxy?.let { SagerDatabase.proxyDao.getById(it) } + val landingProxy = group?.landingProxy?.let { SagerDatabase.proxyDao.getById(it) } + val list = resolveChainInternal() + if (frontProxy != null) { + list.add(frontProxy) } + if (landingProxy != null) { + list.add(0, landingProxy) + } + return list } val extraRules = if (forTest) listOf() else SagerDatabase.rulesDao.enabledRules() diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/GroupSettingsActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/GroupSettingsActivity.kt index acc15c7..4d2e1c2 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/GroupSettingsActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/GroupSettingsActivity.kt @@ -37,14 +37,18 @@ class GroupSettingsActivity( OnPreferenceDataStoreChangeListener { private lateinit var frontProxyPreference: OutboundPreference + private lateinit var landingProxyPreference: OutboundPreference fun ProxyGroup.init() { DataStore.groupName = name ?: "" DataStore.groupType = type DataStore.groupOrder = order DataStore.groupIsSelector = isSelector - DataStore.routeOutboundRule = frontProxy - DataStore.routeOutbound = if (frontProxy >= 0) 3 else 0 + + DataStore.frontProxy = frontProxy + DataStore.landingProxy = landingProxy + DataStore.frontProxyTmp = if (frontProxy >= 0) 3 else 0 + DataStore.landingProxyTmp = if (landingProxy >= 0) 3 else 0 val subscription = subscription ?: SubscriptionBean().applyDefaultValues() DataStore.subscriptionLink = subscription.link @@ -61,7 +65,9 @@ class GroupSettingsActivity( type = DataStore.groupType order = DataStore.groupOrder isSelector = DataStore.groupIsSelector - frontProxy = if (DataStore.routeOutbound == 3) DataStore.routeOutboundRule else -1 + + frontProxy = if (DataStore.frontProxyTmp == 3) DataStore.frontProxy else -1 + landingProxy = if (DataStore.landingProxyTmp == 3) DataStore.landingProxy else -1 val isSubscription = type == GroupType.SUBSCRIPTION if (isSubscription) { @@ -88,13 +94,28 @@ class GroupSettingsActivity( ) { addPreferencesFromResource(R.xml.group_preferences) - frontProxyPreference = findPreference(Key.ROUTE_OUTBOUND)!! + frontProxyPreference = findPreference(Key.GROUP_FRONT_PROXY)!! frontProxyPreference.apply { - entries = listOf("None", "Select...").toTypedArray() - entryValues = listOf("0", "3").toTypedArray() + setEntries(R.array.front_proxy_entry) + setEntryValues(R.array.front_proxy_value) setOnPreferenceChangeListener { _, newValue -> if (newValue.toString() == "3") { - selectProfileForAdd.launch( + selectProfileForAddFront.launch( + Intent(this@GroupSettingsActivity, ProfileSelectActivity::class.java) + ) + false + } else { + true + } + } + } + landingProxyPreference = findPreference(Key.GROUP_LANDING_PROXY)!! + landingProxyPreference.apply { + setEntries(R.array.front_proxy_entry) + setEntryValues(R.array.front_proxy_value) + setOnPreferenceChangeListener { _, newValue -> + if (newValue.toString() == "3") { + selectProfileForAddLanding.launch( Intent(this@GroupSettingsActivity, ProfileSelectActivity::class.java) ) false @@ -119,8 +140,6 @@ class GroupSettingsActivity( true } - val subscriptionUserAgent = - findPreference(Key.SUBSCRIPTION_USER_AGENT)!! val subscriptionAutoUpdate = findPreference(Key.SUBSCRIPTION_AUTO_UPDATE)!! val subscriptionAutoUpdateDelay = @@ -339,20 +358,32 @@ class GroupSettingsActivity( } - val selectProfileForAdd = registerForActivityResult( + val selectProfileForAddFront = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { if (it.resultCode == Activity.RESULT_OK) runOnDefaultDispatcher { val profile = ProfileManager.getProfile( - it.data!!.getLongExtra( - ProfileSelectActivity.EXTRA_PROFILE_ID, 0 - ) + it.data!!.getLongExtra(ProfileSelectActivity.EXTRA_PROFILE_ID, 0) ) ?: return@runOnDefaultDispatcher - DataStore.routeOutboundRule = profile.id + DataStore.frontProxy = profile.id onMainDispatcher { frontProxyPreference.value = "3" } } } + val selectProfileForAddLanding = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { + if (it.resultCode == Activity.RESULT_OK) runOnDefaultDispatcher { + val profile = ProfileManager.getProfile( + it.data!!.getLongExtra(ProfileSelectActivity.EXTRA_PROFILE_ID, 0) + ) ?: return@runOnDefaultDispatcher + DataStore.landingProxy = profile.id + onMainDispatcher { + landingProxyPreference.value = "3" + } + } + } + } \ No newline at end of file diff --git a/app/src/main/java/io/nekohasekai/sagernet/widget/OutboundPreference.kt b/app/src/main/java/io/nekohasekai/sagernet/widget/OutboundPreference.kt index b4576ff..67f6ab2 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/widget/OutboundPreference.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/widget/OutboundPreference.kt @@ -19,7 +19,7 @@ class OutboundPreference override fun getSummary(): CharSequence? { if (value == "3") { - val routeOutbound = DataStore.routeOutboundRule + val routeOutbound = DataStore.profileCacheStore.getLong(key + "Long") ?: 0 if (routeOutbound > 0) { ProfileManager.getProfile(routeOutbound)?.displayName()?.let { return it diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 56af5c8..99037dc 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -247,6 +247,16 @@ 3 + + @string/ssh_auth_type_none + @string/route_profile + + + + 0 + 3 + + tcp ws diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d441400..6f8634a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -504,5 +504,6 @@ Anyone can write advanced plugins, which can control NekoBox. please download an Restart APP to apply changes Use selector Front proxy + Landing Proxy \ No newline at end of file diff --git a/app/src/main/res/xml/group_preferences.xml b/app/src/main/res/xml/group_preferences.xml index ec55ef5..ef65565 100644 --- a/app/src/main/res/xml/group_preferences.xml +++ b/app/src/main/res/xml/group_preferences.xml @@ -22,10 +22,16 @@ + +