newline battles continue

This commit is contained in:
bel
2020-01-19 20:41:30 +00:00
parent 98adb53caf
commit 573696774e
1456 changed files with 501133 additions and 6 deletions

View File

@@ -0,0 +1,20 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
func appendInt32(b []byte, i int32) []byte {
return append(b, byte(i), byte(i>>8), byte(i>>16), byte(i>>24))
}
func appendCString(b []byte, str string) []byte {
b = append(b, str...)
return append(b, 0x00)
}
func appendInt64(b []byte, i int64) []byte {
return append(b, byte(i), byte(i>>8), byte(i>>16), byte(i>>24), byte(i>>32), byte(i>>40), byte(i>>48), byte(i>>56))
}

View File

@@ -0,0 +1,49 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import "go.mongodb.org/mongo-driver/bson"
// Command represents the OP_COMMAND message of the MongoDB wire protocol.
type Command struct {
MsgHeader Header
Database string
CommandName string
Metadata string
CommandArgs string
InputDocs []bson.Raw
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (c Command) MarshalWireMessage() ([]byte, error) {
panic("not implemented")
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (c Command) ValidateWireMessage() error {
panic("not implemented")
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
func (c Command) AppendWireMessage([]byte) ([]byte, error) {
panic("not implemented")
}
// String implements the fmt.Stringer interface.
func (c Command) String() string {
panic("not implemented")
}
// Len implements the WireMessage interface.
func (c Command) Len() int {
panic("not implemented")
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (c *Command) UnmarshalWireMessage([]byte) error {
panic("not implemented")
}

View File

@@ -0,0 +1,47 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import "go.mongodb.org/mongo-driver/bson"
// CommandReply represents the OP_COMMANDREPLY message of the MongoDB wire protocol.
type CommandReply struct {
MsgHeader Header
Metadata bson.Raw
CommandReply bson.Raw
OutputDocs []bson.Raw
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (cr CommandReply) MarshalWireMessage() ([]byte, error) {
panic("not implemented")
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (cr CommandReply) ValidateWireMessage() error {
panic("not implemented")
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
func (cr CommandReply) AppendWireMessage([]byte) ([]byte, error) {
panic("not implemented")
}
// String implements the fmt.Stringer interface.
func (cr CommandReply) String() string {
panic("not implemented")
}
// Len implements the WireMessage interface.
func (cr CommandReply) Len() int {
panic("not implemented")
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (cr *CommandReply) UnmarshalWireMessage([]byte) error {
panic("not implemented")
}

View File

@@ -0,0 +1,112 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import (
"errors"
"fmt"
"go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage"
)
// Compressed represents the OP_COMPRESSED message of the MongoDB wire protocol.
type Compressed struct {
MsgHeader Header
OriginalOpCode OpCode
UncompressedSize int32
CompressorID CompressorID
CompressedMessage []byte
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (c Compressed) MarshalWireMessage() ([]byte, error) {
b := make([]byte, 0, c.Len())
return c.AppendWireMessage(b)
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (c Compressed) ValidateWireMessage() error {
if int(c.MsgHeader.MessageLength) != c.Len() {
return errors.New("incorrect header: message length is not correct")
}
if c.MsgHeader.OpCode != OpCompressed {
return errors.New("incorrect header: opcode is not OpCompressed")
}
if c.OriginalOpCode != c.MsgHeader.OpCode {
return errors.New("incorrect header: original opcode does not match opcode in message header")
}
return nil
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
//
// AppendWireMessage will set the MessageLength property of MsgHeader if it is 0. It will also set the OpCode to
// OpCompressed if the OpCode is 0. If either of these properties are non-zero and not correct, this method will return
// both the []byte with the wire message appended to it and an invalid header error.
func (c Compressed) AppendWireMessage(b []byte) ([]byte, error) {
err := c.MsgHeader.SetDefaults(c.Len(), OpCompressed)
b = c.MsgHeader.AppendHeader(b)
b = appendInt32(b, int32(c.OriginalOpCode))
b = appendInt32(b, c.UncompressedSize)
b = append(b, byte(c.CompressorID))
b = append(b, c.CompressedMessage...)
return b, err
}
// String implements the fmt.Stringer interface.
func (c Compressed) String() string {
return fmt.Sprintf(
`OP_COMPRESSED{MsgHeader: %s, Uncompressed Size: %d, CompressorId: %d, Compressed message: %s}`,
c.MsgHeader, c.UncompressedSize, c.CompressorID, c.CompressedMessage,
)
}
// Len implements the WireMessage interface.
func (c Compressed) Len() int {
// Header + OpCode + UncompressedSize + CompressorId + CompressedMessage
return 16 + 4 + 4 + 1 + len(c.CompressedMessage)
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (c *Compressed) UnmarshalWireMessage(b []byte) error {
var err error
c.MsgHeader, err = ReadHeader(b, 0)
if err != nil {
return err
}
if len(b) < int(c.MsgHeader.MessageLength) {
return Error{Type: ErrOpCompressed, Message: "[]byte too small"}
}
c.OriginalOpCode = OpCode(readInt32(b, 16)) // skip first 16 for header
c.UncompressedSize = readInt32(b, 20)
c.CompressorID = CompressorID(b[24])
// messageLength - Header - OpCode - UncompressedSize - CompressorId
msgLen := c.MsgHeader.MessageLength - 16 - 4 - 4 - 1
c.CompressedMessage = b[25 : 25+msgLen]
return nil
}
// CompressorID is the ID for each type of Compressor.
type CompressorID = wiremessage.CompressorID
// These constants represent the individual compressor IDs for an OP_COMPRESSED.
const (
CompressorNoOp CompressorID = iota
CompressorSnappy
CompressorZLib
)
// DefaultZlibLevel is the default level for zlib compression
const DefaultZlibLevel = 6

View File

@@ -0,0 +1,55 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import "go.mongodb.org/mongo-driver/bson"
// Delete represents the OP_DELETE message of the MongoDB wire protocol.
type Delete struct {
MsgHeader Header
FullCollectionName string
Flags DeleteFlag
Selector bson.Raw
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (d Delete) MarshalWireMessage() ([]byte, error) {
panic("not implemented")
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (d Delete) ValidateWireMessage() error {
panic("not implemented")
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
func (d Delete) AppendWireMessage([]byte) ([]byte, error) {
panic("not implemented")
}
// String implements the fmt.Stringer interface.
func (d Delete) String() string {
panic("not implemented")
}
// Len implements the WireMessage interface.
func (d Delete) Len() int {
panic("not implemented")
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (d *Delete) UnmarshalWireMessage([]byte) error {
panic("not implemented")
}
// DeleteFlag represents the flags on an OP_DELETE message.
type DeleteFlag int32
// These constants represent the individual flags on an OP_DELETE message.
const (
SingleRemove DeleteFlag = 1 << iota
)

View File

@@ -0,0 +1,103 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import (
"errors"
"fmt"
"go.mongodb.org/mongo-driver/x/bsonx"
"strings"
)
// GetMore represents the OP_GET_MORE message of the MongoDB wire protocol.
type GetMore struct {
MsgHeader Header
Zero int32
FullCollectionName string
NumberToReturn int32
CursorID int64
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (gm GetMore) MarshalWireMessage() ([]byte, error) {
b := make([]byte, 0, gm.Len())
return gm.AppendWireMessage(b)
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (gm GetMore) ValidateWireMessage() error {
if int(gm.MsgHeader.MessageLength) != gm.Len() {
return errors.New("incorrect header: message length is not correct")
}
if gm.MsgHeader.OpCode != OpGetMore {
return errors.New("incorrect header: op code is not OpGetMore")
}
if strings.Index(gm.FullCollectionName, ".") == -1 {
return errors.New("incorrect header: collection name does not contain a dot")
}
return nil
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
//
// AppendWireMessage will set the MessageLength property of the MsgHeader
// if it is zero. It will also set the OpCode to OpGetMore if the OpCode is
// zero. If either of these properties are non-zero and not correct, this
// method will return both the []byte with the wire message appended to it
// and an invalid header error.
func (gm GetMore) AppendWireMessage(b []byte) ([]byte, error) {
var err error
err = gm.MsgHeader.SetDefaults(gm.Len(), OpGetMore)
b = gm.MsgHeader.AppendHeader(b)
b = appendInt32(b, gm.Zero)
b = appendCString(b, gm.FullCollectionName)
b = appendInt32(b, gm.NumberToReturn)
b = appendInt64(b, gm.CursorID)
return b, err
}
// String implements the fmt.Stringer interface.
func (gm GetMore) String() string {
return fmt.Sprintf(
`OP_GET_MORE{MsgHeader: %s, Zero: %d, FullCollectionName: %s, NumberToReturn: %d, CursorID: %d}`,
gm.MsgHeader, gm.Zero, gm.FullCollectionName, gm.NumberToReturn, gm.CursorID,
)
}
// Len implements the WireMessage interface.
func (gm GetMore) Len() int {
// Header + Zero + CollectionName + Null Terminator + Return + CursorID
return 16 + 4 + len(gm.FullCollectionName) + 1 + 4 + 8
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (gm *GetMore) UnmarshalWireMessage([]byte) error {
panic("not implemented")
}
// CommandDocument creates a BSON document representing this command.
func (gm GetMore) CommandDocument() bsonx.Doc {
parts := strings.Split(gm.FullCollectionName, ".")
collName := parts[len(parts)-1]
doc := bsonx.Doc{
{"getMore", bsonx.Int64(gm.CursorID)},
{"collection", bsonx.String(collName)},
}
if gm.NumberToReturn != 0 {
doc = doc.Append("batchSize", bsonx.Int32(gm.NumberToReturn))
}
return doc
}
// DatabaseName returns the name of the database for this command.
func (gm GetMore) DatabaseName() string {
return strings.Split(gm.FullCollectionName, ".")[0]
}

View File

@@ -0,0 +1,87 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import (
"fmt"
)
// ErrInvalidHeader is returned when methods are called on a malformed Header.
var ErrInvalidHeader error = Error{Type: ErrHeader, Message: "invalid header"}
// ErrHeaderTooSmall is returned when the size of the header is too small to be valid.
var ErrHeaderTooSmall error = Error{Type: ErrHeader, Message: "the header is too small to be valid"}
// ErrHeaderTooFewBytes is returned when a call to ReadHeader does not contain enough
// bytes to be a valid header.
var ErrHeaderTooFewBytes error = Error{Type: ErrHeader, Message: "invalid header because []byte too small"}
// ErrHeaderInvalidLength is returned when the MessageLength of a header is
// set but is not set to the correct size.
var ErrHeaderInvalidLength error = Error{Type: ErrHeader, Message: "invalid header because MessageLength is imporperly set"}
// ErrHeaderIncorrectOpCode is returned when the OpCode on a header is set but
// is not set to the correct OpCode.
var ErrHeaderIncorrectOpCode error = Error{Type: ErrHeader, Message: "invalid header because OpCode is improperly set"}
// Header represents the header of a MongoDB wire protocol message.
type Header struct {
MessageLength int32
RequestID int32
ResponseTo int32
OpCode OpCode
}
// ReadHeader reads a header from the given slice of bytes starting at offset
// pos.
func ReadHeader(b []byte, pos int32) (Header, error) {
if len(b) < 16 {
return Header{}, ErrHeaderTooFewBytes
}
return Header{
MessageLength: readInt32(b, 0),
RequestID: readInt32(b, 4),
ResponseTo: readInt32(b, 8),
OpCode: OpCode(readInt32(b, 12)),
}, nil
}
func (h Header) String() string {
return fmt.Sprintf(
`Header{MessageLength: %d, RequestID: %d, ResponseTo: %d, OpCode: %v}`,
h.MessageLength, h.RequestID, h.ResponseTo, h.OpCode,
)
}
// AppendHeader will append this header to the given slice of bytes.
func (h Header) AppendHeader(b []byte) []byte {
b = appendInt32(b, h.MessageLength)
b = appendInt32(b, h.RequestID)
b = appendInt32(b, h.ResponseTo)
b = appendInt32(b, int32(h.OpCode))
return b
}
// SetDefaults sets the length and opcode of this header.
func (h *Header) SetDefaults(length int, opcode OpCode) error {
switch h.MessageLength {
case int32(length):
case 0:
h.MessageLength = int32(length)
default:
return ErrHeaderInvalidLength
}
switch h.OpCode {
case opcode:
case OpCode(0):
h.OpCode = opcode
default:
return ErrHeaderIncorrectOpCode
}
return nil
}

View File

@@ -0,0 +1,55 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import "go.mongodb.org/mongo-driver/bson"
// Insert represents the OP_INSERT message of the MongoDB wire protocol.
type Insert struct {
MsgHeader Header
Flags InsertFlag
FullCollectionName string
Documents []bson.Raw
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (i Insert) MarshalWireMessage() ([]byte, error) {
panic("not implemented")
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (i Insert) ValidateWireMessage() error {
panic("not implemented")
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
func (i Insert) AppendWireMessage([]byte) ([]byte, error) {
panic("not implemented")
}
// String implements the fmt.Stringer interface.
func (i Insert) String() string {
panic("not implemented")
}
// Len implements the WireMessage interface.
func (i Insert) Len() int {
panic("not implemented")
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (i *Insert) UnmarshalWireMessage([]byte) error {
panic("not implemented")
}
// InsertFlag represents the flags on an OP_INSERT message.
type InsertFlag int32
// These constants represent the individual flags on an OP_INSERT message.
const (
ContinueOnError InsertFlag = 1 << iota
)

View File

@@ -0,0 +1,92 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import (
"errors"
"fmt"
"go.mongodb.org/mongo-driver/x/bsonx"
)
// KillCursors represents the OP_KILL_CURSORS message of the MongoDB wire protocol.
type KillCursors struct {
MsgHeader Header
Zero int32
NumberOfCursorIDs int32
CursorIDs []int64
DatabaseName string
CollectionName string
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (kc KillCursors) MarshalWireMessage() ([]byte, error) {
b := make([]byte, 0, kc.Len())
return kc.AppendWireMessage(b)
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (kc KillCursors) ValidateWireMessage() error {
if int(kc.MsgHeader.MessageLength) != kc.Len() {
return errors.New("incorrect header: message length is not correct")
}
if kc.MsgHeader.OpCode != OpKillCursors {
return errors.New("incorrect header: op code is not OpGetMore")
}
if kc.NumberOfCursorIDs != int32(len(kc.CursorIDs)) {
return errors.New("incorrect number of cursor IDs")
}
return nil
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
func (kc KillCursors) AppendWireMessage(b []byte) ([]byte, error) {
var err error
err = kc.MsgHeader.SetDefaults(kc.Len(), OpKillCursors)
b = kc.MsgHeader.AppendHeader(b)
b = appendInt32(b, kc.Zero)
b = appendInt32(b, kc.NumberOfCursorIDs)
for _, id := range kc.CursorIDs {
b = appendInt64(b, id)
}
return b, err
}
// String implements the fmt.Stringer interface.
func (kc KillCursors) String() string {
return fmt.Sprintf(
`OP_KILL_CURSORS{MsgHeader: %s, Zero: %d, Number of Cursor IDS: %d, Cursor IDs: %v}`,
kc.MsgHeader, kc.Zero, kc.NumberOfCursorIDs, kc.CursorIDs,
)
}
// Len implements the WireMessage interface.
func (kc KillCursors) Len() int {
// Header + Zero + Number IDs + 8 * Number IDs
return 16 + 4 + 4 + int(kc.NumberOfCursorIDs*8)
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (kc *KillCursors) UnmarshalWireMessage([]byte) error {
panic("not implemented")
}
// CommandDocument creates a BSON document representing this command.
func (kc KillCursors) CommandDocument() bsonx.Doc {
cursors := make([]bsonx.Val, len(kc.CursorIDs))
for i, id := range kc.CursorIDs {
cursors[i] = bsonx.Int64(id)
}
return bsonx.Doc{
{"killCursors", bsonx.String(kc.CollectionName)},
{"cursors", bsonx.Array(cursors)},
}
}

View File

@@ -0,0 +1,303 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import (
"errors"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/x/bsonx"
"go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage"
)
// Msg represents the OP_MSG message of the MongoDB wire protocol.
type Msg struct {
MsgHeader Header
FlagBits MsgFlag
Sections []Section
Checksum uint32
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (m Msg) MarshalWireMessage() ([]byte, error) {
b := make([]byte, 0, m.Len())
return m.AppendWireMessage(b)
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (m Msg) ValidateWireMessage() error {
if int(m.MsgHeader.MessageLength) != m.Len() {
return errors.New("incorrect header: message length is not correct")
}
if m.MsgHeader.OpCode != OpMsg {
return errors.New("incorrect header: opcode is not OpMsg")
}
return nil
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
//
// AppendWireMesssage will set the MessageLength property of the MsgHeader if it is zero. It will also set the Opcode
// to OP_MSG if it is zero. If either of these properties are non-zero and not correct, this method will return both the
// []byte with the wire message appended to it and an invalid header error.
func (m Msg) AppendWireMessage(b []byte) ([]byte, error) {
var err error
err = m.MsgHeader.SetDefaults(m.Len(), OpMsg)
b = m.MsgHeader.AppendHeader(b)
b = appendInt32(b, int32(m.FlagBits))
for _, section := range m.Sections {
newB := make([]byte, 0)
newB = section.AppendSection(newB)
b = section.AppendSection(b)
}
return b, err
}
// String implements the fmt.Stringer interface.
func (m Msg) String() string {
return fmt.Sprintf(
`OP_MSG{MsgHeader: %v, FlagBits: %d, Sections: %v, Checksum: %d}`,
m.MsgHeader, m.FlagBits, m.Sections, m.Checksum,
)
}
// Len implements the WireMessage interface.
func (m Msg) Len() int {
// Header + Flags + len of each section + optional checksum
totalLen := 16 + 4 // header and flag
for _, section := range m.Sections {
totalLen += section.Len()
}
if m.FlagBits&ChecksumPresent > 0 {
totalLen += 4
}
return totalLen
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (m *Msg) UnmarshalWireMessage(b []byte) error {
var err error
m.MsgHeader, err = ReadHeader(b, 0)
if err != nil {
return err
}
if len(b) < int(m.MsgHeader.MessageLength) {
return Error{
Type: ErrOpMsg,
Message: "[]byte too small",
}
}
m.FlagBits = MsgFlag(readInt32(b, 16))
// read each section
sectionBytes := m.MsgHeader.MessageLength - 16 - 4 // number of bytes taken up by sections
hasChecksum := m.FlagBits&ChecksumPresent > 0
if hasChecksum {
sectionBytes -= 4 // 4 bytes at end for checksum
}
m.Sections = make([]Section, 0)
position := 20 // position to read from
for sectionBytes > 0 {
sectionType := SectionType(b[position])
position++
switch sectionType {
case SingleDocument:
rdr, size, err := readDocument(b, int32(position))
if err.Message != "" {
err.Type = ErrOpMsg
return err
}
position += size
sb := SectionBody{
Document: rdr,
}
sb.PayloadType = sb.Kind()
sectionBytes -= int32(sb.Len())
m.Sections = append(m.Sections, sb)
case DocumentSequence:
sds := SectionDocumentSequence{}
sds.Size = readInt32(b, int32(position))
position += 4
identifier, err := readCString(b, int32(position))
if err != nil {
return err
}
sds.Identifier = identifier
position += len(identifier) + 1 // +1 for \0
sds.PayloadType = sds.Kind()
// length of documents to read
// sequenceLen - 4 bytes for size field - identifierLength (including \0)
docsLen := int(sds.Size) - 4 - len(identifier) - 1
for docsLen > 0 {
rdr, size, err := readDocument(b, int32(position))
if err.Message != "" {
err.Type = ErrOpMsg
return err
}
position += size
sds.Documents = append(sds.Documents, rdr)
docsLen -= size
}
sectionBytes -= int32(sds.Len())
m.Sections = append(m.Sections, sds)
}
}
if hasChecksum {
m.Checksum = uint32(readInt32(b, int32(position)))
}
return nil
}
// GetMainDocument returns the document containing the message to send.
func (m *Msg) GetMainDocument() (bsonx.Doc, error) {
return bsonx.ReadDoc(m.Sections[0].(SectionBody).Document)
}
// GetSequenceArray returns this message's document sequence as a BSON array along with the array identifier.
// If this message has no associated document sequence, a nil array is returned.
func (m *Msg) GetSequenceArray() (bsonx.Arr, string, error) {
if len(m.Sections) == 1 {
return nil, "", nil
}
arr := bsonx.Arr{}
sds := m.Sections[1].(SectionDocumentSequence)
for _, rdr := range sds.Documents {
doc, err := bsonx.ReadDoc([]byte(rdr))
if err != nil {
return nil, "", err
}
arr = append(arr, bsonx.Document(doc))
}
return arr, sds.Identifier, nil
}
// AcknowledgedWrite returns true if this msg represents an acknowledged write command.
func (m *Msg) AcknowledgedWrite() bool {
return m.FlagBits&MoreToCome == 0
}
// MsgFlag represents the flags on an OP_MSG message.
type MsgFlag = wiremessage.MsgFlag
// These constants represent the individual flags on an OP_MSG message.
const (
ChecksumPresent MsgFlag = 1 << iota
MoreToCome
ExhaustAllowed MsgFlag = 1 << 16
)
// Section represents a section on an OP_MSG message.
type Section interface {
Kind() SectionType
Len() int
AppendSection([]byte) []byte
}
// SectionBody represents the kind body of an OP_MSG message.
type SectionBody struct {
PayloadType SectionType
Document bson.Raw
}
// Kind implements the Section interface.
func (sb SectionBody) Kind() SectionType {
return SingleDocument
}
// Len implements the Section interface
func (sb SectionBody) Len() int {
return 1 + len(sb.Document) // 1 for PayloadType
}
// AppendSection implements the Section interface.
func (sb SectionBody) AppendSection(dest []byte) []byte {
dest = append(dest, byte(SingleDocument))
dest = append(dest, sb.Document...)
return dest
}
// SectionDocumentSequence represents the kind document sequence of an OP_MSG message.
type SectionDocumentSequence struct {
PayloadType SectionType
Size int32
Identifier string
Documents []bson.Raw
}
// Kind implements the Section interface.
func (sds SectionDocumentSequence) Kind() SectionType {
return DocumentSequence
}
// Len implements the Section interface
func (sds SectionDocumentSequence) Len() int {
// PayloadType + Size + Identifier + 1 (null terminator) + totalDocLen
totalDocLen := 0
for _, doc := range sds.Documents {
totalDocLen += len(doc)
}
return 1 + 4 + len(sds.Identifier) + 1 + totalDocLen
}
// PayloadLen returns the length of the payload
func (sds SectionDocumentSequence) PayloadLen() int {
// 4 bytes for size field, len identifier (including \0), and total docs len
return sds.Len() - 1
}
// AppendSection implements the Section interface
func (sds SectionDocumentSequence) AppendSection(dest []byte) []byte {
dest = append(dest, byte(DocumentSequence))
dest = appendInt32(dest, sds.Size)
dest = appendCString(dest, sds.Identifier)
for _, doc := range sds.Documents {
dest = append(dest, doc...)
}
return dest
}
// SectionType represents the type for 1 section in an OP_MSG
type SectionType = wiremessage.SectionType
// These constants represent the individual section types for a section in an OP_MSG
const (
SingleDocument SectionType = iota
DocumentSequence
)
// OpmsgWireVersion is the minimum wire version needed to use OP_MSG
const OpmsgWireVersion = 6

View File

@@ -0,0 +1,307 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import (
"errors"
"fmt"
"strings"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx"
"go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage"
)
// Query represents the OP_QUERY message of the MongoDB wire protocol.
type Query struct {
MsgHeader Header
Flags QueryFlag
FullCollectionName string
NumberToSkip int32
NumberToReturn int32
Query bson.Raw
ReturnFieldsSelector bson.Raw
SkipSet bool
Limit *int32
BatchSize *int32
}
var optionsMap = map[string]string{
"$orderby": "sort",
"$hint": "hint",
"$comment": "comment",
"$maxScan": "maxScan",
"$max": "max",
"$min": "min",
"$returnKey": "returnKey",
"$showDiskLoc": "showRecordId",
"$maxTimeMS": "maxTimeMS",
"$snapshot": "snapshot",
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
//
// See AppendWireMessage for a description of the rules this method follows.
func (q Query) MarshalWireMessage() ([]byte, error) {
b := make([]byte, 0, q.Len())
return q.AppendWireMessage(b)
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (q Query) ValidateWireMessage() error {
if int(q.MsgHeader.MessageLength) != q.Len() {
return errors.New("incorrect header: message length is not correct")
}
if q.MsgHeader.OpCode != OpQuery {
return errors.New("incorrect header: op code is not OpQuery")
}
if strings.Index(q.FullCollectionName, ".") == -1 {
return errors.New("incorrect header: collection name does not contain a dot")
}
if q.Query != nil && len(q.Query) > 0 {
err := q.Query.Validate()
if err != nil {
return err
}
}
if q.ReturnFieldsSelector != nil && len(q.ReturnFieldsSelector) > 0 {
err := q.ReturnFieldsSelector.Validate()
if err != nil {
return err
}
}
return nil
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
//
// AppendWireMessage will set the MessageLength property of the MsgHeader
// if it is zero. It will also set the OpCode to OpQuery if the OpCode is
// zero. If either of these properties are non-zero and not correct, this
// method will return both the []byte with the wire message appended to it
// and an invalid header error.
func (q Query) AppendWireMessage(b []byte) ([]byte, error) {
var err error
err = q.MsgHeader.SetDefaults(q.Len(), OpQuery)
b = q.MsgHeader.AppendHeader(b)
b = appendInt32(b, int32(q.Flags))
b = appendCString(b, q.FullCollectionName)
b = appendInt32(b, q.NumberToSkip)
b = appendInt32(b, q.NumberToReturn)
b = append(b, q.Query...)
b = append(b, q.ReturnFieldsSelector...)
return b, err
}
// String implements the fmt.Stringer interface.
func (q Query) String() string {
return fmt.Sprintf(
`OP_QUERY{MsgHeader: %s, Flags: %s, FullCollectionname: %s, NumberToSkip: %d, NumberToReturn: %d, Query: %s, ReturnFieldsSelector: %s}`,
q.MsgHeader, q.Flags, q.FullCollectionName, q.NumberToSkip, q.NumberToReturn, q.Query, q.ReturnFieldsSelector,
)
}
// Len implements the WireMessage interface.
func (q Query) Len() int {
// Header + Flags + CollectionName + Null Byte + Skip + Return + Query + ReturnFieldsSelector
return 16 + 4 + len(q.FullCollectionName) + 1 + 4 + 4 + len(q.Query) + len(q.ReturnFieldsSelector)
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (q *Query) UnmarshalWireMessage(b []byte) error {
var err error
q.MsgHeader, err = ReadHeader(b, 0)
if err != nil {
return err
}
if len(b) < int(q.MsgHeader.MessageLength) {
return Error{Type: ErrOpQuery, Message: "[]byte too small"}
}
q.Flags = QueryFlag(readInt32(b, 16))
q.FullCollectionName, err = readCString(b, 20)
if err != nil {
return err
}
pos := 20 + len(q.FullCollectionName) + 1
q.NumberToSkip = readInt32(b, int32(pos))
pos += 4
q.NumberToReturn = readInt32(b, int32(pos))
pos += 4
var size int
var wmerr Error
q.Query, size, wmerr = readDocument(b, int32(pos))
if wmerr.Message != "" {
wmerr.Type = ErrOpQuery
return wmerr
}
pos += size
if pos < len(b) {
q.ReturnFieldsSelector, size, wmerr = readDocument(b, int32(pos))
if wmerr.Message != "" {
wmerr.Type = ErrOpQuery
return wmerr
}
pos += size
}
return nil
}
// AcknowledgedWrite returns true if this command represents an acknowledged write
func (q *Query) AcknowledgedWrite() bool {
wcElem, err := q.Query.LookupErr("writeConcern")
if err != nil {
// no wc --> ack
return true
}
return writeconcern.AcknowledgedValue(wcElem)
}
// Legacy returns true if the query represents a legacy find operation.
func (q Query) Legacy() bool {
return !strings.Contains(q.FullCollectionName, "$cmd")
}
// DatabaseName returns the database name for the query.
func (q Query) DatabaseName() string {
if q.Legacy() {
return strings.Split(q.FullCollectionName, ".")[0]
}
return q.FullCollectionName[:len(q.FullCollectionName)-5] // remove .$cmd
}
// CollectionName returns the collection name for the query.
func (q Query) CollectionName() string {
parts := strings.Split(q.FullCollectionName, ".")
return parts[len(parts)-1]
}
// CommandDocument creates a BSON document representing this command.
func (q Query) CommandDocument() (bsonx.Doc, error) {
if q.Legacy() {
return q.legacyCommandDocument()
}
cmd, err := bsonx.ReadDoc([]byte(q.Query))
if err != nil {
return nil, err
}
cmdElem := cmd[0]
if cmdElem.Key == "$query" {
cmd = cmdElem.Value.Document()
}
return cmd, nil
}
func (q Query) legacyCommandDocument() (bsonx.Doc, error) {
doc, err := bsonx.ReadDoc(q.Query)
if err != nil {
return nil, err
}
parts := strings.Split(q.FullCollectionName, ".")
collName := parts[len(parts)-1]
doc = append(bsonx.Doc{{"find", bsonx.String(collName)}}, doc...)
var filter bsonx.Doc
var queryIndex int
for i, elem := range doc {
if newKey, ok := optionsMap[elem.Key]; ok {
doc[i].Key = newKey
continue
}
if elem.Key == "$query" {
filter = elem.Value.Document()
} else {
// the element is the filter
filter = filter.Append(elem.Key, elem.Value)
}
queryIndex = i
}
doc = append(doc[:queryIndex], doc[queryIndex+1:]...) // remove $query
if len(filter) != 0 {
doc = doc.Append("filter", bsonx.Document(filter))
}
doc, err = q.convertLegacyParams(doc)
if err != nil {
return nil, err
}
return doc, nil
}
func (q Query) convertLegacyParams(doc bsonx.Doc) (bsonx.Doc, error) {
if q.ReturnFieldsSelector != nil {
projDoc, err := bsonx.ReadDoc(q.ReturnFieldsSelector)
if err != nil {
return nil, err
}
doc = doc.Append("projection", bsonx.Document(projDoc))
}
if q.Limit != nil {
limit := *q.Limit
if limit < 0 {
limit *= -1
doc = doc.Append("singleBatch", bsonx.Boolean(true))
}
doc = doc.Append("limit", bsonx.Int32(*q.Limit))
}
if q.BatchSize != nil {
doc = doc.Append("batchSize", bsonx.Int32(*q.BatchSize))
}
if q.SkipSet {
doc = doc.Append("skip", bsonx.Int32(q.NumberToSkip))
}
if q.Flags&TailableCursor > 0 {
doc = doc.Append("tailable", bsonx.Boolean(true))
}
if q.Flags&OplogReplay > 0 {
doc = doc.Append("oplogReplay", bsonx.Boolean(true))
}
if q.Flags&NoCursorTimeout > 0 {
doc = doc.Append("noCursorTimeout", bsonx.Boolean(true))
}
if q.Flags&AwaitData > 0 {
doc = doc.Append("awaitData", bsonx.Boolean(true))
}
if q.Flags&Partial > 0 {
doc = doc.Append("allowPartialResults", bsonx.Boolean(true))
}
return doc, nil
}
// QueryFlag represents the flags on an OP_QUERY message.
type QueryFlag = wiremessage.QueryFlag
// These constants represent the individual flags on an OP_QUERY message.
const (
_ QueryFlag = 1 << iota
TailableCursor
SlaveOK
OplogReplay
NoCursorTimeout
AwaitData
Exhaust
Partial
)

View File

@@ -0,0 +1,51 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import (
"bytes"
"errors"
"go.mongodb.org/mongo-driver/bson"
)
func readInt32(b []byte, pos int32) int32 {
return (int32(b[pos+0])) | (int32(b[pos+1]) << 8) | (int32(b[pos+2]) << 16) | (int32(b[pos+3]) << 24)
}
func readCString(b []byte, pos int32) (string, error) {
null := bytes.IndexByte(b[pos:], 0x00)
if null == -1 {
return "", errors.New("invalid cstring")
}
return string(b[pos : int(pos)+null]), nil
}
func readInt64(b []byte, pos int32) int64 {
return (int64(b[pos+0])) | (int64(b[pos+1]) << 8) | (int64(b[pos+2]) << 16) | (int64(b[pos+3]) << 24) | (int64(b[pos+4]) << 32) |
(int64(b[pos+5]) << 40) | (int64(b[pos+6]) << 48) | (int64(b[pos+7]) << 56)
}
// readDocument will attempt to read a bson.Reader from the given slice of bytes
// from the given position.
func readDocument(b []byte, pos int32) (bson.Raw, int, Error) {
if int(pos)+4 > len(b) {
return nil, 0, Error{Message: "document too small to be valid"}
}
size := int(readInt32(b, int32(pos)))
if int(pos)+size > len(b) {
return nil, 0, Error{Message: "document size is larger than available bytes"}
}
if b[int(pos)+size-1] != 0x00 {
return nil, 0, Error{Message: "document invalid, last byte is not null"}
}
// TODO(GODRIVER-138): When we add 3.0 support, alter this so we either do one larger make or use a pool.
rdr := make(bson.Raw, size)
copy(rdr, b[pos:int(pos)+size])
return rdr, size, Error{Type: ErrNil}
}

View File

@@ -0,0 +1,180 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import (
"errors"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/x/bsonx"
"go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage"
)
// Reply represents the OP_REPLY message of the MongoDB wire protocol.
type Reply struct {
MsgHeader Header
ResponseFlags ReplyFlag
CursorID int64
StartingFrom int32
NumberReturned int32
Documents []bson.Raw
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
//
// See AppendWireMessage for a description of the rules this method follows.
func (r Reply) MarshalWireMessage() ([]byte, error) {
b := make([]byte, 0, r.Len())
return r.AppendWireMessage(b)
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (r Reply) ValidateWireMessage() error {
if int(r.MsgHeader.MessageLength) != r.Len() {
return errors.New("incorrect header: message length is not correct")
}
if r.MsgHeader.OpCode != OpReply {
return errors.New("incorrect header: op code is not OpReply")
}
return nil
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
//
// AppendWireMessage will set the MessageLength property of the MsgHeader
// if it is zero. It will also set the OpCode to OpQuery if the OpCode is
// zero. If either of these properties are non-zero and not correct, this
// method will return both the []byte with the wire message appended to it
// and an invalid header error.
func (r Reply) AppendWireMessage(b []byte) ([]byte, error) {
var err error
err = r.MsgHeader.SetDefaults(r.Len(), OpReply)
b = r.MsgHeader.AppendHeader(b)
b = appendInt32(b, int32(r.ResponseFlags))
b = appendInt64(b, r.CursorID)
b = appendInt32(b, r.StartingFrom)
b = appendInt32(b, r.NumberReturned)
for _, d := range r.Documents {
b = append(b, d...)
}
return b, err
}
// String implements the fmt.Stringer interface.
func (r Reply) String() string {
return fmt.Sprintf(
`OP_REPLY{MsgHeader: %s, ResponseFlags: %s, CursorID: %d, StartingFrom: %d, NumberReturned: %d, Documents: %v}`,
r.MsgHeader, r.ResponseFlags, r.CursorID, r.StartingFrom, r.NumberReturned, r.Documents,
)
}
// Len implements the WireMessage interface.
func (r Reply) Len() int {
// Header + Flags + CursorID + StartingFrom + NumberReturned + Length of Length of Documents
docsLen := 0
for _, d := range r.Documents {
docsLen += len(d)
}
return 16 + 4 + 8 + 4 + 4 + docsLen
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (r *Reply) UnmarshalWireMessage(b []byte) error {
var err error
r.MsgHeader, err = ReadHeader(b, 0)
if err != nil {
return err
}
if r.MsgHeader.MessageLength < 36 {
return errors.New("invalid OP_REPLY: header length too small")
}
if len(b) < int(r.MsgHeader.MessageLength) {
return errors.New("invalid OP_REPLY: []byte too small")
}
r.ResponseFlags = ReplyFlag(readInt32(b, 16))
r.CursorID = readInt64(b, 20)
r.StartingFrom = readInt32(b, 28)
r.NumberReturned = readInt32(b, 32)
pos := 36
for pos < len(b) {
rdr, size, err := readDocument(b, int32(pos))
if err.Message != "" {
err.Type = ErrOpReply
return err
}
r.Documents = append(r.Documents, rdr)
pos += size
}
return nil
}
// GetMainLegacyDocument constructs and returns a BSON document for this reply.
func (r *Reply) GetMainLegacyDocument(fullCollectionName string) (bsonx.Doc, error) {
if r.ResponseFlags&CursorNotFound > 0 {
fmt.Println("cursor not found err")
return bsonx.Doc{
{"ok", bsonx.Int32(0)},
}, nil
}
if r.ResponseFlags&QueryFailure > 0 {
firstDoc := r.Documents[0]
return bsonx.Doc{
{"ok", bsonx.Int32(0)},
{"errmsg", bsonx.String(firstDoc.Lookup("$err").StringValue())},
{"code", bsonx.Int32(firstDoc.Lookup("code").Int32())},
}, nil
}
doc := bsonx.Doc{
{"ok", bsonx.Int32(1)},
}
batchStr := "firstBatch"
if r.StartingFrom != 0 {
batchStr = "nextBatch"
}
batchArr := make([]bsonx.Val, len(r.Documents))
for i, docRaw := range r.Documents {
doc, err := bsonx.ReadDoc(docRaw)
if err != nil {
return nil, err
}
batchArr[i] = bsonx.Document(doc)
}
cursorDoc := bsonx.Doc{
{"id", bsonx.Int64(r.CursorID)},
{"ns", bsonx.String(fullCollectionName)},
{batchStr, bsonx.Array(batchArr)},
}
doc = doc.Append("cursor", bsonx.Document(cursorDoc))
return doc, nil
}
// GetMainDocument returns the main BSON document for this reply.
func (r *Reply) GetMainDocument() (bsonx.Doc, error) {
return bsonx.ReadDoc([]byte(r.Documents[0]))
}
// ReplyFlag represents the flags of an OP_REPLY message.
type ReplyFlag = wiremessage.ReplyFlag
// These constants represent the individual flags of an OP_REPLY message.
const (
CursorNotFound ReplyFlag = 1 << iota
QueryFailure
ShardConfigStale
AwaitCapable
)

View File

@@ -0,0 +1,57 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package wiremessage
import "go.mongodb.org/mongo-driver/bson"
// Update represents the OP_UPDATE message of the MongoDB wire protocol.
type Update struct {
MsgHeader Header
FullCollectionName string
Flags UpdateFlag
Selector bson.Raw
Update bson.Raw
}
// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
func (u Update) MarshalWireMessage() ([]byte, error) {
panic("not implemented")
}
// ValidateWireMessage implements the Validator and WireMessage interfaces.
func (u Update) ValidateWireMessage() error {
panic("not implemented")
}
// AppendWireMessage implements the Appender and WireMessage interfaces.
func (u Update) AppendWireMessage([]byte) ([]byte, error) {
panic("not implemented")
}
// String implements the fmt.Stringer interface.
func (u Update) String() string {
panic("not implemented")
}
// Len implements the WireMessage interface.
func (u Update) Len() int {
panic("not implemented")
}
// UnmarshalWireMessage implements the Unmarshaler interface.
func (u *Update) UnmarshalWireMessage([]byte) error {
panic("not implemented")
}
// UpdateFlag represents the flags on an OP_UPDATE message.
type UpdateFlag int32
// These constants represent the individual flags on an OP_UPDATE message.
const (
Upsert UpdateFlag = 1 << iota
MultiUpdate
)

View File

@@ -0,0 +1,178 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Package wiremessage contains types for speaking the MongoDB Wire Protocol. Since this low
// level library is meant to be used in the context of a driver and in the context of a server
// all of the flags and types of the wire protocol are implemented. For each op there are two
// corresponding implementations. One prefixed with Immutable which can be created by casting a
// []byte to the type, and another prefixed with Mutable that is a struct with methods to mutate
// the op.
package wiremessage // import "go.mongodb.org/mongo-driver/x/network/wiremessage"
import (
"context"
"errors"
"fmt"
"io"
"sync/atomic"
"go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage"
)
// ErrInvalidMessageLength is returned when the provided message length is too small to be valid.
var ErrInvalidMessageLength = errors.New("the message length is too small, it must be at least 16")
// ErrUnknownOpCode is returned when the provided opcode is not a valid opcode.
var ErrUnknownOpCode = errors.New("the opcode is unknown")
var globalRequestID int32
// CurrentRequestID returns the current request ID.
func CurrentRequestID() int32 { return atomic.LoadInt32(&globalRequestID) }
// NextRequestID returns the next request ID.
func NextRequestID() int32 { return atomic.AddInt32(&globalRequestID, 1) }
// Error represents an error related to wire protocol messages.
type Error struct {
Type ErrorType
Message string
}
// Error implements the err interface.
func (e Error) Error() string {
return e.Message
}
// ErrorType is the type of error, which indicates from which part of the code
// the error originated.
type ErrorType uint16
// These constants are the types of errors exposed by this package.
const (
ErrNil ErrorType = iota
ErrHeader
ErrOpQuery
ErrOpReply
ErrOpCompressed
ErrOpMsg
ErrRead
)
// OpCode represents a MongoDB wire protocol opcode.
type OpCode = wiremessage.OpCode
// These constants are the valid opcodes for the version of the wireprotocol
// supported by this library. The skipped OpCodes are historical OpCodes that
// are no longer used.
const (
OpReply OpCode = 1
_ OpCode = 1001
OpUpdate OpCode = 2001
OpInsert OpCode = 2002
_ OpCode = 2003
OpQuery OpCode = 2004
OpGetMore OpCode = 2005
OpDelete OpCode = 2006
OpKillCursors OpCode = 2007
OpCommand OpCode = 2010
OpCommandReply OpCode = 2011
OpCompressed OpCode = 2012
OpMsg OpCode = 2013
)
// WireMessage represents a message in the MongoDB wire protocol.
type WireMessage interface {
Marshaler
Validator
Appender
fmt.Stringer
// Len returns the length in bytes of this WireMessage.
Len() int
}
// Validator is the interface implemented by types that can validate
// themselves as a MongoDB wire protocol message.
type Validator interface {
ValidateWireMessage() error
}
// Marshaler is the interface implemented by types that can marshal
// themselves into a valid MongoDB wire protocol message.
type Marshaler interface {
MarshalWireMessage() ([]byte, error)
}
// Appender is the interface implemented by types that can append themselves, as
// a MongoDB wire protocol message, to the provided slice of bytes.
type Appender interface {
AppendWireMessage([]byte) ([]byte, error)
}
// Unmarshaler is the interface implemented by types that can unmarshal a
// MongoDB wire protocol message version of themselves. The input can be
// assumed to be a valid MongoDB wire protocol message. UnmarshalWireMessage
// must copy the data if it wishes to retain the data after returning.
type Unmarshaler interface {
UnmarshalWireMessage([]byte) error
}
// Writer is the interface implemented by types that can have WireMessages
// written to them.
//
// Implementation must obey the cancellation, timeouts, and deadlines of the
// provided context.Context object.
type Writer interface {
WriteWireMessage(context.Context, WireMessage) error
}
// Reader is the interface implemented by types that can have WireMessages
// read from them.
//
// Implementation must obey the cancellation, timeouts, and deadlines of the
// provided context.Context object.
type Reader interface {
ReadWireMessage(context.Context) (WireMessage, error)
}
// ReadWriter is the interface implemented by types that can both read and write
// WireMessages.
type ReadWriter interface {
Reader
Writer
}
// ReadWriteCloser is the interface implemented by types that can read and write
// WireMessages and can also be closed.
type ReadWriteCloser interface {
Reader
Writer
io.Closer
}
// Transformer is the interface implemented by types that can alter a WireMessage.
// Implementations should not directly alter the provided WireMessage and instead
// make a copy of the message, alter it, and returned the new message.
type Transformer interface {
TransformWireMessage(WireMessage) (WireMessage, error)
}
// ReadFrom will read a single WireMessage from the given io.Reader. This function will
// validate the WireMessage. If the WireMessage is not valid, this method will
// return both the error and the invalid WireMessage. If another type of processing
// error occurs, WireMessage will be nil.
//
// This function will return the immutable versions of wire protocol messages. The
// Convert function can be used to retrieve a mutable version of wire protocol
// messages.
func ReadFrom(io.Reader) (WireMessage, error) { return nil, nil }
// Unmarshal will unmarshal data into a WireMessage.
func Unmarshal([]byte) (WireMessage, error) { return nil, nil }
// Validate will validate that data is a valid MongoDB wire protocol message.
func Validate([]byte) error { return nil }