adhearsion 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG +12 -0
  4. data/README.markdown +1 -10
  5. data/Rakefile +6 -28
  6. data/adhearsion.gemspec +21 -38
  7. data/app_generators/ahn/ahn_generator.rb +3 -4
  8. data/app_generators/ahn/templates/config/environment.rb +4 -0
  9. data/app_generators/ahn/templates/config/startup.rb +11 -5
  10. data/app_generators/ahn/templates/script/ahn +8 -0
  11. data/lib/adhearsion/cli.rb +5 -298
  12. data/lib/adhearsion/commands.rb +308 -0
  13. data/lib/adhearsion/events_support.rb +0 -20
  14. data/lib/adhearsion/initializer/asterisk.rb +0 -1
  15. data/lib/adhearsion/initializer/configuration.rb +4 -1
  16. data/lib/adhearsion/logging.rb +18 -3
  17. data/lib/adhearsion/script_ahn_loader.rb +30 -0
  18. data/lib/adhearsion/tasks/testing.rb +39 -8
  19. data/lib/adhearsion/version.rb +2 -2
  20. data/lib/adhearsion/voip/asterisk/agi_server.rb +15 -8
  21. data/lib/adhearsion/voip/asterisk/commands.rb +340 -86
  22. data/lib/adhearsion/voip/asterisk/manager_interface.rb +0 -2
  23. data/lib/adhearsion/voip/call.rb +11 -3
  24. data/lib/adhearsion/voip/commands.rb +5 -1
  25. data/lib/adhearsion/voip/dial_plan.rb +4 -0
  26. data/lib/theatre/invocation.rb +3 -0
  27. data/spec/{ahn_command_spec.rb → adhearsion/cli_spec.rb} +11 -0
  28. data/spec/{component_manager_spec.rb → adhearsion/component_manager_spec.rb} +0 -0
  29. data/spec/{constants_spec.rb → adhearsion/constants_spec.rb} +0 -0
  30. data/spec/{drb_spec.rb → adhearsion/drb_spec.rb} +0 -0
  31. data/spec/{fixtures → adhearsion/fixtures}/dialplan.rb +0 -0
  32. data/spec/{foundation → adhearsion/foundation}/event_socket_spec.rb +0 -0
  33. data/spec/{host_definitions_spec.rb → adhearsion/host_definitions_spec.rb} +0 -0
  34. data/spec/{initializer → adhearsion/initializer}/configuration_spec.rb +21 -0
  35. data/spec/{initializer → adhearsion/initializer}/loading_spec.rb +0 -0
  36. data/spec/{initializer → adhearsion/initializer}/paths_spec.rb +0 -0
  37. data/spec/{initialization_spec.rb → adhearsion/initializer_spec.rb} +0 -0
  38. data/spec/{logging_spec.rb → adhearsion/logging_spec.rb} +6 -0
  39. data/spec/{relationship_properties_spec.rb → adhearsion/relationship_properties_spec.rb} +0 -0
  40. data/spec/{voip → adhearsion/voip}/asterisk/agi_server_spec.rb +0 -0
  41. data/spec/{voip → adhearsion/voip}/asterisk/ami/ami_spec.rb +1 -0
  42. data/spec/{voip → adhearsion/voip}/asterisk/ami/lexer/ami_fixtures.yml +0 -0
  43. data/spec/{voip → adhearsion/voip}/asterisk/ami/lexer/lexer_story +0 -0
  44. data/spec/{voip → adhearsion/voip}/asterisk/ami/lexer/lexer_story.rb +0 -0
  45. data/spec/{voip → adhearsion/voip}/asterisk/ami/lexer/story_helper.rb +0 -0
  46. data/spec/{voip → adhearsion/voip}/asterisk/commands_spec.rb +549 -47
  47. data/spec/{voip → adhearsion/voip}/asterisk/config_file_generators/agents_spec.rb +0 -0
  48. data/spec/{voip → adhearsion/voip}/asterisk/config_file_generators/queues_spec.rb +0 -0
  49. data/spec/{voip → adhearsion/voip}/asterisk/config_file_generators/voicemail_spec.rb +0 -0
  50. data/spec/{voip → adhearsion/voip}/asterisk/config_manager_spec.rb +0 -0
  51. data/spec/{voip → adhearsion/voip}/asterisk/menu_command/calculated_match_spec.rb +0 -0
  52. data/spec/{voip → adhearsion/voip}/asterisk/menu_command/matchers_spec.rb +0 -0
  53. data/spec/{voip → adhearsion/voip}/call_routing_spec.rb +0 -0
  54. data/spec/{voip → adhearsion/voip}/dialplan_manager_spec.rb +0 -0
  55. data/spec/{voip → adhearsion/voip}/dsl/dialing_dsl_spec.rb +1 -1
  56. data/spec/{voip → adhearsion/voip}/dsl/dispatcher_spec.rb +0 -0
  57. data/spec/{voip → adhearsion/voip}/dsl/dispatcher_spec_helper.rb +0 -0
  58. data/spec/{voip → adhearsion/voip}/dsl/parser_spec.rb +0 -0
  59. data/spec/{voip → adhearsion/voip}/freeswitch/basic_connection_manager_spec.rb +0 -0
  60. data/spec/{voip → adhearsion/voip}/freeswitch/inbound_connection_manager_spec.rb +0 -0
  61. data/spec/{voip → adhearsion/voip}/freeswitch/oes_server_spec.rb +0 -0
  62. data/spec/{voip → adhearsion/voip}/numerical_string_spec.rb +0 -0
  63. data/spec/{voip → adhearsion/voip}/phone_number_spec.rb +0 -0
  64. data/spec/spec_helper.rb +36 -89
  65. data/spec/support/initializer_stubs.rb +47 -0
  66. data/spec/support/the_following_code.rb +3 -0
  67. data/{theatre-spec → spec/theatre}/dsl_examples/simple_before_call.rb +0 -0
  68. data/{theatre-spec → spec/theatre}/dsl_spec.rb +26 -0
  69. data/{theatre-spec → spec/theatre}/invocation_spec.rb +6 -10
  70. data/{theatre-spec → spec/theatre}/namespace_spec.rb +0 -0
  71. data/{theatre-spec → spec/theatre}/spec_helper_spec.rb +0 -0
  72. data/{theatre-spec → spec/theatre}/theatre_class_spec.rb +2 -5
  73. metadata +254 -271
  74. data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.rb +0 -104
  75. data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.yml +0 -2
  76. data/lib/adhearsion/voip/asterisk/super_manager.rb +0 -19
  77. data/spec/silence.rb +0 -10
  78. data/spec/voip/asterisk/ami/old_tests.rb +0 -204
  79. data/spec/voip/asterisk/ami/super_manager/super_manager_story +0 -25
  80. data/spec/voip/asterisk/ami/super_manager/super_manager_story.rb +0 -15
  81. data/spec/voip/asterisk/ami/super_manager/super_manager_story_helper.rb +0 -5
  82. data/theatre-spec/dsl_examples/dynamic_stomp.rb +0 -7
  83. data/theatre-spec/spec_helper.rb +0 -37
@@ -1,104 +0,0 @@
1
- require 'md5'
2
- require 'open-uri'
3
-
4
- SANDBOX_VERSION = 1.0
5
-
6
- initialization do
7
- # We shouldn't start initializing until after the AGI server has initialized.
8
- Events.register_callback(:after_initialized) do
9
-
10
- config = if COMPONENTS.sandbox.has_key? "connect_to"
11
- {"connect_to" => COMPONENTS.sandbox["connect_to"]}
12
- else
13
- begin
14
- yaml_data = open("http://sandbox.adhearsion.com/component/#{SANDBOX_VERSION}").read
15
- YAML.load yaml_data
16
- rescue SocketError
17
- ahn_log.sandbox.error "Could not connect to the sandbox server! Skipping sandbox initialization!"
18
- next
19
- rescue => e
20
- ahn_log.sandbox.error "COULD NOT RETRIEVE SANDBOX CONNECTION INFORMATION! Not initializing sandbox component!"
21
- next
22
- end
23
- end
24
-
25
- begin
26
- # The "connect_to" key is what this version supports
27
- if config.kind_of?(Hash) && config.has_key?("connect_to")
28
- config = config['connect_to']
29
-
30
- host, port = config.values_at "host", "port"
31
-
32
- username, password = COMPONENTS.sandbox["username"].to_s, COMPONENTS.sandbox["password"].to_s
33
-
34
- if username.blank? || password.blank? || username == "user123"
35
- ahn_log.sandbox.error "You must specify your username and password in this component's config file!"
36
- next
37
- end
38
-
39
- # Part of the AGI-superset protocol we use to log in.
40
- identifying_hash = MD5.md5(username + ":" + password).to_s
41
-
42
- if host.nil? || port.nil?
43
- ahn_log.sandbox.error "Invalid YAML returned from server! Skipping sandbox initialization!"
44
- next
45
- end
46
-
47
- Thread.new do
48
- loop do
49
- begin
50
- ahn_log.sandbox.debug "Establishing outbound AGI socket"
51
- socket = TCPSocket.new(host, port)
52
- socket.puts identifying_hash
53
- response = socket.gets
54
- unless response
55
- next
56
- end
57
- response.chomp!
58
- case response
59
- when "authentication accepted"
60
- ahn_log.sandbox "Authentication accepted"
61
-
62
- start_signal = socket.gets
63
- next unless start_signal
64
- start_signal.chomp!
65
-
66
- if start_signal
67
- ahn_log.sandbox "Incoming call from remote sandbox server!"
68
- begin
69
- Adhearsion::Initializer::AsteriskInitializer.agi_server.server.serve(socket)
70
- rescue => e
71
- ahn_log.error "Non-fatal exception in the AGI server: #{e.inspect} \n" + e.backtrace.join("\n")
72
- ensure
73
- socket.close rescue nil
74
- end
75
- ahn_log.sandbox "AGI server finished serving call. Reconnecting to sandbox."
76
- else
77
- ahn_log.sandbox "Remote Asterisk server received no call. Reconnecting..."
78
- end
79
- when "authentication failed"
80
- ahn_log.sandbox.error "Your username or password is invalid! Skipping sandbox initialization..."
81
- break
82
- when /^wait (\d+)$/
83
- sleep response[/^wait (\d+)$/,1].to_i
84
- else
85
- ahn_log.sandbox.error "Invalid login acknowledgement! Skipping sandbox initialization!"
86
- break
87
- end
88
- rescue Errno::ECONNREFUSED
89
- ahn_log.sandbox.error "Could not connect to the sandbox server! Sandbox component stopping..."
90
- break
91
- rescue => e
92
- ahn_log.error "Unrecognized error: #{e.inspect} \n" + e.backtrace.join("\n")
93
- end
94
- end
95
- end
96
-
97
- else
98
- ahn_log.sandbox.error "COULD NOT RETRIEVE SANDBOX CONNECTION INFORMATION! Not initializing sandbox component!"
99
- end
100
- rescue => e
101
- ahn_log.sandbox.error "Encountered an error when connecting to the sandbox! #{e.message}\n" + e.backtrace.join("\n")
102
- end
103
- end
104
- end
@@ -1,2 +0,0 @@
1
- username: user123
2
- password: pass123
@@ -1,19 +0,0 @@
1
- module Adhearsion
2
- module VoIP
3
- module Asterisk
4
- module Manager
5
-
6
- ##
7
- # Higher level abstraction of the Asterisk Manager Interface.
8
- #
9
- class SuperManager
10
-
11
- def initialize
12
- raise NotImplementedError
13
- end
14
-
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,10 +0,0 @@
1
- #
2
- # Seeing the dump of pending specs every time you run them is distracting.
3
- # This file lets you skip pending specs.
4
- class Test::Unit::TestResult
5
- def add_disabled(name)
6
- #nothing!
7
- end
8
- end
9
-
10
- Adhearsion::Logging.silence!
@@ -1,204 +0,0 @@
1
- =begin
2
- describe "Connecting via AMI" do
3
- it "should raise an exception if the password was invalid" do
4
- host, port = "localhost", 5038
5
- ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "bad_password", "localhost", :port => port
6
-
7
- ami_server = AmiServer.new
8
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
9
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
10
-
11
- the_following_code do
12
- ami.connect!
13
- end.should raise_error Adhearsion::VoIP::Asterisk::AMI::AuthenticationFailedException
14
- ami.disconnect!
15
- end
16
-
17
- it "should discover its own permissions and make them available as connection attributes"
18
-
19
- it "should find the Asterisk version when connecting" do
20
- host, port = "localhost", 5038
21
- ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "password", "localhost", :port => port
22
-
23
- ami_server = AmiServer.new
24
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
25
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
26
-
27
- ami.connect!
28
- ami.version.should == "1.0"
29
- ami.disconnect!
30
- end
31
- end
32
-
33
- describe "The AMI command interface" do
34
-
35
- before do
36
- host, port = "localhost", 5038
37
- @ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "password", host, :port => port, :events => false
38
-
39
- ami_server = AmiServer.new
40
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
41
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
42
-
43
- @ami.connect!
44
- end
45
-
46
- after do
47
- @ami.disconnect!
48
- end
49
-
50
- it "should respond to an immediate command" do
51
- resp = @ami.queues
52
- resp[0][:raw].should be_a_kind_of String
53
- end
54
-
55
- it "should respond to a follows command" do
56
- resp = @ami.command :Command => "show channels"
57
- resp[0][:raw].should be_a_kind_of String
58
- end
59
-
60
- it "should respond to a DBGet for a non-existent key with an exception" do
61
- the_following_code do
62
- resp = @ami.dbget :Family => "none", :Key => "somekey"
63
- end.should raise_error Adhearsion::VoIP::Asterisk::AMI::ActionError
64
- end
65
-
66
- it "should respond to a DBGet for a key with an event" do
67
- resp = @ami.dbput :Family => "none", :Key => "somekey", :Val => 5
68
- resp = @ami.dbget :Family => "none", :Key => "somekey"
69
- resp[0]['Val'].should == "5"
70
- end
71
-
72
- it "should respond to a command that generates follows event(s)" do
73
- resp = @ami.queuestatus
74
- resp[0]['Queue'].should == "default"
75
- end
76
-
77
- it "should show usage for an improper follows command" do
78
- resp = @ami.command :Command => "meetme list"
79
- resp[0][:raw].should be_a_kind_of String
80
- end
81
-
82
- it "should respond to a synchronous originate"
83
- it "should respond to an asynchronous originate"
84
-
85
- it "should define events() as a private method to prevent turning events on or off" do
86
- @ami.private_methods.include?("events").should be true
87
- end
88
-
89
- it "should raise an exception when Asterisk doesn't recognize a command" do
90
- the_following_code {
91
- @ami.this_command_does_not_exist_kthx
92
- }.should raise_error Adhearsion::VoIP::Asterisk::AMI::ActionError
93
-
94
- end
95
-
96
- end
97
-
98
- describe 'AMI#originate' do
99
- include AmiCommandTestHelper
100
- it "should pass the arguments to execute_ami_command! with the options given" do
101
- ami = new_ami_instance
102
- options = { :channel => "ohai_lolz", :application => "Echo" }
103
- flexmock(ami).should_receive(:execute_ami_command!).with(:originate, options).once
104
- ami.originate options
105
- end
106
-
107
- it "should rename the :caller_id Hash key to :callerid" do
108
- ami, caller_id = new_ami_instance, "Jay"
109
- options = { :channel => "ohai_lolz", :application => "Echo"}
110
- flexmock(ami).should_receive(:execute_ami_command!).with(:originate, options.merge(:callerid => caller_id)).once
111
- ami.originate options.merge(:caller_id => caller_id)
112
- end
113
-
114
- end
115
-
116
- describe 'AMI#call_and_exec' do
117
- include AmiCommandTestHelper
118
- it "should execute originate properly with the minimum arguments" do
119
- number, app = "12224446666", "Echo"
120
-
121
- ami = flexmock new_ami_instance
122
- ami.should_receive(:originate).once.with(:channel => number, :application => app).and_return true
123
- ami.call_and_exec number, app
124
- end
125
-
126
- end
127
-
128
- describe 'AMI#introduce' do
129
-
130
- include AmiCommandTestHelper
131
-
132
- it "should execute origiante properly (when :caller_id and :options aren't specified)" do
133
- caller, callee, caller_id = "SIP/12224446666@trunk", "SIP/12224447777@trunk", "Jay Phillips"
134
-
135
- correct_args = {:application => "Dial", :channel => caller, :data => callee, :caller_id => "Jay"}
136
- ami = flexmock new_ami_instance
137
- ami.should_receive(:originate).once.with(correct_args).and_return(true)
138
- ami.introduce caller, callee, :caller_id => "Jay"
139
- end
140
-
141
- end
142
-
143
- describe "The manager proxy" do
144
- before do
145
- host, port = "localhost", 5038
146
- @ami = Adhearsion::VoIP::Asterisk::AMI.new "admin", "password", "localhost", :port => port, :events => false
147
-
148
- ami_server = AmiServer.new
149
- flexmock(TCPSocket).should_receive(:new).once.with(host, port).and_return(ami_server)
150
- flexmock(IO).should_receive(:select).at_least.once.with([ami_server], nil, nil, 1.0).and_return(true)
151
-
152
- @ami.connect!
153
- @door = DRb.start_service "druby://127.0.0.1:9050", Adhearsion::DrbDoor.instance
154
- end
155
-
156
- it "should accept a command" do
157
- client = DRbObject.new nil, DRb.uri
158
- client.proxy.ping
159
- end
160
-
161
- after do
162
- DRb.stop_service
163
- @ami.disconnect!
164
- end
165
- end
166
-
167
- describe "The command-sending interface" do
168
- it "should raise an exception if permission was denied"
169
- it "should allow variables to be specified as a Hash"
170
- end
171
-
172
- describe "Sent arbitrary AMI commands" do
173
-
174
- it "should allow a convenient way of parsing by event name"
175
- it "should return Hash arguments"
176
-
177
- it "should recognize its subclasses"
178
- it "should send events to all of its subclasses"
179
- it "should catch action names with method_missing() and format them properly"
180
-
181
- it "should raise an exception if permission was denied"
182
- end
183
-
184
- describe "AMI Packets" do
185
- it "A Packet should not be an error" do
186
- Adhearsion::VoIP::Asterisk::AMI::Packet.new.error?.should.be false
187
- end
188
- it "An ErrorPacket should be an error" do
189
- Adhearsion::VoIP::Asterisk::AMI::ErrorPacket.new.error?.should.be true
190
- end
191
- end
192
-
193
- BEGIN {
194
- module AmiCommandTestHelper
195
- def new_ami_instance
196
- # TODO. mock everything out here
197
- Adhearsion::VoIP::Asterisk::AMI.new("user","pass").tap do |ami|
198
- flexmock(ami).should_receive(:connect!).and_return(true)
199
- end
200
- end
201
-
202
- end
203
- }
204
- =end
@@ -1,25 +0,0 @@
1
- Story: Building and sending high-level AMI actions with SuperManager
2
-
3
- As an Adhearsion user
4
- I want higher-level, intuitive abstractions of the AMI protocol
5
- So that I can control Asterisk better
6
-
7
- TODO:
8
- - Migrate to cucumber
9
-
10
- Scenario: Sending a Ping
11
-
12
- Given a new SuperManager
13
- And a "Ping" action
14
-
15
- When the data it sent
16
- And the server responds with
17
-
18
- Then the data sent should be well-formed
19
- And the 1st action should have the action name "Ping"
20
- And the 1st action should have an ActionID
21
- And the 1st action should have exactly 2 headers
22
-
23
- Scenario: An action with many
24
-
25
- Scenario: A Channel object
@@ -1,15 +0,0 @@
1
- require 'rubygems'
2
- require 'cucumber'
3
-
4
- Given "etwas" do
5
-
6
- end
7
-
8
- When "etwas2" do
9
-
10
- end
11
-
12
- Then "etwas3" do
13
-
14
- end
15
-
@@ -1,5 +0,0 @@
1
- require 'rubygems'
2
- gem 'rspec', "= 1.1.4"
3
- require 'spec/story'
4
-
5
- require File.dirname(__FILE__) + "/super_manager_story"
@@ -1,7 +0,0 @@
1
- events.stomp.this_is_a_dynamic_name.each do
2
-
3
- end
4
-
5
- events.stomp.new_call.each do
6
-
7
- end
@@ -1,37 +0,0 @@
1
- require 'yaml'
2
- require 'yaml/types'
3
- require 'rubygems'
4
- require 'spec'
5
- require 'flexmock/rspec'
6
-
7
- require File.dirname(__FILE__) + "/../lib/theatre.rb"
8
-
9
- Spec::Runner.configure do |config|
10
- config.mock_with :flexmock
11
- end
12
-
13
- class Example
14
- attr_reader :name, :yaml, :metadata, :file
15
- def initialize(name)
16
- @name = name.to_sym
17
- @file = File.expand_path(File.dirname(__FILE__) + "/dsl_examples/#{name}.rb")
18
- @yaml = file_contents[/=begin YAML\n(.+?)\n=end/m, 1]
19
- @metadata = @yaml.nil? ? nil : YAML.load(@yaml)
20
- end
21
-
22
- def file_contents
23
- File.read @file
24
- end
25
-
26
- def register_namespaces_on(obj)
27
- obj = obj.namespace_manager if obj.kind_of? Theatre::Theatre
28
- namespaces = metadata["namespaces"]
29
- if namespaces && namespaces.kind_of?(Array) && namespaces.any?
30
- namespaces.each do |namespace|
31
- obj.register_namespace_name namespace
32
- end
33
- end
34
- obj
35
- end
36
-
37
- end