github.com/0chain/gosdk@v1.17.11/core/util/http_consensus_maps.go (about) 1 package util 2 3 import ( 4 "crypto/sha1" 5 "encoding/hex" 6 "encoding/json" 7 "errors" 8 "net/http" 9 "sort" 10 "strings" 11 ) 12 13 var ErrNilHttpConsensusMaps = errors.New("nil_httpconsensusmaps") 14 15 type HttpConsensusMaps struct { 16 ConsensusThresh int 17 MaxConsensus int 18 19 WinMap map[string]json.RawMessage 20 WinMapConsensus map[string]int 21 22 WinError string 23 WinInfo string 24 } 25 26 func NewHttpConsensusMaps(consensusThresh int) *HttpConsensusMaps { 27 return &HttpConsensusMaps{ 28 ConsensusThresh: consensusThresh, 29 WinMapConsensus: make(map[string]int), 30 } 31 } 32 33 func (c *HttpConsensusMaps) GetValue(name string) (json.RawMessage, bool) { 34 if c == nil || c.WinMap == nil { 35 return nil, false 36 } 37 v, ok := c.WinMap[name] 38 return v, ok 39 } 40 41 func (c *HttpConsensusMaps) Add(statusCode int, respBody string) error { 42 if c == nil { 43 return ErrNilHttpConsensusMaps 44 } 45 if statusCode != http.StatusOK { 46 c.WinError = respBody 47 return nil 48 } 49 50 m, hash, err := c.buildMap(respBody) 51 if err != nil { 52 return err 53 } 54 55 c.WinMapConsensus[hash]++ 56 57 if c.WinMapConsensus[hash] > c.MaxConsensus { 58 c.MaxConsensus = c.WinMapConsensus[hash] 59 c.WinMap = m 60 c.WinInfo = respBody 61 } 62 63 return nil 64 } 65 66 func (c *HttpConsensusMaps) buildMap(respBody string) (map[string]json.RawMessage, string, error) { 67 var m map[string]json.RawMessage 68 err := json.Unmarshal([]byte(respBody), &m) 69 if err != nil { 70 return nil, "", err 71 } 72 73 keys := make([]string, 0, len(m)) 74 75 for k := range m { 76 77 keys = append(keys, k) 78 } 79 sort.Strings(keys) 80 81 sb := strings.Builder{} 82 83 for _, k := range keys { 84 sb.Write(m[k]) 85 sb.WriteString(":") 86 } 87 88 h := sha1.New() 89 h.Write([]byte(sb.String())) 90 hash := h.Sum(nil) 91 92 return m, hex.EncodeToString(hash), nil 93 }