Class: RightScale::Packet

Inherits:
Object show all
Defined in:
lib/right_agent/packets.rb

Overview

Base class for all packets flowing through the RightNet routers Knows how to dump itself to MessagePack or JSON

Direct Known Subclasses

Push, Request, Result, Stats

Constant Summary collapse

VERSION =

Current version of protocol

AgentConfig.protocol_version
DEFAULT_VERSION =

Default version for packet senders unaware of this versioning

0
GLOBAL =

Shard scope value meaning restrict sending request only to agents with no shard id

0
NOT_SERIALIZED =

Instance variables that are not serialized because they are only used locally

["received_at"]
PACKET_SIZE_REGEXP =

Regexp for inserting packet size into msgpack encoded packet For ruby 1.9 size attribute moves from front to back of packet

RUBY_VERSION < "1.9.0" ? Regexp.new("size\xC0", nil, "n") : Regexp.new("size\xC0$", nil, "n")

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePacket

Returns a new instance of Packet.

Raises:

  • (NotImplementedError)


69
70
71
# File 'lib/right_agent/packets.rb', line 69

def initialize
  raise NotImplementedError.new("#{self.class.name} is an abstract class.")
end

Instance Attribute Details

#received_atObject

(Float) Time in seconds in Unix-epoch when message was received



64
65
66
# File 'lib/right_agent/packets.rb', line 64

def received_at
  @received_at
end

#sizeObject

(Integer) Size of packet in bytes



67
68
69
# File 'lib/right_agent/packets.rb', line 67

def size
  @size
end

Class Method Details

.compatible(id) ⇒ Object

Convert serialized AgentIdentity to compatible format

Parameters

id(String)

Serialized identity

Return

(String)

Compatible serialized identity



230
231
232
# File 'lib/right_agent/packets.rb', line 230

def self.compatible(id)
  AgentIdentity.compatible_serialized(id)
end

.json_create(o) ⇒ Object

Create packet from unmarshalled JSON data

Parameters

o(Hash)

MessagePack data

Return

(Packet)

New packet



91
92
93
# File 'lib/right_agent/packets.rb', line 91

def self.json_create(o)
  create(o)
end

.msgpack_create(o) ⇒ Object

Create packet from unmarshalled MessagePack data

Parameters

o(Hash)

MessagePack data

Return

(Packet)

New packet



80
81
82
# File 'lib/right_agent/packets.rb', line 80

def self.msgpack_create(o)
  create(o)
end

Instance Method Details

#enough_precision(value) ⇒ Object

Determine enough precision for floating point value to give at least two significant digits and then convert the value to a decimal digit string of that precision

Parameters

value(Float)

Value to be converted

Return

(String)

Floating point digit string



181
182
183
184
185
186
187
188
189
190
191
# File 'lib/right_agent/packets.rb', line 181

def enough_precision(value)
  scale = [1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0]
  enough = lambda { |v| (v >= 10.0   ? 0 :
                        (v >= 1.0    ? 1 :
                        (v >= 0.1    ? 2 :
                        (v >= 0.01   ? 3 :
                        (v >  0.001  ? 4 :
                        (v >  0.0    ? 5 : 0)))))) }
  digit_str = lambda { |p, v| sprintf("%.#{p}f", (v * scale[p]).round / scale[p])}
  digit_str.call(enough.call(value), value)
end

#id_to_s(id) ⇒ Object

Generate log friendly serialized identity Result marked with leading ‘*’ if not same as original identity

Parameters

id(String)

Serialized identity

Return

(String)

Log friendly serialized identity



201
202
203
204
# File 'lib/right_agent/packets.rb', line 201

def id_to_s(id)
  modified_id = AgentIdentity.compatible_serialized(id)
  if id == modified_id then modified_id else "*#{modified_id}" end
end

#ids_to_s(ids) ⇒ Object

Generate log friendly serialized identity for one or more ids Limit to 1000 bytes

Parameters

ids(Array|String)

Serialized identity or array of serialized identities

Return

(String)

Log friendly serialized identity



214
215
216
217
218
219
220
221
# File 'lib/right_agent/packets.rb', line 214

def ids_to_s(ids)
  if ids.is_a?(Array)
    s = ids.each { |i| id_to_s(i) }.join(', ')
    s.size > 1000 ? "[#{s[0, 1000]}...]" : "[#{s}]"
  else
    id_to_s(ids)
  end
end

#nameObject

Name of packet in lower snake case

Return

(String)

Packet name



148
149
150
# File 'lib/right_agent/packets.rb', line 148

def name
   self.class.to_s.split('::').last.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
end

#one_wayObject

Whether the packet is one that does not have an associated response

Return

(Boolean)

Defaults to true



246
247
248
# File 'lib/right_agent/packets.rb', line 246

def one_way
  true
end

#recv_versionObject

Retrieve protocol version of original creator of packet

Return

(Integer) Received protocol version



264
265
266
# File 'lib/right_agent/packets.rb', line 264

def recv_version
  @version[0]
end

#send_versionObject

Retrieve protocol version of packet for use when sending packet

Return

(Integer) Send protocol version



272
273
274
# File 'lib/right_agent/packets.rb', line 272

def send_version
  @version[1]
end

#send_version=(value) ⇒ Object

Set protocol version of packet for use when sending packet



277
278
279
# File 'lib/right_agent/packets.rb', line 277

def send_version=(value)
  @version[1] = value
end

#target_for_encryptionObject

Get target to be used for encrypting the packet

Return

(String)

Target



238
239
240
# File 'lib/right_agent/packets.rb', line 238

def target_for_encryption
  nil
end

#to_json(*a) ⇒ Object

Marshal packet into JSON format

Parameters

a(Array)

Arguments

Return

js(String)

Marshalled packet



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/right_agent/packets.rb', line 125

def to_json(*a)
  # Hack to override RightScale namespace with Nanite for downward compatibility
  class_name = self.class.name
  if class_name =~ /^RightScale::(.*)/
    class_name = "Nanite::" + Regexp.last_match(1)
  end

  js = {
    'json_class' => class_name,
    'data'       => instance_variables.inject({}) do |m, ivar|
                      name = ivar.to_s.sub(/@/, '')
                      m[name] = instance_variable_get(ivar) unless NOT_SERIALIZED.include?(name)
                      m
                    end
  }.to_json(*a)
  @size = js.size
  js = js.chop + ",\"size\":#{@size}}"
end

#to_msgpack(*a) ⇒ Object

Marshal packet into MessagePack format

Parameters

a(Array)

Arguments

Return

msg(String)

Marshalled packet



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/right_agent/packets.rb', line 102

def to_msgpack(*a)
  msg = {
    'msgpack_class' => self.class.name,
    'data'          => instance_variables.inject({}) do |m, ivar|
                         name = ivar.to_s.sub(/@/, '')
                         m[name] = instance_variable_get(ivar) unless NOT_SERIALIZED.include?(name)
                         m
                       end,
    'size'          => nil
  }.to_msgpack(*a)
  @size = msg.size
  # For msgpack 0.5.1 the to_msgpack result is a MessagePack::Packer so need to convert to string
  msg = msg.to_s.sub!(PACKET_SIZE_REGEXP) { |m| "size" + @size.to_msgpack }
  msg
end

#to_s(filter = nil, version = nil) ⇒ Object

Generate log representation

Parameters

filter(Array(Symbol))

Attributes to be included in output

version(Symbol|nil)

Version to display: :recv_version, :send_version, or nil meaning none

Return

log_msg(String)

Log representation



160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/right_agent/packets.rb', line 160

def to_s(filter = nil, version = nil)
  v = send(version) if version
  v = (v && v != DEFAULT_VERSION) ? " v#{v}" : ""
  log_msg = "[#{name}#{v}]"
  duration = if @duration && (filter.nil? || filter.include?(:duration))
    ", #{enough_precision(@duration)} sec"
  elsif @received_at && (filter.nil? || filter.include?(:local_duration))
    ", #{enough_precision(Time.now.to_f - @received_at)} sec"
  end
  log_msg += " (#{@size.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")} bytes#{duration})" if @size && !@size.to_s.empty?
  log_msg
end

#traceObject

Generate token used to trace execution of operation across multiple packets

Return

tr(String)

Trace token, may be empty



254
255
256
257
258
# File 'lib/right_agent/packets.rb', line 254

def trace
  audit_id = self.respond_to?(:payload) && payload.is_a?(Hash) && (payload['audit_id'] || payload[:audit_id])
  tok = self.respond_to?(:token) && token
  tr = "<#{audit_id || nil}> <#{tok}>"
end