Improve configuration merge

This commit is contained in:
世界 2023-12-10 22:57:28 +08:00
parent 5052e86a5d
commit 7740293a66
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
3 changed files with 17 additions and 19 deletions

View file

@ -17,6 +17,7 @@ import (
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badjson" "github.com/sagernet/sing/common/json/badjson"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -56,8 +57,7 @@ func readConfigAt(path string) (*OptionsEntry, error) {
if err != nil { if err != nil {
return nil, E.Cause(err, "read config at ", path) return nil, E.Cause(err, "read config at ", path)
} }
var options option.Options options, err := json.UnmarshalExtended[option.Options](configContent)
err = options.UnmarshalJSON(configContent)
if err != nil { if err != nil {
return nil, E.Cause(err, "decode config at ", path) return nil, E.Cause(err, "decode config at ", path)
} }
@ -107,13 +107,18 @@ func readConfigAndMerge() (option.Options, error) {
if len(optionsList) == 1 { if len(optionsList) == 1 {
return optionsList[0].options, nil return optionsList[0].options, nil
} }
var mergedOptions option.Options var mergedMessage json.RawMessage
for _, options := range optionsList { for _, options := range optionsList {
mergedOptions, err = badjson.Merge(options.options, mergedOptions) mergedMessage, err = badjson.MergeJSON(options.options.RawMessage, mergedMessage)
if err != nil { if err != nil {
return option.Options{}, E.Cause(err, "merge config at ", options.path) 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 return mergedOptions, nil
} }

View file

@ -3,7 +3,6 @@ package libbox
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/json"
"net/netip" "net/netip"
"os" "os"
@ -15,13 +14,13 @@ import (
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/common/x/list" "github.com/sagernet/sing/common/x/list"
) )
func parseConfig(configContent string) (option.Options, error) { func parseConfig(configContent string) (option.Options, error) {
var options option.Options options, err := json.UnmarshalExtended[option.Options]([]byte(configContent))
err := options.UnmarshalJSON([]byte(configContent))
if err != nil { if err != nil {
return option.Options{}, E.Cause(err, "decode config") return option.Options{}, E.Cause(err, "decode config")
} }

View file

@ -2,13 +2,12 @@ package option
import ( import (
"bytes" "bytes"
"strings"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"
) )
type _Options struct { type _Options struct {
RawMessage json.RawMessage `json:"-"`
Schema string `json:"$schema,omitempty"` Schema string `json:"$schema,omitempty"`
Log *LogOptions `json:"log,omitempty"` Log *LogOptions `json:"log,omitempty"`
DNS *DNSOptions `json:"dns,omitempty"` DNS *DNSOptions `json:"dns,omitempty"`
@ -22,19 +21,14 @@ type _Options struct {
type Options _Options type Options _Options
func (o *Options) UnmarshalJSON(content []byte) error { func (o *Options) UnmarshalJSON(content []byte) error {
decoder := json.NewDecoder(json.NewCommentFilter(bytes.NewReader(content))) decoder := json.NewDecoder(bytes.NewReader(content))
decoder.DisallowUnknownFields() decoder.DisallowUnknownFields()
err := decoder.Decode((*_Options)(o)) err := decoder.Decode((*_Options)(o))
if err == nil { if err != nil {
return nil return err
} }
if syntaxError, isSyntaxError := err.(*json.SyntaxError); isSyntaxError { o.RawMessage = content
prefix := string(content[:syntaxError.Offset]) return nil
row := strings.Count(prefix, "\n") + 1
column := len(prefix) - strings.LastIndex(prefix, "\n") - 1
return E.Extend(syntaxError, "row ", row, ", column ", column)
}
return err
} }
type LogOptions struct { type LogOptions struct {