cell.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package marionette
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "io"
  6. )
  7. const (
  8. // CellHeaderSize is the number of non-payload bytes used by a cell.
  9. CellHeaderSize = 25
  10. // MaxCellLength is the maximum allowed size of a serialized cell.
  11. MaxCellLength = 32768
  12. )
  13. const (
  14. // Normal cells carry zero or more bytes in a payload.
  15. CellTypeNormal = 0x1
  16. // EOS (end-of-stream) cells mark the end of streams and carry no payload.
  17. CellTypeEOS = 0x2
  18. )
  19. // Cell represents a single unit of data sent between the client & server.
  20. //
  21. // This cell is associated with a specific stream and the encoder/decoders
  22. // handle ordering based on sequence id.
  23. type Cell struct {
  24. Type int // Record type (normal, end-of-stream)
  25. Payload []byte // Data
  26. Length int // Size of marshaled data, if specified.
  27. StreamID int // Associated stream
  28. SequenceID int // Record number within stream
  29. UUID int // MAR format identifier
  30. InstanceID int // MAR instance identifier
  31. }
  32. // NewCell returns a new instance of Cell.
  33. func NewCell(streamID, sequenceID, length, typ int) *Cell {
  34. return &Cell{
  35. Type: typ,
  36. SequenceID: sequenceID,
  37. Length: length,
  38. StreamID: streamID,
  39. }
  40. }
  41. // Compare returns -1 if c has a lower sequence than other, 1 if c has a higher
  42. // sequence than other, and 0 if both cells have the same sequence.
  43. func (c *Cell) Compare(other *Cell) int {
  44. if c.SequenceID < other.SequenceID {
  45. return -1
  46. } else if c.SequenceID > other.SequenceID {
  47. return 1
  48. }
  49. return 0
  50. }
  51. // Equal returns true if the payload, stream id, sequence, uuid, and instance id are the same.
  52. func (c *Cell) Equal(other *Cell) bool {
  53. if c == nil && other == nil {
  54. return true
  55. } else if (c != nil && other == nil) || (c == nil && other != nil) {
  56. return false
  57. }
  58. return bytes.Equal(c.Payload, other.Payload) &&
  59. c.StreamID == other.StreamID &&
  60. c.UUID == other.UUID &&
  61. c.InstanceID == other.InstanceID &&
  62. c.SequenceID == other.SequenceID
  63. }
  64. // Size returns the marshaled size of the cell, in bytes.
  65. func (c *Cell) Size() int {
  66. return CellHeaderSize + len(c.Payload) + c.paddingN()
  67. }
  68. // paddingN returns the length of padding, in bytes, if a length is specified.
  69. // If no length is provided or the length is smaller than Size() then 0 is returned.
  70. func (c *Cell) paddingN() int {
  71. n := c.Length - len(c.Payload) - CellHeaderSize
  72. if n < 0 {
  73. return 0
  74. }
  75. return n
  76. }
  77. // MarshalBinary returns a byte slice with a serialized cell.
  78. func (c *Cell) MarshalBinary() ([]byte, error) {
  79. buf := bytes.NewBuffer(make([]byte, 0, c.Size()))
  80. binary.Write(buf, binary.BigEndian, uint32(c.Size()))
  81. binary.Write(buf, binary.BigEndian, uint32(len(c.Payload)))
  82. binary.Write(buf, binary.BigEndian, uint32(c.UUID))
  83. binary.Write(buf, binary.BigEndian, uint32(c.InstanceID))
  84. binary.Write(buf, binary.BigEndian, uint32(c.StreamID))
  85. binary.Write(buf, binary.BigEndian, uint32(c.SequenceID))
  86. binary.Write(buf, binary.BigEndian, uint8(c.Type))
  87. buf.Write(c.Payload)
  88. buf.Write(make([]byte, c.paddingN()))
  89. assert(buf.Len() == CellHeaderSize+len(c.Payload)+c.paddingN())
  90. return buf.Bytes(), nil
  91. }
  92. // UnmarshalBinary decodes a serialized cell.
  93. func (c *Cell) UnmarshalBinary(data []byte) (err error) {
  94. br := bytes.NewReader(data)
  95. // Read cell size.
  96. var sz, payloadN, u32 uint32
  97. if err := binary.Read(br, binary.BigEndian, &sz); err != nil {
  98. return err
  99. }
  100. c.Length = int(sz)
  101. // Limit the reader to the bytes in the cell (minus the sz field).
  102. r := io.LimitReader(br, int64(c.Length-4))
  103. // Read payload size.
  104. if err := binary.Read(r, binary.BigEndian, &payloadN); err != nil {
  105. return err
  106. }
  107. // Read model uuid.
  108. if err := binary.Read(r, binary.BigEndian, &u32); err != nil {
  109. return err
  110. }
  111. c.UUID = int(u32)
  112. // Read model instance id.
  113. if err := binary.Read(r, binary.BigEndian, &u32); err != nil {
  114. return err
  115. }
  116. c.InstanceID = int(u32)
  117. // Read stream id.
  118. if err := binary.Read(r, binary.BigEndian, &u32); err != nil {
  119. return err
  120. }
  121. c.StreamID = int(u32)
  122. // Read sequence id.
  123. if err := binary.Read(r, binary.BigEndian, &u32); err != nil {
  124. return err
  125. }
  126. c.SequenceID = int(u32)
  127. // Read cell type.
  128. var u8 uint8
  129. if err := binary.Read(r, binary.BigEndian, &u8); err != nil {
  130. return err
  131. }
  132. c.Type = int(u8)
  133. // Read payload.
  134. if payloadN > 0 {
  135. c.Payload = make([]byte, payloadN)
  136. if _, err := r.Read(c.Payload); err != nil {
  137. return err
  138. }
  139. return err
  140. } else {
  141. c.Payload = nil
  142. }
  143. return nil
  144. }