Class: Mongo::Protocol::Message Abstract
- Inherits:
-
Object
- Object
- Mongo::Protocol::Message
- Includes:
- Id, Serializers
- Defined in:
- lib/mongo/protocol/message.rb
Overview
A base class providing functionality required by all messages in the MongoDB wire protocol. It provides a minimal DSL for defining typed fields to enable serialization and deserialization over the wire.
Direct Known Subclasses
Constant Summary collapse
- BATCH_SIZE =
The batch size constant.
'batchSize'- COLLECTION =
The collection constant.
'collection'- LIMIT =
The limit constant.
'limit'- ORDERED =
The ordered constant.
'ordered'- Q =
The q constant.
'q'- MAX_MESSAGE_SIZE =
Default max message size of 48MB.
50_331_648
Constants included from Serializers
Serializers::HEADER_PACK, Serializers::INT32_PACK, Serializers::INT64_PACK, Serializers::NULL, Serializers::ZERO
Instance Attribute Summary collapse
-
#request_id ⇒ Fixnum
readonly
Returns the request id for the message.
Class Method Summary collapse
-
.deserialize(io, max_message_size = MAX_MESSAGE_SIZE, expected_response_to = nil, options = {}) ⇒ Message
private
Deserializes messages from an IO stream.
-
.deserialize_array(message, io, field, options = {}) ⇒ Message
private
Deserializes an array of fields in a message.
-
.deserialize_field(message, io, field, options = {}) ⇒ Message
private
Deserializes a single field in a message.
-
.deserialize_header(io) ⇒ Array<Fixnum>
private
Deserializes the header of the message.
-
.field(name, type, multi = false) ⇒ NilClass
private
A method for declaring a message field.
-
.fields ⇒ Integer
private
A class method for getting the fields for a message class.
Instance Method Summary collapse
-
#==(other) ⇒ true, false
(also: #eql?)
Tests for equality between two wire protocol messages by comparing class and field values.
-
#hash ⇒ Fixnum
Creates a hash from the values of the fields of a message.
-
#initialize(*_args) ⇒ Message
constructor
:nodoc:.
-
#maybe_add_server_api(server_api) ⇒ Object
Protocol message subclasses that support the server api option should override this method to add the server api document to the message.
-
#maybe_compress(_compressor, _zlib_compression_level = nil) ⇒ self
private
Compress the message, if supported by the wire protocol used and if the command being sent permits compression.
-
#maybe_decrypt(_context) ⇒ Mongo::Protocol::Msg
Possibly decrypt this message with libmongocrypt.
-
#maybe_encrypt(_connection, _context) ⇒ Mongo::Protocol::Msg
Possibly encrypt this message with libmongocrypt.
-
#maybe_inflate ⇒ Protocol::Message
private
Inflate a message if it is compressed.
-
#number_returned ⇒ 0
Default number returned value for protocol messages.
-
#replyable? ⇒ false
The default for messages is not to require a reply after sending a message to the server.
-
#serialize(buffer = BSON::ByteBuffer.new, max_bson_size = nil, bson_overhead = nil) ⇒ String
(also: #to_s)
Serializes message into bytes that can be sent on the wire.
-
#set_request_id ⇒ Fixnum
Generates a request id for a message.
Methods included from Id
Constructor Details
#initialize(*_args) ⇒ Message
:nodoc:
77 78 79 |
# File 'lib/mongo/protocol/message.rb', line 77 def initialize(*_args) # :nodoc: set_request_id end |
Instance Attribute Details
#request_id ⇒ Fixnum (readonly)
Returns the request id for the message
84 85 86 |
# File 'lib/mongo/protocol/message.rb', line 84 def request_id @request_id end |
Class Method Details
.deserialize(io, max_message_size = MAX_MESSAGE_SIZE, expected_response_to = nil, options = {}) ⇒ Message
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Deserializes messages from an IO stream.
This method returns decompressed messages (i.e. if the message on the wire was OP_COMPRESSED, this method would typically return the OP_MSG message that is the result of decompression).
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/mongo/protocol/message.rb', line 235 def self.deserialize(io, = MAX_MESSAGE_SIZE, expected_response_to = nil, = {}) # io is usually a Mongo::Socket instance, which supports the # timeout option. For compatibility with whoever might call this # method with some other IO-like object, pass options only when they # are not empty. = .slice(:timeout, :socket_timeout) chunk = if .empty? io.read(16) else io.read(16, **) end buf = BSON::ByteBuffer.new(chunk) length, _request_id, response_to, _op_code = deserialize_header(buf) # Protection from potential DOS man-in-the-middle attacks. See # DRIVERS-276. raise Error::MaxMessageSize.new() if length > ( || MAX_MESSAGE_SIZE) # Protection against returning the response to a previous request. See # RUBY-1117 if expected_response_to && response_to != expected_response_to raise Error::UnexpectedResponse.new(expected_response_to, response_to) end chunk = if .empty? io.read(length - 16) else io.read(length - 16, **) end buf = BSON::ByteBuffer.new(chunk) = Registry.get(_op_code).allocate .send(:fields).each do |field| if field[:multi] deserialize_array(, buf, field, ) else deserialize_field(, buf, field, ) end end .fix_after_deserialization if .is_a?(Msg) .maybe_inflate end |
.deserialize_array(message, io, field, options = {}) ⇒ Message
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Deserializes an array of fields in a message
The number of items in the array must be described by a previously deserialized field specified in the class by the field dsl under the key :multi
382 383 384 385 386 387 |
# File 'lib/mongo/protocol/message.rb', line 382 def self.deserialize_array(, io, field, = {}) elements = [] count = .instance_variable_get(field[:multi]) count.times { elements << field[:type].deserialize(io, ) } .instance_variable_set(field[:name], elements) end |
.deserialize_field(message, io, field, options = {}) ⇒ Message
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Deserializes a single field in a message
401 402 403 404 405 406 |
# File 'lib/mongo/protocol/message.rb', line 401 def self.deserialize_field(, io, field, = {}) .instance_variable_set( field[:name], field[:type].deserialize(io, ) ) end |
.deserialize_header(io) ⇒ Array<Fixnum>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Deserializes the header of the message
336 337 338 |
# File 'lib/mongo/protocol/message.rb', line 336 def self.deserialize_header(io) Header.deserialize(io) end |
.field(name, type, multi = false) ⇒ NilClass
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
A method for declaring a message field
356 357 358 359 360 361 362 363 364 |
# File 'lib/mongo/protocol/message.rb', line 356 def self.field(name, type, multi = false) fields << { name: :"@#{name}", type: type, multi: multi } attr_reader name end |
.fields ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
A class method for getting the fields for a message class
327 328 329 |
# File 'lib/mongo/protocol/message.rb', line 327 def self.fields @fields ||= [] end |
Instance Method Details
#==(other) ⇒ true, false Also known as: eql?
Tests for equality between two wire protocol messages by comparing class and field values.
287 288 289 290 291 292 293 294 295 |
# File 'lib/mongo/protocol/message.rb', line 287 def ==(other) return false if self.class != other.class fields.all? do |field| name = field[:name] instance_variable_get(name) == other.instance_variable_get(name) end end |
#hash ⇒ Fixnum
Creates a hash from the values of the fields of a message.
301 302 303 |
# File 'lib/mongo/protocol/message.rb', line 301 def hash fields.map { |field| instance_variable_get(field[:name]) }.hash end |
#maybe_add_server_api(server_api) ⇒ Object
Protocol message subclasses that support the server api option should override this method to add the server api document to the message.
175 176 177 |
# File 'lib/mongo/protocol/message.rb', line 175 def maybe_add_server_api(server_api) raise NotImplementedError end |
#maybe_compress(_compressor, _zlib_compression_level = nil) ⇒ self
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Compress the message, if supported by the wire protocol used and if the command being sent permits compression. Otherwise returns self.
110 111 112 |
# File 'lib/mongo/protocol/message.rb', line 110 def maybe_compress(_compressor, _zlib_compression_level = nil) self end |
#maybe_decrypt(_context) ⇒ Mongo::Protocol::Msg
Possibly decrypt this message with libmongocrypt.
150 151 152 153 154 155 156 |
# File 'lib/mongo/protocol/message.rb', line 150 def maybe_decrypt(_context) # TODO: determine if we should be decrypting data coming from pre-4.2 # servers, potentially using legacy wire protocols. If so we need # to implement decryption for those wire protocols as our current # encryption/decryption code is OP_MSG-specific. self end |
#maybe_encrypt(_connection, _context) ⇒ Mongo::Protocol::Msg
Possibly encrypt this message with libmongocrypt.
166 167 168 169 |
# File 'lib/mongo/protocol/message.rb', line 166 def maybe_encrypt(_connection, _context) # Do nothing if the Message subclass has not implemented this method self end |
#maybe_inflate ⇒ Protocol::Message
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Inflate a message if it is compressed.
140 141 142 |
# File 'lib/mongo/protocol/message.rb', line 140 def maybe_inflate self end |
#number_returned ⇒ 0
Default number returned value for protocol messages.
319 320 321 |
# File 'lib/mongo/protocol/message.rb', line 319 def number_returned 0 end |
#replyable? ⇒ false
The default for messages is not to require a reply after sending a message to the server.
95 96 97 |
# File 'lib/mongo/protocol/message.rb', line 95 def replyable? false end |
#serialize(buffer = BSON::ByteBuffer.new, max_bson_size = nil, bson_overhead = nil) ⇒ String Also known as: to_s
Serializes message into bytes that can be sent on the wire
200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/mongo/protocol/message.rb', line 200 def serialize(buffer = BSON::ByteBuffer.new, max_bson_size = nil, bson_overhead = nil) max_size = if max_bson_size && bson_overhead max_bson_size + bson_overhead elsif max_bson_size max_bson_size end start = buffer.length serialize_header(buffer) serialize_fields(buffer, max_size) buffer.replace_int32(start, buffer.length - start) end |
#set_request_id ⇒ Fixnum
Generates a request id for a message
310 311 312 |
# File 'lib/mongo/protocol/message.rb', line 310 def set_request_id @request_id = self.class.next_id end |