github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/common/badjsonmerge/merge.go (about) 1 package badjsonmerge 2 3 import ( 4 "encoding/json" 5 "reflect" 6 7 "github.com/inazumav/sing-box/common/badjson" 8 "github.com/inazumav/sing-box/option" 9 E "github.com/sagernet/sing/common/exceptions" 10 ) 11 12 func MergeOptions(source option.Options, destination option.Options) (option.Options, error) { 13 rawSource, err := json.Marshal(source) 14 if err != nil { 15 return option.Options{}, E.Cause(err, "marshal source") 16 } 17 rawDestination, err := json.Marshal(destination) 18 if err != nil { 19 return option.Options{}, E.Cause(err, "marshal destination") 20 } 21 rawMerged, err := MergeJSON(rawSource, rawDestination) 22 if err != nil { 23 return option.Options{}, E.Cause(err, "merge options") 24 } 25 var merged option.Options 26 err = json.Unmarshal(rawMerged, &merged) 27 if err != nil { 28 return option.Options{}, E.Cause(err, "unmarshal merged options") 29 } 30 return merged, nil 31 } 32 33 func MergeJSON(rawSource json.RawMessage, rawDestination json.RawMessage) (json.RawMessage, error) { 34 source, err := badjson.Decode(rawSource) 35 if err != nil { 36 return nil, E.Cause(err, "decode source") 37 } 38 destination, err := badjson.Decode(rawDestination) 39 if err != nil { 40 return nil, E.Cause(err, "decode destination") 41 } 42 merged, err := mergeJSON(source, destination) 43 if err != nil { 44 return nil, err 45 } 46 return json.Marshal(merged) 47 } 48 49 func mergeJSON(anySource any, anyDestination any) (any, error) { 50 switch destination := anyDestination.(type) { 51 case badjson.JSONArray: 52 switch source := anySource.(type) { 53 case badjson.JSONArray: 54 destination = append(destination, source...) 55 default: 56 destination = append(destination, source) 57 } 58 return destination, nil 59 case *badjson.JSONObject: 60 switch source := anySource.(type) { 61 case *badjson.JSONObject: 62 for _, entry := range source.Entries() { 63 oldValue, loaded := destination.Get(entry.Key) 64 if loaded { 65 var err error 66 entry.Value, err = mergeJSON(entry.Value, oldValue) 67 if err != nil { 68 return nil, E.Cause(err, "merge object item ", entry.Key) 69 } 70 } 71 destination.Put(entry.Key, entry.Value) 72 } 73 default: 74 return nil, E.New("cannot merge json object into ", reflect.TypeOf(destination)) 75 } 76 return destination, nil 77 default: 78 return destination, nil 79 } 80 }