update.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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. package feed
  17. import (
  18. "fmt"
  19. "strconv"
  20. "github.com/ethereum/go-ethereum/swarm/chunk"
  21. )
  22. // ProtocolVersion defines the current version of the protocol that will be included in each update message
  23. const ProtocolVersion uint8 = 0
  24. const headerLength = 8
  25. // Header defines a update message header including a protocol version byte
  26. type Header struct {
  27. Version uint8 // Protocol version
  28. Padding [headerLength - 1]uint8 // reserved for future use
  29. }
  30. // Update encapsulates the information sent as part of a feed update
  31. type Update struct {
  32. Header Header //
  33. ID // Feed Update identifying information
  34. data []byte // actual data payload
  35. }
  36. const minimumUpdateDataLength = idLength + headerLength + 1
  37. const maxUpdateDataLength = chunk.DefaultSize - signatureLength - idLength - headerLength
  38. // binaryPut serializes the feed update information into the given slice
  39. func (r *Update) binaryPut(serializedData []byte) error {
  40. datalength := len(r.data)
  41. if datalength == 0 {
  42. return NewError(ErrInvalidValue, "a feed update must contain data")
  43. }
  44. if datalength > maxUpdateDataLength {
  45. return NewErrorf(ErrInvalidValue, "feed update data is too big (length=%d). Max length=%d", datalength, maxUpdateDataLength)
  46. }
  47. if len(serializedData) != r.binaryLength() {
  48. return NewErrorf(ErrInvalidValue, "slice passed to putBinary must be of exact size. Expected %d bytes", r.binaryLength())
  49. }
  50. var cursor int
  51. // serialize Header
  52. serializedData[cursor] = r.Header.Version
  53. copy(serializedData[cursor+1:headerLength], r.Header.Padding[:headerLength-1])
  54. cursor += headerLength
  55. // serialize ID
  56. if err := r.ID.binaryPut(serializedData[cursor : cursor+idLength]); err != nil {
  57. return err
  58. }
  59. cursor += idLength
  60. // add the data
  61. copy(serializedData[cursor:], r.data)
  62. cursor += datalength
  63. return nil
  64. }
  65. // binaryLength returns the expected number of bytes this structure will take to encode
  66. func (r *Update) binaryLength() int {
  67. return idLength + headerLength + len(r.data)
  68. }
  69. // binaryGet populates this instance from the information contained in the passed byte slice
  70. func (r *Update) binaryGet(serializedData []byte) error {
  71. if len(serializedData) < minimumUpdateDataLength {
  72. return NewErrorf(ErrNothingToReturn, "chunk less than %d bytes cannot be a feed update chunk", minimumUpdateDataLength)
  73. }
  74. dataLength := len(serializedData) - idLength - headerLength
  75. // at this point we can be satisfied that we have the correct data length to read
  76. var cursor int
  77. // deserialize Header
  78. r.Header.Version = serializedData[cursor] // extract the protocol version
  79. copy(r.Header.Padding[:headerLength-1], serializedData[cursor+1:headerLength]) // extract the padding
  80. cursor += headerLength
  81. if err := r.ID.binaryGet(serializedData[cursor : cursor+idLength]); err != nil {
  82. return err
  83. }
  84. cursor += idLength
  85. data := serializedData[cursor : cursor+dataLength]
  86. cursor += dataLength
  87. // now that all checks have passed, copy data into structure
  88. r.data = make([]byte, dataLength)
  89. copy(r.data, data)
  90. return nil
  91. }
  92. // FromValues deserializes this instance from a string key-value store
  93. // useful to parse query strings
  94. func (r *Update) FromValues(values Values, data []byte) error {
  95. r.data = data
  96. version, _ := strconv.ParseUint(values.Get("protocolVersion"), 10, 32)
  97. r.Header.Version = uint8(version)
  98. return r.ID.FromValues(values)
  99. }
  100. // AppendValues serializes this structure into the provided string key-value store
  101. // useful to build query strings
  102. func (r *Update) AppendValues(values Values) []byte {
  103. r.ID.AppendValues(values)
  104. values.Set("protocolVersion", fmt.Sprintf("%d", r.Header.Version))
  105. return r.data
  106. }