github.com/xxRanger/go-ethereum@v1.8.23/swarm/storage/feed/feed.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  	"hash"
    21  	"unsafe"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/common/hexutil"
    25  	"github.com/ethereum/go-ethereum/swarm/storage"
    26  )
    27  
    28  // Feed represents a particular user's stream of updates on a topic
    29  type Feed struct {
    30  	Topic Topic          `json:"topic"`
    31  	User  common.Address `json:"user"`
    32  }
    33  
    34  // Feed layout:
    35  // TopicLength bytes
    36  // userAddr common.AddressLength bytes
    37  const feedLength = TopicLength + common.AddressLength
    38  
    39  // mapKey calculates a unique id for this feed. Used by the cache map in `Handler`
    40  func (f *Feed) mapKey() uint64 {
    41  	serializedData := make([]byte, feedLength)
    42  	f.binaryPut(serializedData)
    43  	hasher := hashPool.Get().(hash.Hash)
    44  	defer hashPool.Put(hasher)
    45  	hasher.Reset()
    46  	hasher.Write(serializedData)
    47  	hash := hasher.Sum(nil)
    48  	return *(*uint64)(unsafe.Pointer(&hash[0]))
    49  }
    50  
    51  // binaryPut serializes this feed instance into the provided slice
    52  func (f *Feed) binaryPut(serializedData []byte) error {
    53  	if len(serializedData) != feedLength {
    54  		return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize feed. Expected %d, got %d", feedLength, len(serializedData))
    55  	}
    56  	var cursor int
    57  	copy(serializedData[cursor:cursor+TopicLength], f.Topic[:TopicLength])
    58  	cursor += TopicLength
    59  
    60  	copy(serializedData[cursor:cursor+common.AddressLength], f.User[:])
    61  	cursor += common.AddressLength
    62  
    63  	return nil
    64  }
    65  
    66  // binaryLength returns the expected size of this structure when serialized
    67  func (f *Feed) binaryLength() int {
    68  	return feedLength
    69  }
    70  
    71  // binaryGet restores the current instance from the information contained in the passed slice
    72  func (f *Feed) binaryGet(serializedData []byte) error {
    73  	if len(serializedData) != feedLength {
    74  		return NewErrorf(ErrInvalidValue, "Incorrect slice size to read feed. Expected %d, got %d", feedLength, len(serializedData))
    75  	}
    76  
    77  	var cursor int
    78  	copy(f.Topic[:], serializedData[cursor:cursor+TopicLength])
    79  	cursor += TopicLength
    80  
    81  	copy(f.User[:], serializedData[cursor:cursor+common.AddressLength])
    82  	cursor += common.AddressLength
    83  
    84  	return nil
    85  }
    86  
    87  // Hex serializes the feed to a hex string
    88  func (f *Feed) Hex() string {
    89  	serializedData := make([]byte, feedLength)
    90  	f.binaryPut(serializedData)
    91  	return hexutil.Encode(serializedData)
    92  }
    93  
    94  // FromValues deserializes this instance from a string key-value store
    95  // useful to parse query strings
    96  func (f *Feed) FromValues(values Values) (err error) {
    97  	topic := values.Get("topic")
    98  	if topic != "" {
    99  		if err := f.Topic.FromHex(values.Get("topic")); err != nil {
   100  			return err
   101  		}
   102  	} else { // see if the user set name and relatedcontent
   103  		name := values.Get("name")
   104  		relatedContent, _ := hexutil.Decode(values.Get("relatedcontent"))
   105  		if len(relatedContent) > 0 {
   106  			if len(relatedContent) < storage.AddressLength {
   107  				return NewErrorf(ErrInvalidValue, "relatedcontent field must be a hex-encoded byte array exactly %d bytes long", storage.AddressLength)
   108  			}
   109  			relatedContent = relatedContent[:storage.AddressLength]
   110  		}
   111  		f.Topic, err = NewTopic(name, relatedContent)
   112  		if err != nil {
   113  			return err
   114  		}
   115  	}
   116  	f.User = common.HexToAddress(values.Get("user"))
   117  	return nil
   118  }
   119  
   120  // AppendValues serializes this structure into the provided string key-value store
   121  // useful to build query strings
   122  func (f *Feed) AppendValues(values Values) {
   123  	values.Set("topic", f.Topic.Hex())
   124  	values.Set("user", f.User.Hex())
   125  }