瀏覽代碼

Make `rule_set.format` optional

世界 5 月之前
父節點
當前提交
af1bfe4e3e

+ 9 - 0
cmd/sing-box/cmd_rule_set_match.go

@@ -5,6 +5,7 @@ import (
 	"context"
 	"io"
 	"os"
+	"path/filepath"
 
 	"github.com/sagernet/sing-box/adapter"
 	"github.com/sagernet/sing-box/common/srs"
@@ -56,6 +57,14 @@ func ruleSetMatch(sourcePath string, domain string) error {
 	if err != nil {
 		return E.Cause(err, "read rule-set")
 	}
+	if flagRuleSetMatchFormat == "" {
+		switch filepath.Ext(sourcePath) {
+		case ".json":
+			flagRuleSetMatchFormat = C.RuleSetFormatSource
+		case ".srs":
+			flagRuleSetMatchFormat = C.RuleSetFormatBinary
+		}
+	}
 	var ruleSet option.PlainRuleSetCompat
 	switch flagRuleSetMatchFormat {
 	case C.RuleSetFormatSource:

+ 2 - 0
docs/configuration/rule-set/index.md

@@ -84,6 +84,8 @@ List of [Headless Rule](./headless-rule/).
 
 Format of rule-set file, `source` or `binary`.
 
+Optional when `path` or `url` uses `json` or `srs` as extension.
+
 ### Local Fields
 
 #### path

+ 2 - 0
docs/configuration/rule-set/index.zh.md

@@ -84,6 +84,8 @@ icon: material/new-box
 
 规则集格式, `source` 或 `binary`。
 
+当 `path` 或 `url` 使用 `json` 或 `srs` 作为扩展名时可选。
+
 ### 本地字段
 
 #### path

+ 40 - 4
option/rule_set.go

@@ -1,6 +1,8 @@
 package option
 
 import (
+	"net/url"
+	"path/filepath"
 	"reflect"
 
 	C "github.com/sagernet/sing-box/constant"
@@ -27,6 +29,18 @@ type _RuleSet struct {
 type RuleSet _RuleSet
 
 func (r RuleSet) MarshalJSON() ([]byte, error) {
+	if r.Type != C.RuleSetTypeInline {
+		var defaultFormat string
+		switch r.Type {
+		case C.RuleSetTypeLocal:
+			defaultFormat = ruleSetDefaultFormat(r.LocalOptions.Path)
+		case C.RuleSetTypeRemote:
+			defaultFormat = ruleSetDefaultFormat(r.RemoteOptions.URL)
+		}
+		if r.Format == defaultFormat {
+			r.Format = ""
+		}
+	}
 	var v any
 	switch r.Type {
 	case "", C.RuleSetTypeInline:
@@ -62,7 +76,19 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
 	default:
 		return E.New("unknown rule-set type: " + r.Type)
 	}
+	err = badjson.UnmarshallExcluded(bytes, (*_RuleSet)(r), v)
+	if err != nil {
+		return err
+	}
 	if r.Type != C.RuleSetTypeInline {
+		if r.Format == "" {
+			switch r.Type {
+			case C.RuleSetTypeLocal:
+				r.Format = ruleSetDefaultFormat(r.LocalOptions.Path)
+			case C.RuleSetTypeRemote:
+				r.Format = ruleSetDefaultFormat(r.RemoteOptions.URL)
+			}
+		}
 		switch r.Format {
 		case "":
 			return E.New("missing format")
@@ -73,13 +99,23 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
 	} else {
 		r.Format = ""
 	}
-	err = badjson.UnmarshallExcluded(bytes, (*_RuleSet)(r), v)
-	if err != nil {
-		return err
-	}
 	return nil
 }
 
+func ruleSetDefaultFormat(path string) string {
+	if pathURL, err := url.Parse(path); err == nil {
+		path = pathURL.Path
+	}
+	switch filepath.Ext(path) {
+	case ".json":
+		return C.RuleSetFormatSource
+	case ".srs":
+		return C.RuleSetFormatBinary
+	default:
+		return ""
+	}
+}
+
 type LocalRuleSet struct {
 	Path string `json:"path,omitempty"`
 }