Class: Adhearsion::VoIP::Asterisk::AMI::Actions::Action

Inherits:
Object
  • Object
show all
Defined in:
lib/adhearsion/voip/asterisk/ami/actions.rb

Constant Summary collapse

@@subclasses =
[]
@@actions =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, hash, &block) ⇒ Action

Returns a new instance of Action.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 38

def initialize(name, hash, &block)
  @action = name.downcase
  @action_id = __action_id
  @arguments = {}
  @packets = []
  @sync_complete = false
  @error = nil

  # Normalize the keys
  hash.each_pair { |k,v| @arguments[k.to_s.downcase] = v }

  if block and not async?
    raise RuntimeError, "Cannot specify completion callback for synchronous command"
  end
  @async_completion_callback = block
end

Instance Attribute Details

#actionObject

Returns the value of attribute action.



10
11
12
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 10

def action
  @action
end

#action_idObject

Returns the value of attribute action_id.



11
12
13
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 11

def action_id
  @action_id
end

Class Method Details

.[](key) ⇒ Object



29
30
31
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 29

def [](key)
  @@actions[key]
end

.[]=(key, action) ⇒ Object



33
34
35
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 33

def []=(key, action)
  @@actions[key] = action
end

.build(name, hash, &block) ⇒ Object

Return a new instance of the command. Make sure to return an instance of the command-specific subclass if it exists.



16
17
18
19
20
21
22
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 16

def build(name, hash, &block)
  name = name.to_s
  entry = @@subclasses.find { |klass| klass.downcase == name.downcase }
  klass = entry ? Actions.const_get("#{entry}Action") : self
  obj = klass.new(name, hash, &block)
  self[obj.action_id] = obj
end

.inherited(klass) ⇒ Object

Keep a list of the subclasses.



25
26
27
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 25

def inherited(klass)
  @@subclasses << klass.to_s.split("::").last.match(/(.*?)Action/)[1]
end

Instance Method Details

#<<(packet) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 55

def <<(packet)
  if packet.error?
    @error = packet.message
    complete_sync!
  end
  
  # We don't keep every packet, just the important ones.
  @packets << packet if keep?(packet)

  # Check if the synchronous portion of the action is done.
  if completed_by?(packet)
    # The synchronous portion is done.
    complete_sync!
    
    # We're totally done if it is not asynchronous.
    complete! if not async?
  end

  # Check if this is an asynchronous action, and we have received the last event
  complete_async! if completed_by_async?(packet)
end

#async?Boolean

Return true if this action returns matching events that we will not wait on, but can access at a later time.

Returns:

  • (Boolean)


111
112
113
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 111

def async?
  false
end

#check_error!Object

Raises:



93
94
95
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 93

def check_error!
  raise ActionError, @error if @error
end

#complete!Object



152
153
154
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 152

def complete!
							Action[@action_id] = nil
end

#complete_async!Object



147
148
149
150
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 147

def complete_async!
  @async_completion_callback.call(self.packets!) if @async_completion_callback
  complete!
end

#complete_sync!Object



143
144
145
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 143

def complete_sync!
  @sync_complete = true
end

#completed_by?(packet) ⇒ Boolean

Return true if this packet completes the command, i.e., there is no more synchronous response data to receive for this command.

Returns:

  • (Boolean)


128
129
130
131
132
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 128

def completed_by?(packet)
  return true if not waits_for_events?
  return false if not packet.is_event?
  packet.event.downcase == "#{@action}complete"
end

#completed_by_async?(packet) ⇒ Boolean

Return true if this packet completes the matching asynchronous events for this command.

Returns:

  • (Boolean)


136
137
138
139
140
141
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 136

def completed_by_async?(packet)
  return false if not async?
  return false if not packet.is_event?
  statuses = %w(success failure).collect { |status| "#{@action}#{status}" }
  statuses.include?(packet.event.downcase)
end

#done?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 77

def done?
  @sync_complete
end

#follows?Boolean

Actions of the form “Response: <Action> results will follow”

Returns:

  • (Boolean)


116
117
118
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 116

def follows?
  %w(parkedcalls queuestatus agents status sippeers zapshowchannels).include? @action
end

#has_response?Boolean

Virtually all commands return a response. There is at least one exception, handled with a command-specific subclass.

Returns:

  • (Boolean)


122
123
124
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 122

def has_response?
  true
end

#immediate?Boolean

Return true if this is an ‘immediate’ command, i.e., it returns raw results synchronously without a response header. Don’t bother doing this in subclasses. It is easy enough.

Returns:

  • (Boolean)


100
101
102
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 100

def immediate?
  %w(iaxpeers queues).include? @action
end

#keep?(packet) ⇒ Boolean

Return true if the packet should be included in the response. Raw and synchronous responses are kept. Some event responses are rejected.

Returns:

  • (Boolean)


158
159
160
161
162
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 158

def keep?(packet)
  return true if not waits_for_events?
  return false if not packet.is_event?
  return keep_event?(packet)
end

#keep_event?(packet) ⇒ Boolean

By default, we keep any event packet, unless it is the completion packet for a ‘follows’ command. These are just marker packets that signify the end of the event stream for the response. TODO: They do contain a count of the events generated, which perhaps we want to verify matches the number we think we have received?

Returns:

  • (Boolean)


169
170
171
172
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 169

def keep_event?(packet)
  return false if (follows? and completed_by?(packet))
  true
end

#packets!Object



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 81

def packets!
  packets, @packets = @packets, []
  packets.inject([]) do |arr, pkt|
    pkt = pkt.body.inject({}) do |hash, (k, v)|
      hash[k] = v
      hash
    end
    arr << pkt if not pkt.blank?
    arr
  end
end

#to_sObject



174
175
176
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 174

def to_s
  __args_to_str
end

#waits_for_events?Boolean

Return true if this action will return matching events that we will wait on.

Returns:

  • (Boolean)


105
106
107
# File 'lib/adhearsion/voip/asterisk/ami/actions.rb', line 105

def waits_for_events?
  follows? or %w(dbget).include? @action
end