From 36b0f2e91abfe8b0bb8dec8bca157d4106b8d40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 10 Dec 2023 22:57:28 +0800 Subject: [PATCH] Improve configuration merge --- cmd/sing-box/cmd_run.go | 13 +++++++++---- experimental/libbox/config.go | 3 +-- option/config.go | 18 ++++++------------ 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/cmd/sing-box/cmd_run.go b/cmd/sing-box/cmd_run.go index d76d3b9c..568ce1b1 100644 --- a/cmd/sing-box/cmd_run.go +++ b/cmd/sing-box/cmd_run.go @@ -17,6 +17,7 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json/badjson" "github.com/spf13/cobra" @@ -56,8 +57,7 @@ func readConfigAt(path string) (*OptionsEntry, error) { if err != nil { return nil, E.Cause(err, "read config at ", path) } - var options option.Options - err = options.UnmarshalJSON(configContent) + options, err := json.UnmarshalExtended[option.Options](configContent) if err != nil { return nil, E.Cause(err, "decode config at ", path) } @@ -107,13 +107,18 @@ func readConfigAndMerge() (option.Options, error) { if len(optionsList) == 1 { return optionsList[0].options, nil } - var mergedOptions option.Options + var mergedMessage json.RawMessage for _, options := range optionsList { - mergedOptions, err = badjson.Merge(options.options, mergedOptions) + mergedMessage, err = badjson.MergeJSON(options.options.RawMessage, mergedMessage) if err != nil { return option.Options{}, E.Cause(err, "merge config at ", options.path) } } + var mergedOptions option.Options + err = mergedOptions.UnmarshalJSON(mergedMessage) + if err != nil { + return option.Options{}, E.Cause(err, "unmarshal merged config") + } return mergedOptions, nil } diff --git a/experimental/libbox/config.go b/experimental/libbox/config.go index e72dc401..42fc878f 100644 --- a/experimental/libbox/config.go +++ b/experimental/libbox/config.go @@ -20,8 +20,7 @@ import ( ) func parseConfig(configContent string) (option.Options, error) { - var options option.Options - err := options.UnmarshalJSON([]byte(configContent)) + options, err := json.UnmarshalExtended[option.Options]([]byte(configContent)) if err != nil { return option.Options{}, E.Cause(err, "decode config") } diff --git a/option/config.go b/option/config.go index 3cec5520..3f5d7602 100644 --- a/option/config.go +++ b/option/config.go @@ -2,13 +2,12 @@ package option import ( "bytes" - "strings" - E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/json" ) type _Options struct { + RawMessage json.RawMessage `json:"-"` Schema string `json:"$schema,omitempty"` Log *LogOptions `json:"log,omitempty"` DNS *DNSOptions `json:"dns,omitempty"` @@ -22,19 +21,14 @@ type _Options struct { type Options _Options func (o *Options) UnmarshalJSON(content []byte) error { - decoder := json.NewDecoder(json.NewCommentFilter(bytes.NewReader(content))) + decoder := json.NewDecoder(bytes.NewReader(content)) decoder.DisallowUnknownFields() err := decoder.Decode((*_Options)(o)) - if err == nil { - return nil + if err != nil { + return err } - if syntaxError, isSyntaxError := err.(*json.SyntaxError); isSyntaxError { - prefix := string(content[:syntaxError.Offset]) - row := strings.Count(prefix, "\n") + 1 - column := len(prefix) - strings.LastIndex(prefix, "\n") - 1 - return E.Extend(syntaxError, "row ", row, ", column ", column) - } - return err + o.RawMessage = content + return nil } type LogOptions struct {