class Pio::OpenFlow::Message

OpenFlow messages.

Attributes

format[R]

Public Class Methods

method_missing(method, *args, &block) click to toggle source

rubocop:disable MethodLength rubocop:disable AbcSize

# File lib/pio/open_flow/message.rb, line 32
def self.method_missing(method, *args, &block)
  begin
    const_get(:Format).__send__ method, *args, &block
  rescue NameError
    klass = Class.new(BinData::Record)
    const_set :Format, klass
    klass.class_eval do
      include RubyDumper
      define_method(:header_length) { 8 }
      define_method(:length) { _length }
    end
    class_variable_set(:@@valid_options, [])
    retry
  end

  return if method == :endian || method == :virtual

  define_method(args.first) do
    snapshot = @format.snapshot.__send__(args.first)
    if snapshot.class == BinData::Struct::Snapshot
      @format.__send__(args.first)
    else
      snapshot
    end
  end
  class_variable_set(:@@valid_options,
                     class_variable_get(:@@valid_options) + [args.first])
end
new(user_options = {}) click to toggle source

rubocop:enable AbcSize rubocop:enable MethodLength

# File lib/pio/open_flow/message.rb, line 92
def initialize(user_options = {})
  validate_user_options user_options
  @format = self.class.const_get(:Format).new(parse_options(user_options))
end
open_flow_header(opts) click to toggle source

rubocop:disable AbcSize rubocop:disable MethodLength

# File lib/pio/open_flow/message.rb, line 65
def self.open_flow_header(opts)
  module_eval do
    cattr_reader(:type) { opts.fetch(:type) }

    endian :big

    uint8 :version, value: opts.fetch(:version)
    uint8 :type, value: opts.fetch(:type)
    uint16(:_length,
           initial_value: opts[:length] || lambda do
             begin
               8 + body.length
             rescue
               8
             end
           end)
    transaction_id :transaction_id, initial_value: 0

    virtual assert: -> { version == opts.fetch(:version) }
    virtual assert: -> { type == opts.fetch(:type) }

    alias_method :xid, :transaction_id
  end
end
read(raw_data) click to toggle source
# File lib/pio/open_flow/message.rb, line 20
def self.read(raw_data)
  allocate.tap do |message|
    message.instance_variable_set(:@format,
                                  const_get(:Format).read(raw_data))
  end
rescue BinData::ValidityError
  message_name = name.split('::')[1..-1].join(' ')
  raise Pio::ParseError, "Invalid #{message_name} message."
end

Public Instance Methods

method_missing(method, *args, &block) click to toggle source
# File lib/pio/open_flow/message.rb, line 101
def method_missing(method, *args, &block)
  @format.__send__ method, *args, &block
end
to_binary() click to toggle source
# File lib/pio/open_flow/message.rb, line 97
def to_binary
  @format.to_binary_s
end

Private Instance Methods

parse_options(user_options) click to toggle source
# File lib/pio/open_flow/message.rb, line 114
def parse_options(user_options)
  parsed_options = user_options.dup
  parsed_options[:transaction_id] = user_options[:transaction_id] || 0
  parsed_options[:body] = user_options[:body] || ''
  parsed_options
end
validate_user_options(user_options) click to toggle source
# File lib/pio/open_flow/message.rb, line 107
def validate_user_options(user_options)
  unknown_options =
    user_options.keys - self.class.class_variable_get(:@@valid_options)
  return if unknown_options.empty?
  raise "Unknown option: #{unknown_options.first}"
end