1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- package badjsonmerge
- import (
- "encoding/json"
- "reflect"
- "github.com/sagernet/sing-box/common/badjson"
- "github.com/sagernet/sing-box/option"
- E "github.com/sagernet/sing/common/exceptions"
- )
- func MergeOptions(source option.Options, destination option.Options) (option.Options, error) {
- rawSource, err := json.Marshal(source)
- if err != nil {
- return option.Options{}, E.Cause(err, "marshal source")
- }
- rawDestination, err := json.Marshal(destination)
- if err != nil {
- return option.Options{}, E.Cause(err, "marshal destination")
- }
- rawMerged, err := MergeJSON(rawSource, rawDestination)
- if err != nil {
- return option.Options{}, E.Cause(err, "merge options")
- }
- var merged option.Options
- err = json.Unmarshal(rawMerged, &merged)
- if err != nil {
- return option.Options{}, E.Cause(err, "unmarshal merged options")
- }
- return merged, nil
- }
- func MergeJSON(rawSource json.RawMessage, rawDestination json.RawMessage) (json.RawMessage, error) {
- source, err := badjson.Decode(rawSource)
- if err != nil {
- return nil, E.Cause(err, "decode source")
- }
- destination, err := badjson.Decode(rawDestination)
- if err != nil {
- return nil, E.Cause(err, "decode destination")
- }
- merged, err := mergeJSON(source, destination)
- if err != nil {
- return nil, err
- }
- return json.Marshal(merged)
- }
- func mergeJSON(anySource any, anyDestination any) (any, error) {
- switch destination := anyDestination.(type) {
- case badjson.JSONArray:
- switch source := anySource.(type) {
- case badjson.JSONArray:
- destination = append(destination, source...)
- default:
- destination = append(destination, source)
- }
- return destination, nil
- case *badjson.JSONObject:
- switch source := anySource.(type) {
- case *badjson.JSONObject:
- for _, entry := range source.Entries() {
- oldValue, loaded := destination.Get(entry.Key)
- if loaded {
- var err error
- entry.Value, err = mergeJSON(entry.Value, oldValue)
- if err != nil {
- return nil, E.Cause(err, "merge object item ", entry.Key)
- }
- }
- destination.Put(entry.Key, entry.Value)
- }
- default:
- return nil, E.New("cannot merge json object into ", reflect.TypeOf(destination))
- }
- return destination, nil
- default:
- return destination, nil
- }
- }
|