class Vici::Message

The Message class provides the low level encoding and decoding of vici protocol messages. Directly using this class is usually not required.

Constants

KEY_VALUE
LIST_END
LIST_ITEM
LIST_START
SECTION_END
SECTION_START

Public Class Methods

new(data = "") click to toggle source
# File lib/vici.rb, line 92
def initialize(data = "")
  if data.nil?
    @root = {}
  elsif data.is_a?(Hash)
    @root = data
  else
    @encoded = data
  end
end

Public Instance Methods

encoding() click to toggle source

Get the raw byte encoding of an on-the-wire message

# File lib/vici.rb, line 104
def encoding
  @encoded = encode(@root) if @encoded.nil?
  @encoded
end
root() click to toggle source

Get the root element of the parsed ruby data structures

# File lib/vici.rb, line 111
def root
  @root = parse(@encoded) if @root.nil?
  @root
end

Private Instance Methods

encode(node) click to toggle source
# File lib/vici.rb, line 144
def encode(node)
  encoding = ""
  node.each do |key, value|
    encoding = if value.is_a?(Hash)
                 encode_section(encoding, key, value)
               elsif value.is_a?(Array)
                 encode_list(encoding, key, value)
               else
                 encode_kv(encoding, key, value)
               end
  end
  encoding
end
encode_kv(encoding, key, value) click to toggle source
# File lib/vici.rb, line 127
def encode_kv(encoding, key, value)
  encoding << KEY_VALUE << encode_name(key) << encode_value(value)
end
encode_list(encoding, key, value) click to toggle source
# File lib/vici.rb, line 136
def encode_list(encoding, key, value)
  encoding << LIST_START << encode_name(key)
  value.each do |item|
    encoding << LIST_ITEM << encode_value(item)
  end
  encoding << LIST_END
end
encode_name(name) click to toggle source
# File lib/vici.rb, line 118
def encode_name(name)
  [name.length].pack("c") << name
end
encode_section(encoding, key, value) click to toggle source
# File lib/vici.rb, line 131
def encode_section(encoding, key, value)
  encoding << SECTION_START << encode_name(key)
  encoding << encode(value) << SECTION_END
end
encode_value(value) click to toggle source
# File lib/vici.rb, line 122
def encode_value(value)
  value = value.to_s if value.class != String
  [value.length].pack("n") << value
end
parse(encoding) click to toggle source
# File lib/vici.rb, line 170
def parse(encoding)
  stack = [{}]
  list = nil
  until encoding.empty?
    type = encoding.unpack("c")[0]
    encoding = encoding[1..-1]
    case type
    when SECTION_START
      encoding, name = parse_name(encoding)
      stack.push(stack[-1][name] = {})
    when SECTION_END
      raise ParseError, "unexpected section end" if stack.length == 1
      stack.pop
    when KEY_VALUE
      encoding, name = parse_name(encoding)
      encoding, value = parse_value(encoding)
      stack[-1][name] = value
    when LIST_START
      encoding, name = parse_name(encoding)
      stack[-1][name] = []
      list = name
    when LIST_ITEM
      raise ParseError, "unexpected list item" if list.nil?
      encoding, value = parse_value(encoding)
      stack[-1][list].push(value)
    when LIST_END
      raise ParseError, "unexpected list end" if list.nil?
      list = nil
    else
      raise ParseError, "invalid type: #{type}"
    end
  end
  raise ParseError, "unexpected message end" if stack.length > 1
  stack[0]
end
parse_name(encoding) click to toggle source
# File lib/vici.rb, line 158
def parse_name(encoding)
  len = encoding.unpack("c")[0]
  name = encoding[1, len]
  [encoding[(1 + len)..-1], name]
end
parse_value(encoding) click to toggle source
# File lib/vici.rb, line 164
def parse_value(encoding)
  len = encoding.unpack("n")[0]
  value = encoding[2, len]
  [encoding[(2 + len)..-1], value]
end