Class: Pio::OpenFlow::Message

Inherits:
Object
  • Object
show all
Extended by:
ActiveSupport::DescendantsTracker, Flags
Defined in:
lib/pio/open_flow/message.rb

Overview

OpenFlow messages.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Flags

_define_flags, _flags, define_flags_32bit, flags_16bit, flags_32bit

Constructor Details

#initialize(user_options = {}) ⇒ Message

rubocop:enable AbcSize rubocop:enable MethodLength



92
93
94
95
# 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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object



101
102
103
# File 'lib/pio/open_flow/message.rb', line 101

def method_missing(method, *args, &block)
  @format.__send__ method, *args, &block
end

Instance Attribute Details

#formatObject (readonly)

Returns the value of attribute format.



15
16
17
# File 'lib/pio/open_flow/message.rb', line 15

def format
  @format
end

Class Method Details

.method_missing(method, *args, &block) ⇒ Object

rubocop:disable MethodLength rubocop:disable AbcSize



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 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

.open_flow_header(opts) ⇒ Object

rubocop:disable AbcSize rubocop:disable MethodLength



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# 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) ⇒ Object



20
21
22
23
24
25
26
27
28
# 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

Instance Method Details

#to_binaryObject



97
98
99
# File 'lib/pio/open_flow/message.rb', line 97

def to_binary
  @format.to_binary_s
end