lib/amqp/client/properties.rb in amqp-client-1.1.0 vs lib/amqp/client/properties.rb in amqp-client-1.1.1

- old
+ new

@@ -21,174 +21,208 @@ @type = type @user_id = user_id @app_id = app_id end + # Properties as a Hash + # @return [Hash] Properties + def to_h + { + content_type: content_type, + content_encoding: content_encoding, + headers: headers, + delivery_mode: delivery_mode, + priority: priority, + correlation_id: correlation_id, + reply_to: reply_to, + expiration: expiration, + message_id: message_id, + timestamp: timestamp, + type: type, + user_id: user_id, + app_id: app_id + } + end + + alias to_hash to_h + + # Returns true if two Property objects holds the same information + # @return [Boolean] + def ==(other) + return false unless other.is_a? self.class + + instance_variables.all? { |v| instance_variable_get(v) == other.instance_variable_get(v) } + end + # Content type of the message body # @return [String, nil] attr_accessor :content_type # Content encoding of the body # @return [String, nil] attr_accessor :content_encoding - # Custom headers + # Headers, for applications and header exchange routing # @return [Hash<String, Object>, nil] attr_accessor :headers - # 2 for persisted message, transient messages for all other values - # @return [Integer, nil] + # Message persistent level + # @note The exchange and queue have to durable as well for the message to be persistent + # @return [1] Transient message + # @return [2] Persistent message + # @return [nil] Not specified (implicitly transient) attr_accessor :delivery_mode # A priority of the message (between 0 and 255) # @return [Integer, nil] attr_accessor :priority - # A correlation id, most often used used for RPC communication - # @return [Integer, nil] + # Message correlation id, commonly used to correlate RPC requests and responses + # @return [String, nil] attr_accessor :correlation_id # Queue to reply RPC responses to # @return [String, nil] attr_accessor :reply_to # Number of seconds the message will stay in the queue - # @return [Integer] - # @return [String] - # @return [nil] + # @return [String, nil] attr_accessor :expiration + # Application message identifier # @return [String, nil] attr_accessor :message_id - # User-definable, but often used for the time the message was originally generated + # Message timestamp, often indicates when the message was originally generated # @return [Date, nil] attr_accessor :timestamp - # User-definable, but can can indicate what kind of message this is + # Message type name # @return [String, nil] attr_accessor :type - # User-definable, but can be used to verify that this is the user that published the message + # The user that published the message # @return [String, nil] attr_accessor :user_id - # User-definable, but often indicates which app that generated the message + # Name of application that generated the message # @return [String, nil] attr_accessor :app_id # Encode properties into a byte array + # @param properties [Hash] # @return [String] byte array - def encode + def self.encode(properties) + return "\x00\x00" if properties.empty? + flags = 0 arr = [flags] - fmt = StringIO.new(String.new("S>", capacity: 35)) - fmt.pos = 2 + fmt = String.new("S>", capacity: 37) - if content_type + if (content_type = properties[:content_type]) content_type.is_a?(String) || raise(ArgumentError, "content_type must be a string") flags |= (1 << 15) arr << content_type.bytesize << content_type fmt << "Ca*" end - if content_encoding + if (content_encoding = properties[:content_encoding]) content_encoding.is_a?(String) || raise(ArgumentError, "content_encoding must be a string") flags |= (1 << 14) arr << content_encoding.bytesize << content_encoding fmt << "Ca*" end - if headers + if (headers = properties[:headers]) headers.is_a?(Hash) || raise(ArgumentError, "headers must be a hash") flags |= (1 << 13) tbl = Table.encode(headers) arr << tbl.bytesize << tbl fmt << "L>a*" end - if delivery_mode + if (delivery_mode = properties[:delivery_mode]) delivery_mode.is_a?(Integer) || raise(ArgumentError, "delivery_mode must be an int") - delivery_mode.between?(0, 2) || raise(ArgumentError, "delivery_mode must be be between 0 and 2") flags |= (1 << 12) arr << delivery_mode fmt << "C" end - if priority + if (priority = properties[:priority]) priority.is_a?(Integer) || raise(ArgumentError, "priority must be an int") + flags |= (1 << 11) arr << priority fmt << "C" end - if correlation_id - priority.is_a?(String) || raise(ArgumentError, "correlation_id must be a string") + if (correlation_id = properties[:correlation_id]) + correlation_id.is_a?(String) || raise(ArgumentError, "correlation_id must be a string") flags |= (1 << 10) arr << correlation_id.bytesize << correlation_id fmt << "Ca*" end - if reply_to + if (reply_to = properties[:reply_to]) reply_to.is_a?(String) || raise(ArgumentError, "reply_to must be a string") flags |= (1 << 9) arr << reply_to.bytesize << reply_to fmt << "Ca*" end - if expiration - self.expiration = expiration.to_s if expiration.is_a?(Integer) + if (expiration = properties[:expiration]) + expiration = expiration.to_s if expiration.is_a?(Integer) expiration.is_a?(String) || raise(ArgumentError, "expiration must be a string or integer") flags |= (1 << 8) arr << expiration.bytesize << expiration fmt << "Ca*" end - if message_id + if (message_id = properties[:message_id]) message_id.is_a?(String) || raise(ArgumentError, "message_id must be a string") flags |= (1 << 7) arr << message_id.bytesize << message_id fmt << "Ca*" end - if timestamp + if (timestamp = properties[:timestamp]) timestamp.is_a?(Integer) || timestamp.is_a?(Time) || raise(ArgumentError, "timestamp must be an Integer or a Time") flags |= (1 << 6) arr << timestamp.to_i fmt << "Q>" end - if type + if (type = properties[:type]) type.is_a?(String) || raise(ArgumentError, "type must be a string") flags |= (1 << 5) arr << type.bytesize << type fmt << "Ca*" end - if user_id + if (user_id = properties[:user_id]) user_id.is_a?(String) || raise(ArgumentError, "user_id must be a string") flags |= (1 << 4) arr << user_id.bytesize << user_id fmt << "Ca*" end - if app_id + if (app_id = properties[:app_id]) app_id.is_a?(String) || raise(ArgumentError, "app_id must be a string") flags |= (1 << 3) arr << app_id.bytesize << app_id fmt << "Ca*" end arr[0] = flags - arr.pack(fmt.string) + arr.pack(fmt) end # Decode a byte array # @return [Properties] - def self.decode(bytes) + def self.decode(bytes, pos = 0) p = new - flags = bytes.unpack1("S>") - pos = 2 + flags = bytes.byteslice(pos, 2).unpack1("S>") + pos += 2 if (flags & 0x8000).positive? len = bytes.getbyte(pos) pos += 1 p.content_type = bytes.byteslice(pos, len).force_encoding("utf-8") pos += len