eric-adhearsion 0.7.999

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +456 -0
  3. data/Manifest.txt +149 -0
  4. data/README.txt +6 -0
  5. data/Rakefile +48 -0
  6. data/ahn_generators/component/USAGE +5 -0
  7. data/ahn_generators/component/component_generator.rb +57 -0
  8. data/ahn_generators/component/templates/configuration.rb +0 -0
  9. data/ahn_generators/component/templates/lib/lib.rb.erb +3 -0
  10. data/ahn_generators/component/templates/test/test.rb.erb +12 -0
  11. data/ahn_generators/component/templates/test/test_helper.rb +14 -0
  12. data/app_generators/ahn/USAGE +5 -0
  13. data/app_generators/ahn/ahn_generator.rb +76 -0
  14. data/app_generators/ahn/templates/.ahnrc +12 -0
  15. data/app_generators/ahn/templates/README +8 -0
  16. data/app_generators/ahn/templates/Rakefile +3 -0
  17. data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
  18. data/app_generators/ahn/templates/components/simon_game/lib/simon_game.rb +61 -0
  19. data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +14 -0
  20. data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +31 -0
  21. data/app_generators/ahn/templates/config/startup.rb +53 -0
  22. data/app_generators/ahn/templates/dialplan.rb +4 -0
  23. data/bin/ahn +28 -0
  24. data/bin/ahnctl +68 -0
  25. data/bin/jahn +32 -0
  26. data/lib/adhearsion/blank_slate.rb +5 -0
  27. data/lib/adhearsion/cli.rb +106 -0
  28. data/lib/adhearsion/component_manager.rb +277 -0
  29. data/lib/adhearsion/core_extensions/all.rb +9 -0
  30. data/lib/adhearsion/core_extensions/array.rb +0 -0
  31. data/lib/adhearsion/core_extensions/custom_daemonizer.rb +45 -0
  32. data/lib/adhearsion/core_extensions/global.rb +1 -0
  33. data/lib/adhearsion/core_extensions/guid.rb +5 -0
  34. data/lib/adhearsion/core_extensions/hash.rb +0 -0
  35. data/lib/adhearsion/core_extensions/metaprogramming.rb +17 -0
  36. data/lib/adhearsion/core_extensions/numeric.rb +4 -0
  37. data/lib/adhearsion/core_extensions/proc.rb +0 -0
  38. data/lib/adhearsion/core_extensions/pseudo_uuid.rb +11 -0
  39. data/lib/adhearsion/core_extensions/publishable.rb +73 -0
  40. data/lib/adhearsion/core_extensions/relationship_properties.rb +40 -0
  41. data/lib/adhearsion/core_extensions/string.rb +26 -0
  42. data/lib/adhearsion/core_extensions/thread.rb +13 -0
  43. data/lib/adhearsion/core_extensions/thread_safety.rb +7 -0
  44. data/lib/adhearsion/core_extensions/time.rb +0 -0
  45. data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
  46. data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
  47. data/lib/adhearsion/distributed/gateways/rest_gateway.rb +9 -0
  48. data/lib/adhearsion/distributed/gateways/soap_gateway.rb +9 -0
  49. data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +9 -0
  50. data/lib/adhearsion/distributed/peer_finder.rb +0 -0
  51. data/lib/adhearsion/distributed/remote_cli.rb +0 -0
  52. data/lib/adhearsion/hooks.rb +57 -0
  53. data/lib/adhearsion/host_definitions.rb +63 -0
  54. data/lib/adhearsion/initializer/asterisk.rb +59 -0
  55. data/lib/adhearsion/initializer/configuration.rb +202 -0
  56. data/lib/adhearsion/initializer/database.rb +92 -0
  57. data/lib/adhearsion/initializer/drb.rb +25 -0
  58. data/lib/adhearsion/initializer/freeswitch.rb +22 -0
  59. data/lib/adhearsion/initializer/paths.rb +55 -0
  60. data/lib/adhearsion/initializer/rails.rb +40 -0
  61. data/lib/adhearsion/initializer.rb +217 -0
  62. data/lib/adhearsion/logging.rb +92 -0
  63. data/lib/adhearsion/services/scheduler.rb +5 -0
  64. data/lib/adhearsion/tasks/database.rb +5 -0
  65. data/lib/adhearsion/tasks/generating.rb +20 -0
  66. data/lib/adhearsion/tasks/lint.rb +4 -0
  67. data/lib/adhearsion/tasks/testing.rb +37 -0
  68. data/lib/adhearsion/tasks.rb +15 -0
  69. data/lib/adhearsion/version.rb +9 -0
  70. data/lib/adhearsion/voip/asterisk/agi_server.rb +78 -0
  71. data/lib/adhearsion/voip/asterisk/ami/actions.rb +238 -0
  72. data/lib/adhearsion/voip/asterisk/ami/machine.rb +871 -0
  73. data/lib/adhearsion/voip/asterisk/ami/machine.rl +109 -0
  74. data/lib/adhearsion/voip/asterisk/ami/parser.rb +262 -0
  75. data/lib/adhearsion/voip/asterisk/ami.rb +147 -0
  76. data/lib/adhearsion/voip/asterisk/commands.rb +1182 -0
  77. data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
  78. data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
  79. data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
  80. data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
  81. data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
  82. data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
  83. data/lib/adhearsion/voip/asterisk.rb +4 -0
  84. data/lib/adhearsion/voip/call.rb +391 -0
  85. data/lib/adhearsion/voip/call_routing.rb +64 -0
  86. data/lib/adhearsion/voip/commands.rb +9 -0
  87. data/lib/adhearsion/voip/constants.rb +39 -0
  88. data/lib/adhearsion/voip/conveniences.rb +18 -0
  89. data/lib/adhearsion/voip/dial_plan.rb +205 -0
  90. data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
  91. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
  92. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
  93. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
  94. data/lib/adhearsion/voip/dsl/dialplan/parser.rb +75 -0
  95. data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
  96. data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
  97. data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
  98. data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
  99. data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
  100. data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
  101. data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
  102. data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
  103. data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
  104. data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
  105. data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
  106. data/lib/adhearsion.rb +31 -0
  107. data/script/destroy +14 -0
  108. data/script/generate +14 -0
  109. data/spec/fixtures/dialplan.rb +3 -0
  110. data/spec/initializer/test_configuration.rb +267 -0
  111. data/spec/initializer/test_loading.rb +162 -0
  112. data/spec/initializer/test_paths.rb +43 -0
  113. data/spec/silence.rb +10 -0
  114. data/spec/test_ahn_command.rb +149 -0
  115. data/spec/test_code_quality.rb +87 -0
  116. data/spec/test_component_manager.rb +97 -0
  117. data/spec/test_constants.rb +8 -0
  118. data/spec/test_drb.rb +104 -0
  119. data/spec/test_helper.rb +94 -0
  120. data/spec/test_hooks.rb +37 -0
  121. data/spec/test_host_definitions.rb +79 -0
  122. data/spec/test_initialization.rb +105 -0
  123. data/spec/test_logging.rb +80 -0
  124. data/spec/test_relationship_properties.rb +54 -0
  125. data/spec/voip/asterisk/ami_response_definitions.rb +23 -0
  126. data/spec/voip/asterisk/config_file_generators/test_agents.rb +253 -0
  127. data/spec/voip/asterisk/config_file_generators/test_queues.rb +325 -0
  128. data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +306 -0
  129. data/spec/voip/asterisk/menu_command/test_calculated_match.rb +111 -0
  130. data/spec/voip/asterisk/menu_command/test_matchers.rb +98 -0
  131. data/spec/voip/asterisk/mock_ami_server.rb +176 -0
  132. data/spec/voip/asterisk/test_agi_server.rb +451 -0
  133. data/spec/voip/asterisk/test_ami.rb +227 -0
  134. data/spec/voip/asterisk/test_commands.rb +2006 -0
  135. data/spec/voip/asterisk/test_config_manager.rb +129 -0
  136. data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
  137. data/spec/voip/dsl/test_dialing_dsl.rb +268 -0
  138. data/spec/voip/dsl/test_dispatcher.rb +82 -0
  139. data/spec/voip/dsl/test_parser.rb +87 -0
  140. data/spec/voip/freeswitch/test_basic_connection_manager.rb +39 -0
  141. data/spec/voip/freeswitch/test_inbound_connection_manager.rb +39 -0
  142. data/spec/voip/freeswitch/test_oes_server.rb +9 -0
  143. data/spec/voip/test_call_routing.rb +127 -0
  144. data/spec/voip/test_dialplan_manager.rb +372 -0
  145. data/spec/voip/test_numerical_string.rb +48 -0
  146. data/spec/voip/test_phone_number.rb +36 -0
  147. data/test/test_ahn_generator.rb +59 -0
  148. data/test/test_component_generator.rb +52 -0
  149. data/test/test_generator_helper.rb +20 -0
  150. metadata +254 -0
@@ -0,0 +1,238 @@
1
+ module Adhearsion
2
+ module VoIP
3
+ module Asterisk
4
+ class AMI
5
+ module Actions
6
+ class Action
7
+ @@subclasses = []
8
+ @@actions = {}
9
+
10
+ attr_accessor :action
11
+ attr_accessor :action_id
12
+
13
+ class << self
14
+ # Return a new instance of the command. Make sure to return an instance
15
+ # of the command-specific subclass if it exists.
16
+ def build(name, hash, &block)
17
+ name = name.to_s
18
+ entry = @@subclasses.find { |klass| klass.downcase == name.downcase }
19
+ klass = entry ? Actions.const_get("#{entry}Action") : self
20
+ obj = klass.new(name, hash, &block)
21
+ self[obj.action_id] = obj
22
+ end
23
+
24
+ # Keep a list of the subclasses.
25
+ def inherited(klass)
26
+ @@subclasses << klass.to_s.split("::").last.match(/(.*?)Action/)[1]
27
+ end
28
+
29
+ def [](key)
30
+ @@actions[key]
31
+ end
32
+
33
+ def []=(key, action)
34
+ @@actions[key] = action
35
+ end
36
+ end
37
+
38
+ def initialize(name, hash, &block)
39
+ @action = name.downcase
40
+ @action_id = __action_id
41
+ @arguments = {}
42
+ @packets = []
43
+ @sync_complete = false
44
+ @error = nil
45
+
46
+ # Normalize the keys
47
+ hash.each_pair { |k,v| @arguments[k.to_s.downcase] = v }
48
+
49
+ if block and not async?
50
+ raise RuntimeError, "Cannot specify completion callback for synchronous command"
51
+ end
52
+ @async_completion_callback = block
53
+ end
54
+
55
+ def <<(packet)
56
+ if packet.error?
57
+ @error = packet.message
58
+ complete_sync!
59
+ end
60
+
61
+ # We don't keep every packet, just the important ones.
62
+ @packets << packet if keep?(packet)
63
+
64
+ # Check if the synchronous portion of the action is done.
65
+ if completed_by?(packet)
66
+ # The synchronous portion is done.
67
+ complete_sync!
68
+
69
+ # We're totally done if it is not asynchronous.
70
+ complete! if not async?
71
+ end
72
+
73
+ # Check if this is an asynchronous action, and we have received the last event
74
+ complete_async! if completed_by_async?(packet)
75
+ end
76
+
77
+ def done?
78
+ @sync_complete
79
+ end
80
+
81
+ def packets!
82
+ packets, @packets = @packets, []
83
+ packets.inject([]) do |arr, pkt|
84
+ pkt = pkt.body.inject({}) do |hash, (k, v)|
85
+ hash[k] = v
86
+ hash
87
+ end
88
+ arr << pkt if not pkt.blank?
89
+ arr
90
+ end
91
+ end
92
+
93
+ def check_error!
94
+ raise ActionError, @error if @error
95
+ end
96
+
97
+ # Return true if this is an 'immediate' command, i.e., it returns raw
98
+ # results synchronously without a response header.
99
+ # Don't bother doing this in subclasses. It is easy enough.
100
+ def immediate?
101
+ %w(iaxpeers queues).include? @action
102
+ end
103
+
104
+ # Return true if this action will return matching events that we will wait on.
105
+ def waits_for_events?
106
+ follows? or %w(dbget).include? @action
107
+ end
108
+
109
+ # Return true if this action returns matching events that we will not wait on,
110
+ # but can access at a later time.
111
+ def async?
112
+ false
113
+ end
114
+
115
+ # Actions of the form "Response: <Action> results will follow"
116
+ def follows?
117
+ %w(parkedcalls queuestatus agents status sippeers zapshowchannels).include? @action
118
+ end
119
+
120
+ # Virtually all commands return a response. There is at least one
121
+ # exception, handled with a command-specific subclass.
122
+ def has_response?
123
+ true
124
+ end
125
+
126
+ # Return true if this packet completes the command, i.e., there is
127
+ # no more synchronous response data to receive for this command.
128
+ def completed_by?(packet)
129
+ return true if not waits_for_events?
130
+ return false if not packet.is_event?
131
+ packet.event.downcase == "#{@action}complete"
132
+ end
133
+
134
+ # Return true if this packet completes the matching asynchronous
135
+ # events for this command.
136
+ def completed_by_async?(packet)
137
+ return false if not async?
138
+ return false if not packet.is_event?
139
+ statuses = %w(success failure).collect { |status| "#{@action}#{status}" }
140
+ statuses.include?(packet.event.downcase)
141
+ end
142
+
143
+ def complete_sync!
144
+ @sync_complete = true
145
+ end
146
+
147
+ def complete_async!
148
+ @async_completion_callback.call(self.packets!) if @async_completion_callback
149
+ complete!
150
+ end
151
+
152
+ def complete!
153
+ Action[@action_id] = nil
154
+ end
155
+
156
+ # Return true if the packet should be included in the response. Raw and
157
+ # synchronous responses are kept. Some event responses are rejected.
158
+ def keep?(packet)
159
+ return true if not waits_for_events?
160
+ return false if not packet.is_event?
161
+ return keep_event?(packet)
162
+ end
163
+
164
+ # By default, we keep any event packet, unless it is the completion
165
+ # packet for a 'follows' command. These are just marker packets that
166
+ # signify the end of the event stream for the response.
167
+ # TODO: They do contain a count of the events generated, which perhaps
168
+ # we want to verify matches the number we think we have received?
169
+ def keep_event?(packet)
170
+ return false if (follows? and completed_by?(packet))
171
+ true
172
+ end
173
+
174
+ def to_s
175
+ __args_to_str
176
+ end
177
+
178
+ private
179
+
180
+ # Immediate commands do not return response headers, so there is no
181
+ # chance (or need) to get an action id. We'll make those packets
182
+ # action ids to be 0 artificially.
183
+ def __action_id
184
+ immediate? ? 0 : Time.now.to_f.to_s
185
+ end
186
+
187
+ def __args_to_str
188
+ action = ""
189
+ action << "action: #{@action}\r\n"
190
+ action << "actionid: #{@action_id}\r\n"
191
+ @arguments.keys.sort { |a,b| a.to_s <=> b.to_s }.each { |k| action << "#{k}: #{@arguments[k]}\r\n" }
192
+ action << "\r\n"
193
+ end
194
+ end
195
+
196
+ class OriginateAction < Action
197
+ # Return true if this action will return events, i.e. it is asynchronous.
198
+ # This is controlled by the 'Async' argument to the command.
199
+ def async?
200
+ @arguments['async'] == true
201
+ end
202
+ end
203
+
204
+ class DBGetAction < Action
205
+ # Needed only because this asynchronous response (when the
206
+ # command succeeds) does not return a response with the
207
+ # name "DBGetComplete".
208
+ def completed_by?(packet)
209
+ return true if not waits_for_events?
210
+ return false if not packet.is_event?
211
+ packet.event == "DBGetResponse"
212
+ end
213
+ end
214
+
215
+ class SIPpeersAction < Action
216
+ # Sigh. The only reason for this is that the naming
217
+ # convention differs.
218
+ def completed_by?(packet)
219
+ return true if not waits_for_events?
220
+ return false if not packet.is_event?
221
+ packet.event == "PeerlistComplete"
222
+ end
223
+ end
224
+
225
+ class EventsAction < Action
226
+ # Again, this is a command that is subclassed due to interface
227
+ # inconsistency. If the command turns on events with the mask
228
+ # of "On", there is no response. If it is "Off" or set on for
229
+ # specific events, there is a reponse. Ugly.
230
+ def has_response?
231
+ @arguments['eventmask'] !~ /^on$/i
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end