diff --git a/.github/workflows/release_shadowquic.yml b/.github/workflows/release_shadowquic.yml index cb78db93..836bf246 100644 --- a/.github/workflows/release_shadowquic.yml +++ b/.github/workflows/release_shadowquic.yml @@ -19,7 +19,7 @@ jobs: run: | git submodule update --init plugin/shadowquic/src/main/rust/shadowquic - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 21 @@ -31,8 +31,8 @@ jobs: ndk-version: r29 - name: Setup Rust run: | - rustup toolchain install 1.93.1 - rustup override set 1.93.1 + rustup toolchain install 1.94.1 + rustup override set 1.94.1 rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android - name: Native Build env: diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowquic/ShadowQUICBean.java b/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowquic/ShadowQUICBean.java index 96ed509a..df4bfb61 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowquic/ShadowQUICBean.java +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowquic/ShadowQUICBean.java @@ -39,6 +39,7 @@ public class ShadowQUICBean extends AbstractBean { public Boolean disableALPN; public Boolean useSunnyQUIC; public String certificate; + public Long brutalUploadBandwidth; @Override public void initializeDefaultValues() { @@ -53,12 +54,13 @@ public class ShadowQUICBean extends AbstractBean { if (disableALPN == null) disableALPN = false; if (useSunnyQUIC == null) useSunnyQUIC = false; if (certificate == null) certificate = ""; + if (brutalUploadBandwidth == null) brutalUploadBandwidth = 0L; } @Override public void serialize(ByteBufferOutput output) { super.serialize(output); - output.writeInt(2); + output.writeInt(3); output.writeString(username); output.writeString(password); output.writeString(sni); @@ -69,6 +71,7 @@ public class ShadowQUICBean extends AbstractBean { output.writeBoolean(disableALPN); output.writeBoolean(useSunnyQUIC); output.writeString(certificate); + output.writeLong(brutalUploadBandwidth); } @Override @@ -89,6 +92,9 @@ public class ShadowQUICBean extends AbstractBean { if (version >= 2) { certificate = input.readString(); } + if (version >= 3) { + brutalUploadBandwidth = input.readLong(); + } } @Override diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowquic/ShadowQUICFmt.kt b/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowquic/ShadowQUICFmt.kt index c4276831..1abc69be 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowquic/ShadowQUICFmt.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowquic/ShadowQUICFmt.kt @@ -56,7 +56,19 @@ fun ShadowQUICBean.buildShadowQUICConfig(port: Int, username: String = "", passw } else if (alpn.isNotEmpty()) { outboundObject["alpn"] = alpn.listByLineOrComma() } - if (congestionControl.isNotEmpty()) outboundObject["congestion-control"] = congestionControl + when (congestionControl) { + "" -> {} + "brutal" -> { + val brutalObject: MutableMap = HashMap() + brutalObject["bandwidth"] = "${brutalUploadBandwidth}m" + val congestionControlObject: MutableMap = HashMap() + congestionControlObject["brutal"] = brutalObject + outboundObject["congestion-control"] = congestionControlObject + } + else -> { + outboundObject["congestion-control"] = congestionControl + } + } if (zeroRTT) outboundObject["zero-rtt"] = zeroRTT if (udpOverStream) outboundObject["over-stream"] = udpOverStream if (useSunnyQUIC && certificate.isNotEmpty() && cacheFile != null) { diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ShadowQUICSettingsActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ShadowQUICSettingsActivity.kt index 999e27de..1441eba5 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ShadowQUICSettingsActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ShadowQUICSettingsActivity.kt @@ -23,6 +23,7 @@ import android.os.Bundle import androidx.preference.EditTextPreference import androidx.preference.SwitchPreference import com.takisoft.preferencex.PreferenceFragmentCompat +import com.takisoft.preferencex.SimpleMenuPreference import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.database.DataStore @@ -47,6 +48,7 @@ class ShadowQUICSettingsActivity : ProfileSettingsActivity() { DataStore.serverShadowQUICDisableALPN = disableALPN DataStore.serverShadowQUICUseSunnyQUIC = useSunnyQUIC DataStore.serverCertificates = certificate + DataStore.serverUploadSpeed = brutalUploadBandwidth } override fun ShadowQUICBean.serialize() { @@ -63,6 +65,7 @@ class ShadowQUICSettingsActivity : ProfileSettingsActivity() { disableALPN = DataStore.serverShadowQUICDisableALPN useSunnyQUIC = DataStore.serverShadowQUICUseSunnyQUIC certificate = DataStore.serverCertificates + brutalUploadBandwidth = DataStore.serverUploadSpeed } override fun PreferenceFragmentCompat.createPreferences( @@ -90,6 +93,13 @@ class ShadowQUICSettingsActivity : ProfileSettingsActivity() { certificate.isEnabled = newValue as Boolean true } + val congestionControl = findPreference(Key.SERVER_CONGESTION_CONTROLLER)!! + val brutalUploadBandwidth = findPreference(Key.SERVER_UPLOAD_SPEED)!! + brutalUploadBandwidth.isEnabled = congestionControl.value == "brutal" + congestionControl.setOnPreferenceChangeListener { _, newValue -> + brutalUploadBandwidth.isEnabled = (newValue as String) == "brutal" + true + } } } \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 6e37e3dd..5ab3c8ef 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -894,6 +894,7 @@ bbr cubic new-reno + brutal diff --git a/app/src/main/res/xml/shadowquic_preferences.xml b/app/src/main/res/xml/shadowquic_preferences.xml index a815a1d9..cc2d0856 100644 --- a/app/src/main/res/xml/shadowquic_preferences.xml +++ b/app/src/main/res/xml/shadowquic_preferences.xml @@ -52,6 +52,11 @@ app:key="serverCongestionController" app:title="@string/congestion_control" app:useSimpleSummaryProvider="true" /> +