sevenscale-adhearsion 0.7.1000

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +1186 -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 +402 -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 +453 -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