1// Copyright (C) MongoDB, Inc. 2017-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7// Package wiremessage contains types for speaking the MongoDB Wire Protocol. Since this low
8// level library is meant to be used in the context of a driver and in the context of a server
9// all of the flags and types of the wire protocol are implemented. For each op there are two
10// corresponding implementations. One prefixed with Immutable which can be created by casting a
11// []byte to the type, and another prefixed with Mutable that is a struct with methods to mutate
12// the op.
13package wiremessage // import "go.mongodb.org/mongo-driver/x/network/wiremessage"
14
15import (
16	"context"
17	"errors"
18	"fmt"
19	"io"
20	"sync/atomic"
21)
22
23// ErrInvalidMessageLength is returned when the provided message length is too small to be valid.
24var ErrInvalidMessageLength = errors.New("the message length is too small, it must be at least 16")
25
26// ErrUnknownOpCode is returned when the provided opcode is not a valid opcode.
27var ErrUnknownOpCode = errors.New("the opcode is unknown")
28
29var globalRequestID int32
30
31// CurrentRequestID returns the current request ID.
32func CurrentRequestID() int32 { return atomic.LoadInt32(&globalRequestID) }
33
34// NextRequestID returns the next request ID.
35func NextRequestID() int32 { return atomic.AddInt32(&globalRequestID, 1) }
36
37// Error represents an error related to wire protocol messages.
38type Error struct {
39	Type    ErrorType
40	Message string
41}
42
43// Error implements the err interface.
44func (e Error) Error() string {
45	return e.Message
46}
47
48// ErrorType is the type of error, which indicates from which part of the code
49// the error originated.
50type ErrorType uint16
51
52// These constants are the types of errors exposed by this package.
53const (
54	ErrNil ErrorType = iota
55	ErrHeader
56	ErrOpQuery
57	ErrOpReply
58	ErrOpCompressed
59	ErrOpMsg
60	ErrRead
61)
62
63// OpCode represents a MongoDB wire protocol opcode.
64type OpCode int32
65
66// These constants are the valid opcodes for the version of the wireprotocol
67// supported by this library. The skipped OpCodes are historical OpCodes that
68// are no longer used.
69const (
70	OpReply        OpCode = 1
71	_              OpCode = 1001
72	OpUpdate       OpCode = 2001
73	OpInsert       OpCode = 2002
74	_              OpCode = 2003
75	OpQuery        OpCode = 2004
76	OpGetMore      OpCode = 2005
77	OpDelete       OpCode = 2006
78	OpKillCursors  OpCode = 2007
79	OpCommand      OpCode = 2010
80	OpCommandReply OpCode = 2011
81	OpCompressed   OpCode = 2012
82	OpMsg          OpCode = 2013
83)
84
85// String implements the fmt.Stringer interface.
86func (oc OpCode) String() string {
87	switch oc {
88	case OpReply:
89		return "OP_REPLY"
90	case OpUpdate:
91		return "OP_UPDATE"
92	case OpInsert:
93		return "OP_INSERT"
94	case OpQuery:
95		return "OP_QUERY"
96	case OpGetMore:
97		return "OP_GET_MORE"
98	case OpDelete:
99		return "OP_DELETE"
100	case OpKillCursors:
101		return "OP_KILL_CURSORS"
102	case OpCommand:
103		return "OP_COMMAND"
104	case OpCommandReply:
105		return "OP_COMMANDREPLY"
106	case OpCompressed:
107		return "OP_COMPRESSED"
108	case OpMsg:
109		return "OP_MSG"
110	default:
111		return "<invalid opcode>"
112	}
113}
114
115// WireMessage represents a message in the MongoDB wire protocol.
116type WireMessage interface {
117	Marshaler
118	Validator
119	Appender
120	fmt.Stringer
121
122	// Len returns the length in bytes of this WireMessage.
123	Len() int
124}
125
126// Validator is the interface implemented by types that can validate
127// themselves as a MongoDB wire protocol message.
128type Validator interface {
129	ValidateWireMessage() error
130}
131
132// Marshaler is the interface implemented by types that can marshal
133// themselves into a valid MongoDB wire protocol message.
134type Marshaler interface {
135	MarshalWireMessage() ([]byte, error)
136}
137
138// Appender is the interface implemented by types that can append themselves, as
139// a MongoDB wire protocol message, to the provided slice of bytes.
140type Appender interface {
141	AppendWireMessage([]byte) ([]byte, error)
142}
143
144// Unmarshaler is the interface implemented by types that can unmarshal a
145// MongoDB wire protocol message version of themselves. The input can be
146// assumed to be a valid MongoDB wire protocol message. UnmarshalWireMessage
147// must copy the data if it wishes to retain the data after returning.
148type Unmarshaler interface {
149	UnmarshalWireMessage([]byte) error
150}
151
152// Writer is the interface implemented by types that can have WireMessages
153// written to them.
154//
155// Implementation must obey the cancellation, timeouts, and deadlines of the
156// provided context.Context object.
157type Writer interface {
158	WriteWireMessage(context.Context, WireMessage) error
159}
160
161// Reader is the interface implemented by types that can have WireMessages
162// read from them.
163//
164// Implementation must obey the cancellation, timeouts, and deadlines of the
165// provided context.Context object.
166type Reader interface {
167	ReadWireMessage(context.Context) (WireMessage, error)
168}
169
170// ReadWriter is the interface implemented by types that can both read and write
171// WireMessages.
172type ReadWriter interface {
173	Reader
174	Writer
175}
176
177// ReadWriteCloser is the interface implemented by types that can read and write
178// WireMessages and can also be closed.
179type ReadWriteCloser interface {
180	Reader
181	Writer
182	io.Closer
183}
184
185// Transformer is the interface implemented by types that can alter a WireMessage.
186// Implementations should not directly alter the provided WireMessage and instead
187// make a copy of the message, alter it, and returned the new message.
188type Transformer interface {
189	TransformWireMessage(WireMessage) (WireMessage, error)
190}
191
192// ReadFrom will read a single WireMessage from the given io.Reader. This function will
193// validate the WireMessage. If the WireMessage is not valid, this method will
194// return both the error and the invalid WireMessage. If another type of processing
195// error occurs, WireMessage will be nil.
196//
197// This function will return the immutable versions of wire protocol messages. The
198// Convert function can be used to retrieve a mutable version of wire protocol
199// messages.
200func ReadFrom(io.Reader) (WireMessage, error) { return nil, nil }
201
202// Unmarshal will unmarshal data into a WireMessage.
203func Unmarshal([]byte) (WireMessage, error) { return nil, nil }
204
205// Validate will validate that data is a valid MongoDB wire protocol message.
206func Validate([]byte) error { return nil }
207