github.com/codingfuture/orig-energi3@v0.8.4/swarm/storage/feed/topic.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package feed 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 24 "github.com/ethereum/go-ethereum/common/bitutil" 25 "github.com/ethereum/go-ethereum/common/hexutil" 26 "github.com/ethereum/go-ethereum/swarm/storage" 27 ) 28 29 // TopicLength establishes the max length of a topic string 30 const TopicLength = storage.AddressLength 31 32 // Topic represents what a feed is about 33 type Topic [TopicLength]byte 34 35 // ErrTopicTooLong is returned when creating a topic with a name/related content too long 36 var ErrTopicTooLong = fmt.Errorf("Topic is too long. Max length is %d", TopicLength) 37 38 // NewTopic creates a new topic from a provided name and "related content" byte array, 39 // merging the two together. 40 // If relatedContent or name are longer than TopicLength, they will be truncated and an error returned 41 // name can be an empty string 42 // relatedContent can be nil 43 func NewTopic(name string, relatedContent []byte) (topic Topic, err error) { 44 if relatedContent != nil { 45 contentLength := len(relatedContent) 46 if contentLength > TopicLength { 47 contentLength = TopicLength 48 err = ErrTopicTooLong 49 } 50 copy(topic[:], relatedContent[:contentLength]) 51 } 52 nameBytes := []byte(name) 53 nameLength := len(nameBytes) 54 if nameLength > TopicLength { 55 nameLength = TopicLength 56 err = ErrTopicTooLong 57 } 58 bitutil.XORBytes(topic[:], topic[:], nameBytes[:nameLength]) 59 return topic, err 60 } 61 62 // Hex will return the topic encoded as an hex string 63 func (t *Topic) Hex() string { 64 return hexutil.Encode(t[:]) 65 } 66 67 // FromHex will parse a hex string into this Topic instance 68 func (t *Topic) FromHex(hex string) error { 69 bytes, err := hexutil.Decode(hex) 70 if err != nil || len(bytes) != len(t) { 71 return NewErrorf(ErrInvalidValue, "Cannot decode topic") 72 } 73 copy(t[:], bytes) 74 return nil 75 } 76 77 // Name will try to extract the topic name out of the Topic 78 func (t *Topic) Name(relatedContent []byte) string { 79 nameBytes := *t 80 if relatedContent != nil { 81 contentLength := len(relatedContent) 82 if contentLength > TopicLength { 83 contentLength = TopicLength 84 } 85 bitutil.XORBytes(nameBytes[:], t[:], relatedContent[:contentLength]) 86 } 87 z := bytes.IndexByte(nameBytes[:], 0) 88 if z < 0 { 89 z = TopicLength 90 } 91 return string(nameBytes[:z]) 92 93 } 94 95 // UnmarshalJSON implements the json.Unmarshaller interface 96 func (t *Topic) UnmarshalJSON(data []byte) error { 97 var hex string 98 json.Unmarshal(data, &hex) 99 return t.FromHex(hex) 100 } 101 102 // MarshalJSON implements the json.Marshaller interface 103 func (t *Topic) MarshalJSON() ([]byte, error) { 104 return json.Marshal(t.Hex()) 105 }