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'.freeze
- COLLECTION =
The collection constant.
'collection'.freeze
- LIMIT =
The limit constant.
'limit'.freeze
- ORDERED =
The ordered constant.
'ordered'.freeze
- Q =
The q constant.
'q'.freeze
- MAX_MESSAGE_SIZE =
Default max message size of 48MB.
50331648.freeze
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
Deserializes an array of fields in a message.
-
.deserialize_field(message, io, field, options = {}) ⇒ Message
Deserializes a single field in a message.
-
.deserialize_header(io) ⇒ Array<Fixnum>
Deserializes the header of the message.
-
.field(name, type, multi = false) ⇒ NilClass
A method for declaring a message field.
-
.fields ⇒ Integer
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
-
#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:
79 80 81 |
# File 'lib/mongo/protocol/message.rb', line 79 def initialize(*args) # :nodoc: set_request_id end |
Instance Attribute Details
#request_id ⇒ Fixnum (readonly)
Returns the request id for the message
86 87 88 |
# File 'lib/mongo/protocol/message.rb', line 86 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).
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 281 282 283 284 285 286 287 288 |
# File 'lib/mongo/protocol/message.rb', line 238 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) if .empty? chunk = io.read(16) else chunk = 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. if length > ( || MAX_MESSAGE_SIZE) raise Error::MaxMessageSize.new() end # 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 if .empty? chunk = io.read(length - 16) else chunk = 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 if .is_a?(Msg) .fix_after_deserialization end .maybe_inflate end |
.deserialize_array(message, io, field, options = {}) ⇒ Message
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
432 433 434 435 436 437 |
# File 'lib/mongo/protocol/message.rb', line 432 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
Deserializes a single field in a message
450 451 452 453 454 455 |
# File 'lib/mongo/protocol/message.rb', line 450 def self.deserialize_field(, io, field, = {}) .instance_variable_set( field[:name], field[:type].deserialize(io, ) ) end |
.deserialize_header(io) ⇒ Array<Fixnum>
Deserializes the header of the message
388 389 390 |
# File 'lib/mongo/protocol/message.rb', line 388 def self.deserialize_header(io) Header.deserialize(io) end |
.field(name, type, multi = false) ⇒ NilClass
A method for declaring a message field
407 408 409 410 411 412 413 414 415 |
# File 'lib/mongo/protocol/message.rb', line 407 def self.field(name, type, multi = false) fields << { :name => "@#{name}".intern, :type => type, :multi => multi } attr_reader name end |
.fields ⇒ Integer
A class method for getting the fields for a message class
340 341 342 |
# File 'lib/mongo/protocol/message.rb', line 340 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.
295 296 297 298 299 300 301 302 |
# File 'lib/mongo/protocol/message.rb', line 295 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.
308 309 310 |
# File 'lib/mongo/protocol/message.rb', line 308 def hash fields.map { |field| instance_variable_get(field[:name]) }.hash end |
#maybe_add_server_api(server_api) ⇒ Object
173 174 175 |
# File 'lib/mongo/protocol/message.rb', line 173 def maybe_add_server_api(server_api) raise Error::ServerApiNotSupported, "Server API parameters cannot be sent to pre-3.6 MongoDB servers. Please remove the :server_api parameter from Client options or use MongoDB 3.6 or newer" 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.
112 113 114 |
# File 'lib/mongo/protocol/message.rb', line 112 def maybe_compress(compressor, zlib_compression_level = nil) self end |
#maybe_decrypt(context) ⇒ Mongo::Protocol::Msg
Possibly decrypt this message with libmongocrypt.
152 153 154 155 156 157 158 |
# File 'lib/mongo/protocol/message.rb', line 152 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.
168 169 170 171 |
# File 'lib/mongo/protocol/message.rb', line 168 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.
142 143 144 |
# File 'lib/mongo/protocol/message.rb', line 142 def maybe_inflate self end |
#number_returned ⇒ 0
Default number returned value for protocol messages.
326 |
# File 'lib/mongo/protocol/message.rb', line 326 def number_returned; 0; end |
#replyable? ⇒ false
The default for messages is not to require a reply after sending a message to the server.
97 98 99 |
# File 'lib/mongo/protocol/message.rb', line 97 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
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/mongo/protocol/message.rb', line 201 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 else nil 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
317 318 319 |
# File 'lib/mongo/protocol/message.rb', line 317 def set_request_id @request_id = self.class.next_id end |