class Poseidon::Protocol::ProtocolStruct

Public Class Methods

new(hash) click to toggle source
Calls superclass method
# File lib/poseidon/protocol/protocol_struct.rb, line 7
def self.new(hash)
  klass = super(*hash.keys)
  klass.type_map = hash
  klass
end
prepend_crc32() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 26
def self.prepend_crc32
  @prepend_crc32 = true
  self
end
prepend_crc32?() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 40
def self.prepend_crc32?
  @prepend_crc32
end
prepend_size() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 21
def self.prepend_size
  @prepend_size = true
  self
end
prepend_size?() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 36
def self.prepend_size?
  @prepend_size
end
read(buffer) click to toggle source

Populate struct from buffer based on members and their type definition.

# File lib/poseidon/protocol/protocol_struct.rb, line 153
def self.read(buffer)
  s = new
  s.read(buffer)
  s
end
size_bound_array(member) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 48
def self.size_bound_array(member)
  @size_bound_members ||= []
  @size_bound_members  << member
  self
end
size_bound_array?(member) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 54
def self.size_bound_array?(member)
  @size_bound_members ||= []
  @size_bound_members.include?(member)
end
truncatable() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 31
def self.truncatable
  @truncatable = true
  self
end
truncatable?() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 44
def self.truncatable?
  @truncatable
end
type_map() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 17
def self.type_map
  @type_map 
end
type_map=(type_map) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 13
def self.type_map=(type_map)
  @type_map = type_map
end

Public Instance Methods

checksum_failed?() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 247
def checksum_failed?
  @checksum_failed
end
error_class() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 89
def error_class
  Errors::ERROR_CODES[self[:error]]
end
have_header?(buffer) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 197
def have_header?(buffer)
  if self.class.truncatable?
    if self.class.prepend_crc32?
      header_bytes = 8
    else
      header_bytes = 4
    end

    return buffer.bytes_remaining >= header_bytes
  else
    return true
  end
end
maybe_prepend_crc32(buffer) { || ... } click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 123
def maybe_prepend_crc32(buffer)
  if self.class.prepend_crc32?
    buffer.prepend_crc32 do
      yield
    end
  else
    yield
  end
end
maybe_prepend_size(buffer) { || ... } click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 113
def maybe_prepend_size(buffer)
  if self.class.prepend_size?
    buffer.prepend_size do
      yield
    end
  else
    yield
  end
end
objects_with_errors() click to toggle source

Recursively find all objects with errors

# File lib/poseidon/protocol/protocol_struct.rb, line 60
def objects_with_errors
  children = []
  each_pair do |member, value|
    case value
    when Array
      value.each do |v|
        if v.respond_to?(:objects_with_errors)
          children << v
        end
      end
    else
      if value.respond_to?(:objects_with_errors)
        children << value
      end
    end
  end

  children_with_errors = children.map(&:objects_with_errors).flatten
  if members.include?(:error) && self[:error] != Errors::NO_ERROR_CODE
    children_with_errors + [self]
  else
    children_with_errors
  end
end
raise_error() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 85
def raise_error
  raise error_class if error_class
end
raise_error_if_one_exists() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 93
def raise_error_if_one_exists
  objects_with_errors.each do |object|
    object.raise_error
  end
end
read(buffer) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 159
def read(buffer)
  if self.class.prepend_size?
    if !have_header?(buffer)
      @truncated = true
      return
    end

    @size = buffer.int32

    if self.class.prepend_crc32?
      @crc32 = buffer.int32
      @computed_crc32 = [Zlib::crc32(buffer.peek(@size-4))].pack("l>").unpack("l>").first
      if @crc32 != @computed_crc32
        @checksum_failed = true
      end
      expected_bytes_remaining = @size - 4
    else
      expected_bytes_remaining = @size
    end

    if self.class.truncatable? && expected_bytes_remaining > buffer.bytes_remaining
      @truncated = true
      return
    end
  end

  members.each do |member|
    begin
      self[member] = read_member(buffer, member)
    rescue DecodingError
      # Just reraise instead of producing a crazy nested exception
      raise
    rescue
      raise DecodingError, "Error while reading #{member} in #{self.class} (#{$!.class}: #{$!.message}))"
    end
  end
end
read_member(buffer, member) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 211
def read_member(buffer, member)
  case type = type_map[member]
  when Array
    if self.class.size_bound_array?(member)
      if @size
        array_buffer = ResponseBuffer.new(buffer.read(@size))
      else
        array_buffer = buffer
      end

      array = []
      while !array_buffer.eof? && (v = read_type(array_buffer, type.first))
        array << v
      end
      array
    else
      buffer.int32.times.map { read_type(buffer, type.first) }
    end
  else
    read_type(buffer, type)
  end
end
read_type(buffer, type) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 234
def read_type(buffer, type)
  case type
  when Symbol
    buffer.send(type)
  else
    type.read(buffer)
  end
end
truncated?() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 251
def truncated?
  @truncated
end
type_map() click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 243
def type_map
  self.class.type_map
end
write(buffer) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 99
def write(buffer)
  maybe_prepend_size(buffer) do
    maybe_prepend_crc32(buffer) do
      each_pair do |member, value|
        begin
          write_member(buffer, member, value)
        rescue
          raise EncodingError, "Error writting #{member} in #{self.class} (#{$!.class}: #{$!.message})"
        end
      end
    end
  end
end
write_member(buffer, member, value) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 133
def write_member(buffer, member, value)
  case type = type_map[member]
  when Array
    buffer.int32(value.size) unless self.class.size_bound_array?(member)
    value.each { |v| write_type(buffer, type.first, v) }
  else
    write_type(buffer, type, value)
  end
end
write_type(buffer, type, value) click to toggle source
# File lib/poseidon/protocol/protocol_struct.rb, line 143
def write_type(buffer, type, value)
  case type
  when Symbol
    buffer.send(type, value)
  else
    value.write(buffer)
  end
end