blob: c2cb153227c9ae4682e1ae113348b9923c1c29f1 [file] [log] [blame]
// 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 (
"context"
"errors"
"fmt"
"io"
"sync/atomic"
)
// 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 int32
// 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
)
// String implements the fmt.Stringer interface.
func (oc OpCode) String() string {
switch oc {
case OpReply:
return "OP_REPLY"
case OpUpdate:
return "OP_UPDATE"
case OpInsert:
return "OP_INSERT"
case OpQuery:
return "OP_QUERY"
case OpGetMore:
return "OP_GET_MORE"
case OpDelete:
return "OP_DELETE"
case OpKillCursors:
return "OP_KILL_CURSORS"
case OpCommand:
return "OP_COMMAND"
case OpCommandReply:
return "OP_COMMANDREPLY"
case OpCompressed:
return "OP_COMPRESSED"
case OpMsg:
return "OP_MSG"
default:
return "<invalid opcode>"
}
}
// 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 }