mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2025-12-19 14:40:06 +08:00
implement front proxy & landing proxy
This commit is contained in:
parent
eec96213aa
commit
bb51a38474
@ -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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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?) {
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -96,8 +96,7 @@ fun buildConfig(
|
||||
val group = SagerDatabase.groupDao.getById(proxy.groupId)
|
||||
var optionsToMerge = ""
|
||||
|
||||
fun ProxyEntity.resolveChain(): MutableList<ProxyEntity> {
|
||||
val frontProxy = group?.frontProxy?.let { SagerDatabase.proxyDao.getById(it) }
|
||||
fun ProxyEntity.resolveChainInternal(): MutableList<ProxyEntity> {
|
||||
val bean = requireBean()
|
||||
if (bean is ChainBean) {
|
||||
val beans = SagerDatabase.proxyDao.getEntities(bean.proxies)
|
||||
@ -105,20 +104,24 @@ fun buildConfig(
|
||||
val beanList = ArrayList<ProxyEntity>()
|
||||
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<ProxyEntity> {
|
||||
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()
|
||||
|
||||
@ -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<UserAgentPreference>(Key.SUBSCRIPTION_USER_AGENT)!!
|
||||
val subscriptionAutoUpdate =
|
||||
findPreference<SwitchPreference>(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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -247,6 +247,16 @@
|
||||
<item>3</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="front_proxy_entry">
|
||||
<item>@string/ssh_auth_type_none</item>
|
||||
<item>@string/route_profile</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="front_proxy_value">
|
||||
<item>0</item>
|
||||
<item>3</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="networks_value">
|
||||
<item>tcp</item>
|
||||
<item>ws</item>
|
||||
|
||||
@ -504,5 +504,6 @@ Anyone can write advanced plugins, which can control NekoBox. please download an
|
||||
<string name="need_restart">Restart APP to apply changes</string>
|
||||
<string name="use_selector">Use selector</string>
|
||||
<string name="front_proxy">Front proxy</string>
|
||||
<string name="landing_proxy">Landing Proxy</string>
|
||||
|
||||
</resources>
|
||||
@ -22,10 +22,16 @@
|
||||
|
||||
<io.nekohasekai.sagernet.widget.OutboundPreference
|
||||
app:icon="@drawable/ic_hardware_router"
|
||||
app:key="routeOutbound"
|
||||
app:key="groupFrontProxy"
|
||||
app:title="@string/front_proxy"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<io.nekohasekai.sagernet.widget.OutboundPreference
|
||||
app:icon="@drawable/baseline_public_24"
|
||||
app:key="groupLandingProxy"
|
||||
app:title="@string/landing_proxy"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<PreferenceCategory
|
||||
app:key="groupSubscription"
|
||||
app:title="@string/subscription_settings">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user