#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'rubygems' require 'json' require 'time' require 'uri' require 'azure/service_bus/brokered_message' module Azure module ServiceBus # BrokeredMessageSerializer class BrokeredMessageSerializer PROPERTIES = { 'ContentType' => 'content_type', 'CorrelationId' => 'correlation_id', 'SessionID' => 'session_id', 'DeliveryCount' => 'delivery_count', 'LockedUntilUtc' => 'locked_until_utc', 'LockToken' => 'lock_token', 'MessageId' => 'message_id', 'Label' => 'label', 'ReplyTo' => 'reply_to', 'EnqueuedTimeUtc' => 'enqueued_time_utc', 'SequenceNumber' => 'sequence_number', 'TimeToLive' => 'time_to_live', 'To' => 'to', 'ScheduledEnqueueTimeUtc' => 'scheduled_enqueue_time_utc', 'ReplyToSessionId' => 'reply_to_session_id' }.freeze attr_reader :message def initialize(msg) @message = msg end def self.get_from_http_response(response) props = JSON.parse(response.headers['brokerproperties']) BrokeredMessage.new(response.body) do |m| loc_header = response.headers['location'] m.location = URI(loc_header) unless loc_header.nil? m.content_type = response.headers['content-type'] # String based properties m.lock_token = props['LockToken'] m.message_id = props['MessageId'] m.label = props['Label'] m.to = props['To'] m.session_id = props['SessionID'] m.correlation_id = props['CorrelationId'] m.reply_to = props['ReplyTo'] m.reply_to = props['ReplyTo'] m.reply_to_session_id = props['ReplyToSessionId'] # Time based properties utc_lock = props['LockedUntilUtc'] m.locked_until_utc = Time.parse(utc_lock) unless utc_lock.nil? enqueued_time_utc = self.parse_dot_net_serialized_datetime( props['EnqueuedTimeUtc'] ) unless props['EnqueuedTimeUtc'].nil? m.enqueued_time_utc = enqueued_time_utc unless enqueued_time_utc.nil? m.scheduled_enqueue_time_utc = Time.parse( props['ScheduledEnqueueTimeUtc'] ) unless props['ScheduledEnqueueTimeUtc'].nil? # Numeric based properties m.delivery_count = props['DeliveryCount'].to_i m.sequence_number = props['SequenceNumber'].to_i m.time_to_live = props['TimeToLive'].to_f # Custom Properties header_names_black_list = %w( brokerproperties date transfer-encoding location server connection content-type content-length strict-transport-security ) props = response.headers.reject do |k, _| header_names_black_list.include?(k.downcase) end props.each do |prop_name, value| parsed = JSON.parse('{ "' + prop_name + '" : ' + value + '}') m.properties[prop_name] = parsed[prop_name] end end end # Serialize the message's attributes to JSON # # Returns a JSON String def to_json hash = {} PROPERTIES.each do |p, u| attr_name = u.encode('UTF-8') value = @message.send(attr_name) hash[p] = value.to_s.encode('UTF-8') unless value.nil? end hash.to_json end # Build a hash based on message properties and ensure # the values are in a valid format for HTTP headers # # Returns a Hash def get_property_headers hash = {} @message.properties.each do |name, value| value = value.httpdate if !value.nil? && value.class == Time tmp = JSON.generate [value] hash[name] = tmp[1..(tmp.length - 2)] end hash end private # Take the .net json serialization of a DateTime (i.e. /Date(...)/) # and return a time object # # Returns a Time instance def self.parse_dot_net_serialized_datetime(datetime) begin Time.parse(datetime) rescue milliseconds_in_second = 1000 match = /\/Date\((\d+)\)\//.match(datetime) if !match.nil? ticks = match[1].to_i Time.at(ticks / milliseconds_in_second) else nil end end end end end end