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"]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePacket

Returns a new instance of Packet.

Raises:

  • (NotImplementedError)


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

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



60
61
62
# File 'lib/right_agent/packets.rb', line 60

def received_at
  @received_at
end

#sizeObject

(Integer) Size of packet in bytes



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

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



228
229
230
# File 'lib/right_agent/packets.rb', line 228

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



87
88
89
# File 'lib/right_agent/packets.rb', line 87

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



76
77
78
# File 'lib/right_agent/packets.rb', line 76

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



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

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



199
200
201
202
# File 'lib/right_agent/packets.rb', line 199

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



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

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



146
147
148
# File 'lib/right_agent/packets.rb', line 146

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



244
245
246
# File 'lib/right_agent/packets.rb', line 244

def one_way
  true
end

#recv_versionObject

Retrieve protocol version of original creator of packet

Return

(Integer) Received protocol version



262
263
264
# File 'lib/right_agent/packets.rb', line 262

def recv_version
  @version[0]
end

#send_versionObject

Retrieve protocol version of packet for use when sending packet

Return

(Integer) Send protocol version



270
271
272
# File 'lib/right_agent/packets.rb', line 270

def send_version
  @version[1]
end

#send_version=(value) ⇒ Object

Set protocol version of packet for use when sending packet



275
276
277
# File 'lib/right_agent/packets.rb', line 275

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

#target_for_encryptionObject

Get target to be used for encrypting the packet

Return

(String)

Target



236
237
238
# File 'lib/right_agent/packets.rb', line 236

def target_for_encryption
  nil
end

#to_json(*a) ⇒ Object

Marshal packet into JSON format

Parameters

a(Array)

Arguments

Return

js(String)

Marshalled packet



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

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



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

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 ruby 1.9 size attribute moves from front to back of packet
  re = RUBY_VERSION < "1.9.0" ? Regexp.new("size\xC0") : Regexp.new("size\xC0$", nil, "n")
  # For msgpack 0.5.1 the to_msgpack result is a MessagePack::Packer so need to convert to string
  msg = msg.to_s.sub!(re) { |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



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

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



252
253
254
255
256
# File 'lib/right_agent/packets.rb', line 252

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