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_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.
-
#deserialize_array(io, field, options = {}) ⇒ Array
private
Deserializes an array of fields in a message.
-
#deserialize_field(io, field, options = {}) ⇒ Object
private
Deserializes a single field into this message.
-
#fields ⇒ Array<Hash>
private
A method for getting the fields for a message class.
-
#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.
-
#serialize_fields(buffer, max_bson_size = nil) ⇒ String
private
Serializes message fields into a buffer.
-
#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).
231 232 233 234 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 |
# File 'lib/mongo/protocol/message.rb', line 231 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 .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_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
332 333 334 |
# File 'lib/mongo/protocol/message.rb', line 332 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
352 353 354 355 356 357 358 359 360 |
# File 'lib/mongo/protocol/message.rb', line 352 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
323 324 325 |
# File 'lib/mongo/protocol/message.rb', line 323 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.
283 284 285 286 287 288 289 290 291 |
# File 'lib/mongo/protocol/message.rb', line 283 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 |
#deserialize_array(io, field, options = {}) ⇒ Array
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
377 378 379 380 381 382 |
# File 'lib/mongo/protocol/message.rb', line 377 def 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(io, field, options = {}) ⇒ Object
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 into this message.
395 396 397 398 399 400 |
# File 'lib/mongo/protocol/message.rb', line 395 def deserialize_field(io, field, = {}) instance_variable_set( field[:name], field[:type].deserialize(io, ) ) end |
#fields ⇒ Array<Hash>
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 getting the fields for a message class
406 407 408 |
# File 'lib/mongo/protocol/message.rb', line 406 def fields self.class.fields end |
#hash ⇒ Fixnum
Creates a hash from the values of the fields of a message.
297 298 299 |
# File 'lib/mongo/protocol/message.rb', line 297 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.
171 172 173 |
# File 'lib/mongo/protocol/message.rb', line 171 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 |
# File 'lib/mongo/protocol/message.rb', line 150 def maybe_decrypt(_context) self end |
#maybe_encrypt(_connection, _context) ⇒ Mongo::Protocol::Msg
Possibly encrypt this message with libmongocrypt.
162 163 164 165 |
# File 'lib/mongo/protocol/message.rb', line 162 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.
315 316 317 |
# File 'lib/mongo/protocol/message.rb', line 315 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
196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/mongo/protocol/message.rb', line 196 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 |
#serialize_fields(buffer, max_bson_size = nil) ⇒ String
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.
Serializes message fields into a buffer
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 |
# File 'lib/mongo/protocol/message.rb', line 415 def serialize_fields(buffer, max_bson_size = nil) fields.each do |field| value = instance_variable_get(field[:name]) if field[:multi] value.each do |item| if field[:type].respond_to?(:size_limited?) field[:type].serialize(buffer, item, max_bson_size) else field[:type].serialize(buffer, item) end end elsif field[:type].respond_to?(:size_limited?) field[:type].serialize(buffer, value, max_bson_size) else field[:type].serialize(buffer, value) end end end |
#set_request_id ⇒ Fixnum
Generates a request id for a message
306 307 308 |
# File 'lib/mongo/protocol/message.rb', line 306 def set_request_id @request_id = self.class.next_id end |