Refactoring mux settings

This commit is contained in:
armv9 2025-02-23 18:55:11 +09:00
parent 607afa8ce3
commit c7ef42d9f1
14 changed files with 139 additions and 113 deletions

View File

@ -52,9 +52,6 @@ object Key {
const val ALWAYS_SHOW_ADDRESS = "alwaysShowAddress" const val ALWAYS_SHOW_ADDRESS = "alwaysShowAddress"
// Protocol Settings // Protocol Settings
const val MUX_TYPE = "muxType"
const val MUX_PROTOCOLS = "mux"
const val MUX_CONCURRENCY = "muxConcurrency"
const val GLOBAL_ALLOW_INSECURE = "globalAllowInsecure" const val GLOBAL_ALLOW_INSECURE = "globalAllowInsecure"
const val ACQUIRE_WAKE_LOCK = "acquireWakeLock" const val ACQUIRE_WAKE_LOCK = "acquireWakeLock"

View File

@ -169,9 +169,6 @@ object DataStore : OnPreferenceDataStoreChangeListener {
// protocol // protocol
var muxType by configurationStore.stringToInt(Key.MUX_TYPE)
var muxProtocols by configurationStore.stringSet(Key.MUX_PROTOCOLS)
var muxConcurrency by configurationStore.stringToInt(Key.MUX_CONCURRENCY) { 8 }
var globalAllowInsecure by configurationStore.boolean(Key.GLOBAL_ALLOW_INSECURE) { false } var globalAllowInsecure by configurationStore.boolean(Key.GLOBAL_ALLOW_INSECURE) { false }
// old cache, DO NOT ADD // old cache, DO NOT ADD

View File

@ -33,6 +33,7 @@ import io.nekohasekai.sagernet.ktx.app
import io.nekohasekai.sagernet.ktx.applyDefaultValues import io.nekohasekai.sagernet.ktx.applyDefaultValues
import io.nekohasekai.sagernet.ui.profile.* import io.nekohasekai.sagernet.ui.profile.*
import moe.matsuri.nb4a.Protocols import moe.matsuri.nb4a.Protocols
import moe.matsuri.nb4a.SingBoxOptions.MultiplexOptions
import moe.matsuri.nb4a.proxy.config.ConfigBean import moe.matsuri.nb4a.proxy.config.ConfigBean
import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity
import moe.matsuri.nb4a.proxy.neko.* import moe.matsuri.nb4a.proxy.neko.*
@ -309,19 +310,31 @@ data class ProxyEntity(
} }
} }
fun needCoreMux(): Boolean { fun singMux(): MultiplexOptions? {
return when (type) { return when (type) {
TYPE_VMESS -> if (vmessBean!!.isVLESS) { TYPE_VMESS -> MultiplexOptions().apply {
Protocols.isProfileNeedMux(vmessBean!!) && Protocols.shouldEnableMux("vless") enabled = vmessBean!!.enableMux
} else { padding = vmessBean!!.muxPadding
Protocols.isProfileNeedMux(vmessBean!!) && Protocols.shouldEnableMux("vmess") max_streams = vmessBean!!.muxConcurrency
protocol = when (vmessBean!!.muxType) {
1 -> "smux"
2 -> "yamux"
else -> "h2mux"
}
} }
TYPE_TROJAN -> Protocols.isProfileNeedMux(trojanBean!!) TYPE_TROJAN -> MultiplexOptions().apply {
&& Protocols.shouldEnableMux("trojan") enabled = trojanBean!!.enableMux
padding = trojanBean!!.muxPadding
max_streams = trojanBean!!.muxConcurrency
protocol = when (trojanBean!!.muxType) {
1 -> "smux"
2 -> "yamux"
else -> "h2mux"
}
}
TYPE_SS -> !ssBean!!.sUoT && Protocols.shouldEnableMux("shadowsocks") else -> null
else -> false
} }
} }

View File

@ -383,18 +383,12 @@ fun buildConfig(
// val keepAliveInterval = DataStore.tcpKeepAliveInterval // val keepAliveInterval = DataStore.tcpKeepAliveInterval
// val needKeepAliveInterval = keepAliveInterval !in intArrayOf(0, 15) // val needKeepAliveInterval = keepAliveInterval !in intArrayOf(0, 15)
if (!muxApplied && proxyEntity.needCoreMux()) { if (!muxApplied) {
val muxObj = proxyEntity.singMux()
if (muxObj != null && muxObj.enabled) {
muxApplied = true muxApplied = true
currentOutbound["multiplex"] = MultiplexOptions().apply { currentOutbound["multiplex"] = muxObj.asMap()
enabled = true
padding = Protocols.shouldEnableMux("padding")
max_streams = DataStore.muxConcurrency
protocol = when (DataStore.muxType) {
1 -> "smux"
2 -> "yamux"
else -> "h2mux"
} }
}.asMap()
} }
} }
} }

View File

@ -92,10 +92,10 @@ fun TrojanGoBean.buildTrojanGoConfig(port: Int): String {
put(password) put(password)
}) })
put("log_level", if (DataStore.logLevel > 0) 0 else 2) put("log_level", if (DataStore.logLevel > 0) 0 else 2)
if (Protocols.shouldEnableMux("trojan-go")) put("mux", JSONObject().apply { // if (Protocols.shouldEnableMux("trojan-go")) put("mux", JSONObject().apply {
put("enabled", true) // put("enabled", true)
put("concurrency", DataStore.muxConcurrency) // put("concurrency", DataStore.muxConcurrency)
}) // })
put("tcp", JSONObject().apply { put("tcp", JSONObject().apply {
put("prefer_ipv4", DataStore.ipv6Mode <= IPv6Mode.ENABLE) put("prefer_ipv4", DataStore.ipv6Mode <= IPv6Mode.ENABLE)
}) })

View File

@ -52,11 +52,20 @@ public abstract class StandardV2RayBean extends AbstractBean {
public Boolean enableECH; public Boolean enableECH;
public String echConfig;
// sing-box 不再使用
public Boolean enablePqSignature; public Boolean enablePqSignature;
public Boolean disabledDRS; public Boolean disabledDRS;
public String echConfig; // --------------------------------------- Mux
public Boolean enableMux;
public Boolean muxPadding;
public Integer muxType;
public Integer muxConcurrency;
// --------------------------------------- // // --------------------------------------- //
@ -101,11 +110,16 @@ public abstract class StandardV2RayBean extends AbstractBean {
if (JavaUtil.isNullOrBlank(echConfig)) echConfig = ""; if (JavaUtil.isNullOrBlank(echConfig)) echConfig = "";
if (enablePqSignature == null) enablePqSignature = false; if (enablePqSignature == null) enablePqSignature = false;
if (disabledDRS == null) disabledDRS = false; if (disabledDRS == null) disabledDRS = false;
if (enableMux == null) enableMux = false;
if (muxPadding == null) muxPadding = false;
if (muxType == null) muxType = 0;
if (muxConcurrency == null) muxConcurrency = 1;
} }
@Override @Override
public void serialize(ByteBufferOutput output) { public void serialize(ByteBufferOutput output) {
output.writeInt(1); output.writeInt(2);
super.serialize(output); super.serialize(output);
output.writeString(uuid); output.writeString(uuid);
output.writeString(encryption); output.writeString(encryption);
@ -160,6 +174,11 @@ public abstract class StandardV2RayBean extends AbstractBean {
} }
output.writeInt(packetEncoding); output.writeInt(packetEncoding);
output.writeBoolean(enableMux);
output.writeBoolean(muxPadding);
output.writeInt(muxType);
output.writeInt(muxConcurrency);
} }
@Override @Override
@ -239,6 +258,13 @@ public abstract class StandardV2RayBean extends AbstractBean {
} }
packetEncoding = input.readInt(); packetEncoding = input.readInt();
if (version >= 2) {
enableMux = input.readBoolean();
muxPadding = input.readBoolean();
muxType = input.readInt();
muxConcurrency = input.readInt();
}
} }
@Override @Override
@ -251,6 +277,10 @@ public abstract class StandardV2RayBean extends AbstractBean {
bean.enableECH = enableECH; bean.enableECH = enableECH;
bean.disabledDRS = disabledDRS; bean.disabledDRS = disabledDRS;
bean.echConfig = echConfig; bean.echConfig = echConfig;
bean.enableMux = enableMux;
bean.muxPadding = muxPadding;
bean.muxType = muxType;
bean.muxConcurrency = muxConcurrency;
} }
public boolean isVLESS() { public boolean isVLESS() {

View File

@ -416,6 +416,20 @@ object RawUpdater : GroupUpdater() {
realityOpt.value.toString() realityOpt.value.toString()
} }
} }
"smux" -> for (smuxOpt in (opt.value as Map<String, Any>)) {
when (smuxOpt.key.lowercase()) {
"enabled" -> bean.enableMux =
smuxOpt.value.toString() == "true"
"max-streams" -> bean.muxConcurrency =
smuxOpt.value.toString().toInt()
"padding" -> bean.muxPadding =
smuxOpt.value.toString() == "true"
}
}
} }
} }
if (isHttpUpgrade) { if (isHttpUpgrade) {
@ -475,6 +489,19 @@ object RawUpdater : GroupUpdater() {
grpcOpt.value.toString() grpcOpt.value.toString()
} }
} }
"smux" -> for (smuxOpt in (opt.value as Map<String, Any>)) {
when (smuxOpt.key.lowercase()) {
"enabled" -> bean.enableMux =
smuxOpt.value.toString() == "true"
"max-streams" -> bean.muxConcurrency =
smuxOpt.value.toString().toInt()
"padding" -> bean.muxPadding =
smuxOpt.value.toString() == "true"
}
}
} }
} }
if (isHttpUpgrade) { if (isHttpUpgrade) {

View File

@ -17,7 +17,6 @@ import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.ktx.*
import io.nekohasekai.sagernet.utils.Theme import io.nekohasekai.sagernet.utils.Theme
import io.nekohasekai.sagernet.widget.AppListPreference import io.nekohasekai.sagernet.widget.AppListPreference
import moe.matsuri.nb4a.Protocols
import moe.matsuri.nb4a.ui.* import moe.matsuri.nb4a.ui.*
class SettingsPreferenceFragment : PreferenceFragmentCompat() { class SettingsPreferenceFragment : PreferenceFragmentCompat() {
@ -81,7 +80,6 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
val ipv6Mode = findPreference<Preference>(Key.IPV6_MODE)!! val ipv6Mode = findPreference<Preference>(Key.IPV6_MODE)!!
val trafficSniffing = findPreference<Preference>(Key.TRAFFIC_SNIFFING)!! val trafficSniffing = findPreference<Preference>(Key.TRAFFIC_SNIFFING)!!
val muxConcurrency = findPreference<EditTextPreference>(Key.MUX_CONCURRENCY)!!
val tcpKeepAliveInterval = findPreference<EditTextPreference>(Key.TCP_KEEP_ALIVE_INTERVAL)!! val tcpKeepAliveInterval = findPreference<EditTextPreference>(Key.TCP_KEEP_ALIVE_INTERVAL)!!
tcpKeepAliveInterval.isVisible = false tcpKeepAliveInterval.isVisible = false
@ -123,16 +121,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
true true
} }
val muxProtocols = findPreference<MultiSelectListPreference>(Key.MUX_PROTOCOLS)!!
muxProtocols.apply {
val e = Protocols.getCanMuxList().toTypedArray()
entries = e
entryValues = e
}
portLocalDns.setOnBindEditTextListener(EditTextPreferenceModifiers.Port) portLocalDns.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
muxConcurrency.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
mixedPort.setOnBindEditTextListener(EditTextPreferenceModifiers.Port) mixedPort.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
val metedNetwork = findPreference<Preference>(Key.METERED_NETWORK)!! val metedNetwork = findPreference<Preference>(Key.METERED_NETWORK)!!
@ -175,7 +164,6 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
appendHttpProxy.onPreferenceChangeListener = reloadListener appendHttpProxy.onPreferenceChangeListener = reloadListener
showDirectSpeed.onPreferenceChangeListener = reloadListener showDirectSpeed.onPreferenceChangeListener = reloadListener
trafficSniffing.onPreferenceChangeListener = reloadListener trafficSniffing.onPreferenceChangeListener = reloadListener
muxConcurrency.onPreferenceChangeListener = reloadListener
tcpKeepAliveInterval.onPreferenceChangeListener = reloadListener tcpKeepAliveInterval.onPreferenceChangeListener = reloadListener
bypassLan.onPreferenceChangeListener = reloadListener bypassLan.onPreferenceChangeListener = reloadListener
bypassLanInCore.onPreferenceChangeListener = reloadListener bypassLanInCore.onPreferenceChangeListener = reloadListener

View File

@ -47,6 +47,11 @@ abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV
private val enableECH = pbm.add(PreferenceBinding(Type.Bool, "enableECH")) private val enableECH = pbm.add(PreferenceBinding(Type.Bool, "enableECH"))
private val echConfig = pbm.add(PreferenceBinding(Type.Text, "echConfig")) private val echConfig = pbm.add(PreferenceBinding(Type.Text, "echConfig"))
private val enableMux = pbm.add(PreferenceBinding(Type.Bool, "enableMux"))
private val muxPadding = pbm.add(PreferenceBinding(Type.Bool, "muxPadding"))
private val muxType = pbm.add(PreferenceBinding(Type.TextToInt, "muxType"))
private val muxConcurrency = pbm.add(PreferenceBinding(Type.TextToInt, "muxConcurrency"))
override fun StandardV2RayBean.init() { override fun StandardV2RayBean.init() {
if (this is TrojanBean) { if (this is TrojanBean) {
this@StandardV2RaySettingsActivity.uuid.fieldName = "password" this@StandardV2RaySettingsActivity.uuid.fieldName = "password"
@ -158,6 +163,7 @@ abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV
host.preference.isVisible = true host.preference.isVisible = true
path.preference.isVisible = true path.preference.isVisible = true
} }
"ws" -> { "ws" -> {
host.preference.setTitle(R.string.ws_host) host.preference.setTitle(R.string.ws_host)
path.preference.setTitle(R.string.ws_path) path.preference.setTitle(R.string.ws_path)

View File

@ -2,43 +2,13 @@ package moe.matsuri.nb4a
import android.content.Context import android.content.Context
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProxyEntity.Companion.TYPE_NEKO import io.nekohasekai.sagernet.database.ProxyEntity.Companion.TYPE_NEKO
import io.nekohasekai.sagernet.fmt.AbstractBean import io.nekohasekai.sagernet.fmt.AbstractBean
import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean
import io.nekohasekai.sagernet.fmt.v2ray.isTLS
import io.nekohasekai.sagernet.ktx.app import io.nekohasekai.sagernet.ktx.app
import io.nekohasekai.sagernet.ktx.getColorAttr import io.nekohasekai.sagernet.ktx.getColorAttr
import moe.matsuri.nb4a.plugin.NekoPluginManager
// Settings for all protocols, built-in or plugin // Settings for all protocols, built-in or plugin
object Protocols { object Protocols {
// Mux
fun isProfileNeedMux(bean: StandardV2RayBean): Boolean {
return when (bean.type) {
"tcp", "ws" -> true
"http" -> !bean.isTLS()
else -> false
}
}
fun shouldEnableMux(protocol: String): Boolean {
return DataStore.muxProtocols.contains(protocol)
}
fun getCanMuxList(): List<String> {
// built-in and support mux
val list = mutableListOf("vmess", "trojan", "trojan-go", "shadowsocks", "vless", "padding")
NekoPluginManager.getProtocols().forEach {
if (it.protocolConfig.optBoolean("canMux")) {
list.add(it.protocolId)
}
}
return list
}
// Deduplication // Deduplication

View File

@ -65,8 +65,8 @@ suspend fun NekoBean.updateAllConfig(port: Int) = suspendCoroutine<Unit> {
val otherArgs = mutableMapOf<String, Any>() val otherArgs = mutableMapOf<String, Any>()
otherArgs["finalAddress"] = finalAddress otherArgs["finalAddress"] = finalAddress
otherArgs["finalPort"] = finalPort otherArgs["finalPort"] = finalPort
otherArgs["muxEnabled"] = Protocols.shouldEnableMux(protocolId) // otherArgs["muxEnabled"] = Protocols.shouldEnableMux(protocolId)
otherArgs["muxConcurrency"] = DataStore.muxConcurrency // otherArgs["muxConcurrency"] = DataStore.muxConcurrency
val ret = jsip.buildAllConfig(port, this@updateAllConfig, otherArgs) val ret = jsip.buildAllConfig(port, this@updateAllConfig, otherArgs)

View File

@ -568,4 +568,6 @@
<string name="allow_insecure_on_request_sum">Disable certificate checking when updating <string name="allow_insecure_on_request_sum">Disable certificate checking when updating
subscriptions</string> subscriptions</string>
<string name="global_allow_insecure">Always allow insecure</string> <string name="global_allow_insecure">Always allow insecure</string>
<string name="mux_preference">Mulitplex</string>
<string name="padding">Padding</string>
</resources> </resources>

View File

@ -134,34 +134,6 @@
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory app:title="@string/protocol_settings">
<MultiSelectListPreference
app:defaultValue="@array/mux_select_init"
app:entries="@array/mux_select_init"
app:entryValues="@array/mux_select_init"
app:icon="@drawable/ic_baseline_compare_arrows_24"
app:key="mux"
app:summary="@string/mux_sum"
app:title="@string/enable_mux" />
<moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="0"
app:entries="@array/mux_type"
app:entryValues="@array/int_array_3"
app:key="muxType"
app:title="@string/mux_type"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
app:defaultValue="8"
app:icon="@drawable/ic_baseline_low_priority_24"
app:key="muxConcurrency"
app:title="@string/mux_concurrency"
app:useSimpleSummaryProvider="true" />
<SwitchPreference
app:key="globalAllowInsecure"
app:icon="@drawable/ic_action_lock_open"
app:title="@string/global_allow_insecure" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/cag_dns"> <PreferenceCategory app:title="@string/cag_dns">
<EditTextPreference <EditTextPreference
app:defaultValue="https://dns.google/dns-query" app:defaultValue="https://dns.google/dns-query"
@ -267,5 +239,9 @@
<SwitchPreference <SwitchPreference
app:key="allowInsecureOnRequest" app:key="allowInsecureOnRequest"
app:title="@string/allow_insecure_on_request_sum" /> app:title="@string/allow_insecure_on_request_sum" />
<SwitchPreference
app:icon="@drawable/ic_action_lock_open"
app:key="globalAllowInsecure"
app:title="@string/global_allow_insecure" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@ -118,11 +118,6 @@
app:key="allowInsecure" app:key="allowInsecure"
app:summary="@string/allow_insecure_sum" app:summary="@string/allow_insecure_sum"
app:title="@string/allow_insecure" /> app:title="@string/allow_insecure" />
<SwitchPreference
app:icon="@drawable/ic_baseline_security_24"
app:key="enableECH"
app:summary="@string/enable_ech_sum"
app:title="@string/enable_ech" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
@ -149,10 +144,41 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
app:key="serverECHCategory" app:key="serverMuxCategory"
app:title="@string/ech_settings"> app:title="@string/mux_preference">
<SwitchPreference
app:icon="@drawable/ic_baseline_compare_arrows_24"
app:key="enableMux"
app:summary="@string/mux_sum"
app:title="@string/enable_mux" />
<moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="0"
app:entries="@array/mux_type"
app:entryValues="@array/int_array_3"
app:key="muxType"
app:title="@string/mux_type"
app:useSimpleSummaryProvider="true" />
<EditTextPreference <EditTextPreference
app:icon="@drawable/ic_baseline_texture_24" app:defaultValue="1"
app:icon="@drawable/ic_baseline_low_priority_24"
app:key="muxConcurrency"
app:title="@string/mux_concurrency"
app:useSimpleSummaryProvider="true" />
<SwitchPreference
app:icon="@drawable/baseline_developer_board_24"
app:key="muxPadding"
app:title="@string/padding" />
</PreferenceCategory>
<PreferenceCategory
app:key="serverECHCategory"
app:title="ECH">
<SwitchPreference
app:icon="@drawable/ic_baseline_security_24"
app:key="enableECH"
app:title="@string/enable" />
<EditTextPreference
app:icon="@drawable/ic_baseline_nfc_24"
app:key="echConfig" app:key="echConfig"
app:title="@string/ech_config" app:title="@string/ech_config"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />