feat(overwrite): add app-level providers, scripts and validated custom proxies

Providers and custom proxies stay behind feature flags.

Changelog: Invalid override warnings and rule presets
This commit is contained in:
chen08209
2026-09-25 03:56:59 +08:00
parent a390a42032
commit 46fb7fee04
76 changed files with 7370 additions and 1171 deletions
+1
View File
@@ -171,6 +171,7 @@ const (
crashMethod CoreMethod = "crash"
setupConfigMethod CoreMethod = "setupConfig"
getConfigMethod CoreMethod = "getConfig"
dumpRuleSetMethod CoreMethod = "dumpRuleSet"
clearEffectMethod CoreMethod = "clearEffect"
watchRouteMethod CoreMethod = "watchRoute"
)
+20
View File
@@ -31,10 +31,12 @@ import (
"github.com/metacubex/mihomo/config"
"github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/features"
cp "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/dns"
"github.com/metacubex/mihomo/hub/executor"
"github.com/metacubex/mihomo/listener"
"github.com/metacubex/mihomo/log"
rp "github.com/metacubex/mihomo/rules/provider"
"github.com/metacubex/mihomo/tunnel"
"github.com/metacubex/mihomo/tunnel/statistic"
)
@@ -778,6 +780,24 @@ func handleGetConfig(path string) (*config.RawConfig, error) {
return config.UnmarshalRawConfig(buf)
}
func handleDumpRuleSet(path string) (string, error) {
buf, err := os.ReadFile(path)
if err != nil {
return "", err
}
mrsBehaviors := []cp.RuleBehavior{cp.Domain, cp.IPCIDR}
var errs []error
for _, behavior := range mrsBehaviors {
var text strings.Builder
err := rp.ConvertToMrs(buf, behavior, cp.MrsRule, &text)
if err == nil {
return text.String(), nil
}
errs = append(errs, err)
}
return "", errors.Join(errs...)
}
func handleCrash() {
panic("handle invoke crash")
}
+39
View File
@@ -30,6 +30,7 @@ import (
cp "github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/dns"
"github.com/metacubex/mihomo/log"
rp "github.com/metacubex/mihomo/rules/provider"
"github.com/metacubex/mihomo/tunnel"
D "github.com/miekg/dns"
)
@@ -1107,3 +1108,41 @@ func TestProxyViewKeepsWhatTheHostReads(t *testing.T) {
t.Error("the view still carries delay history")
}
}
func TestDumpRuleSetReadsEitherMrsBehavior(t *testing.T) {
cases := []struct {
behavior cp.RuleBehavior
source string
want string
}{
{cp.Domain, "example.com\n+.example.org\n", "+.example.org\nexample.com\n"},
{cp.IPCIDR, "10.0.0.0/8\n192.168.1.0/24\n", "10.0.0.0/8\n192.168.1.0/24\n"},
}
for _, c := range cases {
var mrs strings.Builder
if err := rp.ConvertToMrs([]byte(c.source), c.behavior, cp.TextRule, &mrs); err != nil {
t.Fatalf("encode %s: %v", c.behavior, err)
}
path := filepath.Join(t.TempDir(), "rules.mrs")
if err := os.WriteFile(path, []byte(mrs.String()), 0o644); err != nil {
t.Fatal(err)
}
got, err := handleDumpRuleSet(path)
if err != nil {
t.Fatalf("dump %s: %v", c.behavior, err)
}
if got != c.want {
t.Fatalf("dump %s = %q, want %q", c.behavior, got, c.want)
}
}
}
func TestDumpRuleSetRejectsText(t *testing.T) {
path := filepath.Join(t.TempDir(), "rules.txt")
if err := os.WriteFile(path, []byte("example.com\n"), 0o644); err != nil {
t.Fatal(err)
}
if _, err := handleDumpRuleSet(path); err == nil {
t.Fatal("dumping a text rule set succeeded")
}
}
+10
View File
@@ -200,6 +200,16 @@ var methodHandlers = map[CoreMethod]methodHandler{
}
response.success(rawConfig)
}),
dumpRuleSetMethod: withArguments(func(path *string, response MethodResponse) {
safeGo(response, func() {
text, err := handleDumpRuleSet(*path)
if err != nil {
response.failure("core_error", err.Error(), nil)
return
}
response.success(text)
})
}),
getProxiesMethod: withoutArguments(func(response MethodResponse) {
response.success(handleGetProxies())
}),