Conversation
- Implement std FromStr and Display for Protocol; remove custom from_str and the thin SourceProtocol/OutputProtocol aliases - Drop cli::OutputFormat: a no-arg enum that was only used to double-dispatch what Protocol::default_output_format already encodes - Registry uses IndexMap so iteration order matches registration order (deterministic logging and format-detection fallback) - Introduce FORMAT_SUBSCRIPTION/FORMAT_PLAIN constants; route detect.rs and loader.rs through them and Protocol::as_format_str to kill scattered "clash"/"singbox"/"v2ray" literals - TemplateEngine auto-numbers unnamed sources (source_N) instead of collapsing them to a shared "default" key
Commands: - Each subcommand becomes a dedicated Args struct (ConvertArgs, ValidateArgs, TemplateArgs) via clap's #[derive(Args)]. Handlers receive typed args directly instead of pattern-matching the whole Commands enum and returning "Expected X" errors that can't actually fire — main.rs has already dispatched. - AppConfig::merge_cli_params collapses into merge_convert_args (only the Convert subcommand has overridable fields). URL handling: - Drop the hand-rolled append_flag_to_url / get_flag_param_value / update_flag_param trio. url::Url does it correctly including fragment preservation and proper percent-encoding. - New unit tests cover add/replace/override/fragment cases. Sing-box DNS normalization: - Move the legacy-DNS fallback out of SourceLoader and into SingboxFormat::parse_config where it belongs. The loader no longer knows about singbox internals, removing a backwards-pointing cross-module call.
Move the parsed-source model (Source, Config enum, ProxyServer
extraction) from utils/source/parser.rs to protocols/source.rs.
The Config variants wrap protocol-specific configs (clash::Config,
singbox::Config, v2ray::Config) and the extraction code reaches deep
into protocol types — this is protocol-layer logic, not a generic
util. Keeping it in utils forced `utils -> protocols` edges
throughout the codebase (utils becomes protocol-aware, inverting the
dependency arrow).
Now utils stays genuinely generic (parse_helpers only in the source
subtree; the loader remains as IO/orchestration).
No behavior change: type paths update from
`utils::source::parser::{Source,Config}` to `protocols::source::...`
(re-exported at `protocols::{Source,Config}`), and the file moves
via `git mv` preserving history. All 114 tests pass.
ProtocolFormat gains a processor() method returning a 'static ProtocolProcessor reference. Each format (Clash/Singbox/V2Ray) holds its processor as a module-level static so the trait method can hand it out without heap allocation. ProtocolRegistry drops its second map. One registration call per protocol now covers descriptor metadata + parse_config + validate + default template + template processor. Forgetting to register the processor half is no longer possible.
The flat `parameters: HashMap<String, Value>` field was a serde-exposed bag of protocol-specific JSON that duplicated the typed `params: ProxyParams` enum. Two sources of truth, always at risk of drifting apart. Collapse into one: each ProxyParams variant carries its own `extras: HashMap<String, Value>` for raw leftover fields specific to that protocol. ProxyServer::extras() forwards to the variant. - ProxyServer loses the flat parameters field - Each ProxyParams variant (Shadowsocks/Vmess/Trojan/Vless/ Hysteria2/Generic) gains `extras` - Every construction site (source.rs, subscription.rs, tests) now populates extras inside the variant instead of the flat map - Every read site in the three template processors reads through `node.extras()`; pattern-matching downstream on ProxyParams adds `..` to tolerate the new field
Previously SourceMeta.source held the raw user input (e.g.
"https://x/y?type=clash&token=..&flag=..") and downstream code
re-parsed it twice: loader used starts_with("http") to branch,
then sliced at '?' for file paths; URL flag manipulation parsed the
same string again.
Now SourceMeta carries a typed SourceLocation { Url(url::Url) |
File(PathBuf) }, computed once in parse_source_string. The parser
also splits synthetic keys (type/name/flag) from the user's own
URL query params — our keys never reach the remote server, and
with_flag_param operates on url::Url directly without re-parsing.
The raw `source` string is kept purely for log/display output
(tests still assert on it).
NetworkError grows from a single String bag into a structured variant
{ kind: NetworkErrorKind, url: Option<String>, detail: String }:
- Timeout, Connect, Status(u16), Tls, Other
- is_retryable() marks transient failures (timeout, connect, 5xx, 429)
- format_error hints are kind-specific: a 403/401 now points at
User-Agent filtering (the exact failure mode we saw on the
subscription panel) instead of the generic "check your network"
SourceLoader::load_from_url now honors config.retry_count (previously
declared-but-unused) with exponential backoff (250ms, 500ms, 1s,
capped at 4s). 4xx/DNS errors skip the retry loop.
Add wiremock integration tests (tests/url_fetch_test.rs):
- happy-path HTTP fetch + parse
- 403 surfaces as Status(403) variant (regression guard for the
UA-filtering scenario)
- transient 503 is retried and succeeds on the second attempt
- 404 is NOT retried (expect(1) asserts the hit count)
GitHub deprecated Node 20 actions — runners will force Node 24 from June 2nd 2026 and remove Node 20 entirely on September 16th 2026. Move every flagged action to its Node-24 release line: - actions/checkout v4 -> v6 - Swatinem/rust-cache v2.8.2 -> v2.9.1 - actions/upload-artifact v4 -> v7 - actions/download-artifact v4 -> v7 dtolnay/rust-toolchain@v1 and softprops/action-gh-release@v2 were not flagged and stay as-is. Note: upload/download-artifact v5+ require Actions Runner 2.327.1 or newer. GitHub-hosted runners already satisfy this; self-hosted ones need to be up-to-date.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.