Skip to content

Bump sing-quic pin; drop the Hysteria2 client binary#113

Merged
hawkff merged 1 commit into
mainfrom
chore/sing-quic-bump-drop-hy2-sidecar
Jun 30, 2026
Merged

Bump sing-quic pin; drop the Hysteria2 client binary#113
hawkff merged 1 commit into
mainfrom
chore/sing-quic-bump-drop-hy2-sidecar

Conversation

@hawkff

@hawkff hawkff commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • Bump the sing-quic replace pin to the current hawkff HEAD. This pulls in
    configurable BBR profiles, a random hop interval, shared QUIC options, realm
    support, gecko obfs on the migrated base, and a salamander data-race fix, built
    on sing v0.8.10 + quic-go v0.59-mod.5.
  • The shared-QUIC-options refactor moves the per-window / MTU knobs into
    qtls.QUICOptions; the matching sing-box change is pinned via COMMIT_SING_BOX
    (buildScript/lib/core/get_source_env.sh).
  • Drop the bundled Hysteria2 client binary. Its features now run in the native
    core, so the binary is no longer reachable. Removed: the build step + env +
    cache-key segment + ABI checks across all workflows, the native-executable
    entry, the plugin mapping, the dead config builder, and the redundant external
    plugin branch.
  • canUseSingBox() now routes all Hysteria2 to the native outbound and reserves
    the external plugin path for the Hysteria1 transports. Hysteria1 support is
    unchanged.

Testing

  • go mod tidy in libcore/; the version triple is unchanged.
  • Local :app:compileOssDebugKotlin and spotlessKotlinCheck pass.
  • Full Depot build-apk run is green end-to-end: libcore built from source
    against the new pins (gomobile bind OK), sidecars built without the dropped
    binary, app compiled + APK assembled and signed (BUILD SUCCESSFUL in ~3m).
  • Unit tests run on CI (local JDK is too new for the test runner's bytecode
    instrumentation; test bodies pass, only teardown trips).

Notes

  • Companion change: hawkff/sing-box feat/sing-quic-shared-quic-options
    (adopts the shared QUIC options); pinned here via COMMIT_SING_BOX.

Greptile Summary

This PR drops the bundled Hysteria2 client binary (libhysteria2.so) now that its functionality is handled natively by the sing-box core, and bumps the sing-quic replace pin to pull in BBR profiles, a random hop interval, shared QUIC options, realm support, gecko obfs, and a salamander data-race fix.

  • Hysteria2 binary removal: Build scripts, cache keys, artifact-verification loops, Executable.kt, and PluginManager.kt all have their hysteria2 / libhysteria2.so references removed; the dead buildHysteria2SidecarConfig function is deleted.
  • Routing logic: canUseSingBox() now explicitly returns true for all Hysteria2 beans (previously implicit because protocol always defaulted to PROTOCOL_UDP for v2), and ConfigBuilder.kt hardcodes \"hysteria-plugin\" for the HysteriaBean external-plugin branch (a code path only reachable for Hysteria1 non-UDP transports).
  • Dependency pins: libcore/go.mod advances sing-quic to v0.6.2-0.20260630192917-42e8810bc4b8; get_source_env.sh bumps COMMIT_SING_BOX to 8bac84d6… (version 1.13.13-10-g8bac84d6).

Confidence Score: 5/5

All changes are self-consistent and fully tested according to the PR description; no functional regressions are expected.

The removal of the Hysteria2 sidecar is complete and consistent across all five workflow files, Executable.kt, PluginManager.kt, and the build scripts. The canUseSingBox() rewrite makes an implicit invariant (Hysteria2 always had protocol == PROTOCOL_UDP) explicit, producing identical runtime behaviour. The ConfigBuilder hardcoding of "hysteria-plugin" is safe because that branch is only reachable when needExternal() is true, which requires canUseSingBox() == false, which cannot happen for Hysteria2. Dead code (buildHysteria2SidecarConfig) is cleanly removed. The go.mod and sing-box commit pins advance together as a matched pair.

No files require special attention. The logic change in HysteriaFmt.kt is worth a quick read to confirm the canUseSingBox equivalence, but it is correct.

Important Files Changed

Filename Overview
app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt canUseSingBox() now explicitly returns true for Hysteria2 (was implicit via protocol defaulting to PROTOCOL_UDP); Hysteria1 behaviour unchanged. Dead buildHysteria2SidecarConfig builder removed cleanly.
app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt Plugin-ID lookup for HysteriaBean hardcoded to "hysteria-plugin" — safe because this code path is only reachable when needExternal() is true, which requires canUseSingBox() == false, which can only happen for Hysteria1 non-UDP transports.
app/src/main/java/io/nekohasekai/sagernet/plugin/PluginManager.kt hysteria2-plugin → libhysteria2.so mapping removed; remaining entries (hysteria-plugin, mieru-plugin, etc.) are unaffected.
buildScript/lib/core/get_source_env.sh COMMIT_SING_BOX and VERSION_SING_BOX bumped to the companion sing-box commit that adopts the shared QUIC options refactor.
libcore/go.mod sing-quic replace pin advanced one week to 20260630 HEAD; go.sum updated accordingly.
.github/workflows/build.yml Hysteria2 build step, env var, sidecars-status hash input, cache-key segment, and ABI verification all removed consistently.

Reviews (1): Last reviewed commit: "core: bump sing-quic pin; drop the Hyste..." | Re-trigger Greptile

Bump the sing-quic replace pin to the current hawkff HEAD (configurable
BBR profiles, random hop interval, shared QUIC options, realm support,
gecko obfs on the migrated base, and a salamander data-race fix; built on
sing v0.8.10 + quic-go v0.59-mod.5). The shared-QUIC-options refactor moves
the per-window / MTU knobs into qtls.QUICOptions; the matching sing-box
change is pinned via COMMIT_SING_BOX.

Hysteria2 (incl. gecko obfs) runs natively in the core, so the bundled
client binary is no longer reachable. Remove its build step, env, cache-key
segment and ABI checks across the workflows, the native-executable entry,
the plugin mapping, the dead config builder, and the now-redundant external
plugin branch. canUseSingBox() now routes all Hysteria2 to the native
outbound and reserves the external path for the Hysteria1 transports.
Hysteria1 support is unchanged.
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Note: range_5422f22f88d4 appears under dependency updates as the relevant standalone checkpoint.

Walkthrough

This PR removes the Hysteria2 sidecar entirely: deletes the build script, removes the native plugin mapping and sidecar config generator, simplifies Hysteria plugin/protocol selection logic, drops libhysteria2.so from process termination and CI verification, and updates GitHub/Depot CI workflows. It also bumps pinned sing-box and sing-quic dependency versions.

Changes

Hysteria2 Sidecar Removal

Layer / File(s) Summary
App-side plugin/config simplification
app/.../fmt/hysteria/HysteriaFmt.kt, app/.../fmt/ConfigBuilder.kt, app/.../plugin/PluginManager.kt, app/.../bg/Executable.kt
buildHysteria2SidecarConfig is removed, pluginId resolution for HysteriaBean always returns "hysteria-plugin", canUseSingBox() is simplified, hysteria2-plugin mapping is dropped from native library resolution, and libhysteria2.so is removed from the killAll executable set.
Build script removal
buildScript/lib/hysteria2.sh
The script that downloaded/verified Hysteria2 native binaries is deleted entirely.
CI/CD workflow updates
.depot/workflows/build-apk.yml, .github/workflows/build.yml, .github/workflows/ci.yml, .github/workflows/preview.yml, .github/workflows/release.yml
HYSTERIA_VERSION env vars, hysteria2.sh cache-hash inputs, Hysteria2 download/build steps, and libhysteria2.so from artifact verification lists are removed across all five workflows.

Dependency Pin Updates

Layer / File(s) Summary
Version bumps
buildScript/lib/core/get_source_env.sh, libcore/go.mod
COMMIT_SING_BOX/VERSION_SING_BOX are bumped to a newer pinned commit, and the sing-quic replace directive is updated to a newer pseudo-version.

Sequence Diagram(s)

Not applicable — these changes are configuration/build-pipeline removals and simplification of conditional logic, not new multi-component control flow.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Possibly related PRs

  • hawkff/NekoBoxForAndroid#17: Original PR that introduced the Hysteria2 sidecar build script, plugin resolution, and config generation now being removed.
  • hawkff/NekoBoxForAndroid#26: Implements the related shift to native sing-box handling for Hysteria2 Gecko obfs, touching the same HysteriaFmt.kt code paths.
  • hawkff/NekoBoxForAndroid#35: Adds HY2 options relying on buildHysteria2SidecarConfig/hysteria2-plugin, conflicting directly with this PR's removal of those same code paths.

Poem

Hop, hop, the sidecar's gone,
No more libhysteria2.so to don.
One plugin path, clean and neat,
Sing-box pinned to a fresher beat.
🐰 Twitching nose at CI green —
The build run's never been so lean!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main changes: bumping sing-quic and removing the Hysteria2 client binary.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description accurately matches the changes: it covers the sing-quic pin bump, sing-box pin sync, Hysteria2 removal, and routing logic updates.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt`:
- Around line 378-383: Hysteria2 is now routed through the native sing-box
outbound, but Hysteria2-specific profile fields are still being parsed and shown
without being serialized. Update the Hysteria2 builder in HysteriaFmt/Hysteria2
to either emit disableMtuDiscovery, streamReceiveWindow, and
connectionReceiveWindow into the native outbound config or clear/hide those
settings before they reach that path, so the values are not silently dropped
when canUseSingBox() returns true for protocolVersion == 2.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0faa0a74-76b5-4712-93f0-9f02cab39bb7

📥 Commits

Reviewing files that changed from the base of the PR and between 1f068fe and bc12e77.

⛔ Files ignored due to path filters (1)
  • libcore/go.sum is excluded by !**/*.sum
📒 Files selected for processing (12)
  • .depot/workflows/build-apk.yml
  • .github/workflows/build.yml
  • .github/workflows/ci.yml
  • .github/workflows/preview.yml
  • .github/workflows/release.yml
  • app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt
  • app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt
  • app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt
  • app/src/main/java/io/nekohasekai/sagernet/plugin/PluginManager.kt
  • buildScript/lib/core/get_source_env.sh
  • buildScript/lib/hysteria2.sh
  • libcore/go.mod
💤 Files with no reviewable changes (3)
  • app/src/main/java/io/nekohasekai/sagernet/plugin/PluginManager.kt
  • buildScript/lib/hysteria2.sh
  • app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt

Comment on lines +378 to +383
// Hysteria2 always uses the native sing-box outbound; the faketcp / wechat-video
// transports are a Hysteria1-only concept, and gecko obfs is handled natively by
// this fork's core (via the hawkff/sing-quic gecko backport).
if (protocolVersion == 2) return true
// Hysteria1 falls back to the external plugin for the non-UDP transports.
return protocol == HysteriaBean.PROTOCOL_UDP

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fmt=$(fd -p 'HysteriaFmt.kt' app/src/main/java | head -n1)
bean=$(fd -p 'HysteriaBean.kt' app/src/main/java | head -n1)
proxy=$(fd -p 'ProxyEntity.kt' app/src/main/java | head -n1)

echo "=== canUseSingBox() and Hysteria2 outbound ==="
nl -ba "$fmt" | sed -n '377,480p'

echo
echo "=== Hysteria bean fields still present ==="
rg -n -C2 'disableMtuDiscovery|streamReceiveWindow|connectionReceiveWindow|protocolVersion' "$bean"

echo
echo "=== downstream needExternal() selection ==="
rg -n -C2 'TYPE_HYSTERIA|needExternal\(' "$proxy"

echo
echo "=== other references to the affected Hysteria fields ==="
rg -n -C2 'disableMtuDiscovery|streamReceiveWindow|connectionReceiveWindow' app/src/main/java

Repository: hawkff/NekoBoxForAndroid

Length of output: 249


🏁 Script executed:

#!/bin/bash
set -euo pipefail

fmt=$(fd -p 'HysteriaFmt.kt' app/src/main/java | head -n1)
bean=$(fd -p 'HysteriaBean.kt' app/src/main/java | head -n1)
proxy=$(fd -p 'ProxyEntity.kt' app/src/main/java | head -n1)

echo "FMT=$fmt"
echo "BEAN=$bean"
echo "PROXY=$proxy"

echo
echo "=== HysteriaFmt.kt relevant section ==="
sed -n '370,490p' "$fmt"

echo
echo "=== HysteriaBean.kt relevant declarations ==="
sed -n '1,260p' "$bean"

echo
echo "=== ProxyEntity.kt relevant selection logic ==="
sed -n '330,390p' "$proxy"

echo
echo "=== Other references to affected fields ==="
rg -n -C2 'disableMtuDiscovery|streamReceiveWindow|connectionReceiveWindow' app/src/main/java

Repository: hawkff/NekoBoxForAndroid

Length of output: 5545


🏁 Script executed:

#!/bin/bash
set -euo pipefail

fmt=$(fd -p 'HysteriaFmt.kt' app/src/main/java | head -n1)
bean=$(fd -p 'HysteriaBean.kt' app/src/main/java | head -n1)
proxy=$(fd -p 'ProxyEntity.kt' app/src/main/java | head -n1)

printf 'FMT=%s\nBEAN=%s\nPROXY=%s\n' "$fmt" "$bean" "$proxy"

echo
echo "=== HysteriaFmt.kt relevant section ==="
sed -n '370,490p' "$fmt" | cat -n

echo
echo "=== HysteriaBean.kt relevant declarations ==="
sed -n '1,260p' "$bean" | cat -n

echo
echo "=== ProxyEntity.kt relevant selection logic ==="
sed -n '330,390p' "$proxy" | cat -n

echo
echo "=== Other references to affected fields ==="
rg -n -C2 'disableMtuDiscovery|streamReceiveWindow|connectionReceiveWindow' app/src/main/java

Repository: hawkff/NekoBoxForAndroid

Length of output: 6392


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the bean definition and all references to the three fields.
bean=$(rg -l --hidden --glob '*.kt' 'class HysteriaBean|data class HysteriaBean' app/src/main/java | head -n1)

echo "BEAN=$bean"

echo
echo "=== Bean definition ==="
sed -n '1,260p' "$bean" | cat -n

echo
echo "=== Field references across the app ==="
rg -n -C2 'disableMtuDiscovery|streamReceiveWindow|connectionReceiveWindow' app/src/main/java

echo
echo "=== Hysteria-related UI / serialization references ==="
rg -n -C2 'Hysteria2|hysteria2ObfsType|disableMtuDiscovery|streamReceiveWindow|connectionReceiveWindow' app/src/main/java

Repository: hawkff/NekoBoxForAndroid

Length of output: 162


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Candidate Hysteria files ==="
fd -a -i 'hysteria' app/src/main/java

echo
echo "=== Definitions / references for the three fields ==="
rg -n -C2 'disableMtuDiscovery|streamReceiveWindow|connectionReceiveWindow' app/src/main/java

echo
echo "=== Hysteria bean class declarations ==="
rg -n -C2 'class HysteriaBean|data class HysteriaBean' app/src/main/java

Repository: hawkff/NekoBoxForAndroid

Length of output: 12480


Hysteria2 native path still drops profile settings
canUseSingBox() now sends every v2 profile through the native outbound, but the Hysteria2 builder still omits disableMtuDiscovery, streamReceiveWindow, and connectionReceiveWindow. Those values are still parsed, stored, and exposed in the UI, so they’ll be silently ignored for Hysteria2 profiles unless the native outbound starts serializing them or the fields are hidden/cleared first.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt` around
lines 378 - 383, Hysteria2 is now routed through the native sing-box outbound,
but Hysteria2-specific profile fields are still being parsed and shown without
being serialized. Update the Hysteria2 builder in HysteriaFmt/Hysteria2 to
either emit disableMtuDiscovery, streamReceiveWindow, and
connectionReceiveWindow into the native outbound config or clear/hide those
settings before they reach that path, so the values are not silently dropped
when canUseSingBox() returns true for protocolVersion == 2.

@hawkff

hawkff commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

Declining this finding on merit (pre-existing, not a regression in this PR):

  • For protocolVersion 2 the settings screen hides streamReceiveWindow,
    connectionReceiveWindow and disableMtuDiscovery (HysteriaSettingsActivity.updateVersion(2)
    sets all three isVisible = false), so they are not exposed in the UI for v2.
  • The v2 parsers (parseHysteria2 / parseHysteria2Json) never populate these
    fields, so a v2 bean keeps their defaults (0 / false); there is nothing to drop.
  • The native v2 builder intentionally omits them, and this predates this PR — v2 UDP
    profiles already used the native outbound before this change. canUseSingBox() was
    only tightened to keep all v2 on the native path; it did not change which fields are
    emitted.

No code change needed.

@hawkff hawkff merged commit 9b0ca46 into main Jun 30, 2026
7 checks passed
@hawkff hawkff deleted the chore/sing-quic-bump-drop-hy2-sidecar branch June 30, 2026 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant