rclone/vendor/storj.io/drpc/drpcwire/packet.go
2020-05-12 15:56:50 +00:00

161 lines
3.9 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package drpcwire
import "fmt"
//go:generate stringer -type=Kind -trimprefix=Kind_ -output=packet_string.go
// Kind is the enumeration of all the different kinds of messages drpc sends.
type Kind uint8
const (
// kindReserved is saved for the future in case we need to extend.
kindReserved Kind = 0
// kindCancelDeprecated is a reminder that we once used this kind value.
kindCancelDeprecated Kind = 4
// KindInvoke is used to invoke an rpc. The body is the name of the rpc.
KindInvoke Kind = 1
// KindMessage is used to send messages. The body is a protobuf.
KindMessage Kind = 2
// KindError is used to inform that an error happened. The body is an error
// with a code attached.
KindError Kind = 3
// KindClose is used to inform that the rpc is dead. It has no body.
KindClose Kind = 5
// KindCloseSend is used to inform that no more messages will be sent.
// It has no body.
KindCloseSend Kind = 6 // body must be empty
// KindInvokeMetadata includes metadata about the next Invoke packet.
KindInvokeMetadata Kind = 7
)
//
// packet id
//
// ID represents a packet id.
type ID struct {
// Stream is the stream identifier.
Stream uint64
// Message is the message identifier.
Message uint64
}
// Less returns true if the id is less than the provided one. An ID is less than
// another if the Stream is less, and if the stream is equal, if the Message
// is less.
func (i ID) Less(j ID) bool {
return i.Stream < j.Stream || (i.Stream == j.Stream && i.Message < j.Message)
}
// String returns a human readable form of the ID.
func (i ID) String() string { return fmt.Sprintf("<%d,%d>", i.Stream, i.Message) }
//
// data frame
//
// Frame is a split data frame on the wire.
type Frame struct {
// Data is the payload of bytes.
Data []byte
// ID is used so that the frame can be reconstructed.
ID ID
// Kind is the kind of the payload.
Kind Kind
// Done is true if this is the last frame for the ID.
Done bool
// Control is true if the frame has the control bit set.
Control bool
}
// ParseFrame attempts to parse a frame at the beginning of buf. If successful
// then rem contains the unparsed data, fr contains the parsed frame, ok will
// be true, and err will be nil. If there is not enough data for a frame, ok
// will be false and err will be nil. If the data in the buf is malformed, then
// an error is returned.
func ParseFrame(buf []byte) (rem []byte, fr Frame, ok bool, err error) {
var length uint64
var control byte
if len(buf) < 4 {
goto bad
}
rem, control = buf[1:], buf[0]
fr.Done = (control & 0b00000001) > 0
fr.Control = (control & 0b10000000) > 0
fr.Kind = Kind((control & 0b01111110) >> 1)
rem, fr.ID.Stream, ok, err = ReadVarint(rem)
if !ok || err != nil {
goto bad
}
rem, fr.ID.Message, ok, err = ReadVarint(rem)
if !ok || err != nil {
goto bad
}
rem, length, ok, err = ReadVarint(rem)
if !ok || err != nil || length > uint64(len(rem)) {
goto bad
}
rem, fr.Data = rem[length:], rem[:length]
return rem, fr, true, nil
bad:
return buf, fr, false, err
}
// AppendFrame appends a marshaled form of the frame to the provided buffer.
func AppendFrame(buf []byte, fr Frame) []byte {
control := byte(fr.Kind << 1)
if fr.Done {
control |= 0b00000001
}
if fr.Control {
control |= 0b10000000
}
out := buf
out = append(out, control)
out = AppendVarint(out, fr.ID.Stream)
out = AppendVarint(out, fr.ID.Message)
out = AppendVarint(out, uint64(len(fr.Data)))
out = append(out, fr.Data...)
return out
}
//
// packet
//
// Packet is a single message sent by drpc.
type Packet struct {
// Data is the payload of the packet.
Data []byte
// ID is the identifier for the packet.
ID ID
// Kind is the kind of the packet.
Kind Kind
}
// String returns a human readable form of the packet.
func (p Packet) String() string {
return fmt.Sprintf("<s:%d m:%d kind:%s data:%d>",
p.ID.Stream, p.ID.Message, p.Kind, len(p.Data))
}