fusenapi/utils/hash/hash.go
2023-08-08 10:53:28 +08:00

82 lines
1.4 KiB
Go

package hash
import (
"bytes"
"crypto/sha256"
"encoding/json"
"fmt"
"reflect"
"sort"
)
func JsonHashKey(v interface{}) string {
if reflect.TypeOf(v).Kind() == reflect.String {
var obj interface{}
err := json.Unmarshal([]byte(v.(string)), &obj)
if err == nil {
// 反序列化成功,直接替换v
v = obj
}
}
h := sha256.New()
h.Write(marshalOrdered(v))
return fmt.Sprintf("%x", h.Sum(nil))
}
func marshalOrdered(v interface{}) []byte {
switch v := v.(type) {
case map[string]interface{}:
sortedKeys := make([]string, 0, len(v))
for key := range v {
sortedKeys = append(sortedKeys, key)
}
sort.Strings(sortedKeys)
var buf bytes.Buffer
buf.WriteByte('{')
for i, key := range sortedKeys {
if i > 0 {
buf.WriteByte(',')
}
b, err := json.Marshal(key)
if err != nil {
panic(err)
}
buf.Write(b)
buf.WriteByte(':')
b = marshalOrdered(v[key])
buf.Write(b)
}
buf.WriteByte('}')
return buf.Bytes()
case []interface{}:
var buf bytes.Buffer
sort.Slice(v, func(i, j int) bool {
return bytes.Compare(marshalOrdered(v[i]), marshalOrdered(v[j])) == 1
})
buf.WriteByte('[')
for i, val := range v {
if i > 0 {
buf.WriteByte(',')
}
b := marshalOrdered(val)
buf.Write(b)
}
buf.WriteByte(']')
return buf.Bytes()
default:
b, err := json.Marshal(v)
if err != nil {
panic(err)
}
return b
}
}