eric-adhearsion 0.7.999 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +8 -2
- data/EVENTS +11 -0
- data/Rakefile +96 -24
- data/adhearsion.gemspec +148 -0
- data/app_generators/ahn/ahn_generator.rb +24 -9
- data/app_generators/ahn/templates/.ahnrc +25 -3
- data/app_generators/ahn/templates/Rakefile +22 -2
- data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
- data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
- data/app_generators/ahn/templates/components/simon_game/{lib/simon_game.rb → simon_game.rb} +14 -19
- data/app_generators/ahn/templates/config/startup.rb +3 -6
- data/app_generators/ahn/templates/dialplan.rb +2 -3
- data/app_generators/ahn/templates/events.rb +32 -0
- data/bin/jahn +10 -0
- data/examples/asterisk_manager_interface/standalone.rb +51 -0
- data/lib/adhearsion.rb +17 -11
- data/lib/adhearsion/cli.rb +141 -24
- data/lib/adhearsion/component_manager.rb +169 -238
- data/lib/adhearsion/component_manager/component_tester.rb +55 -0
- data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
- data/lib/adhearsion/events_support.rb +84 -0
- data/lib/adhearsion/{core_extensions → foundation}/all.rb +0 -0
- data/lib/adhearsion/{blank_slate.rb → foundation/blank_slate.rb} +0 -0
- data/lib/adhearsion/{core_extensions → foundation}/custom_daemonizer.rb +0 -0
- data/lib/adhearsion/foundation/event_socket.rb +203 -0
- data/lib/adhearsion/foundation/future_resource.rb +36 -0
- data/lib/adhearsion/{core_extensions → foundation}/global.rb +0 -0
- data/lib/adhearsion/{core_extensions → foundation}/metaprogramming.rb +0 -0
- data/lib/adhearsion/foundation/numeric.rb +13 -0
- data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
- data/lib/adhearsion/{core_extensions → foundation}/relationship_properties.rb +2 -0
- data/lib/adhearsion/foundation/string.rb +26 -0
- data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
- data/lib/adhearsion/{core_extensions → foundation}/thread_safety.rb +0 -0
- data/lib/adhearsion/host_definitions.rb +5 -1
- data/lib/adhearsion/initializer.rb +229 -73
- data/lib/adhearsion/initializer/asterisk.rb +33 -11
- data/lib/adhearsion/initializer/configuration.rb +58 -6
- data/lib/adhearsion/initializer/database.rb +3 -46
- data/lib/adhearsion/initializer/drb.rb +9 -3
- data/lib/adhearsion/initializer/freeswitch.rb +3 -3
- data/lib/adhearsion/initializer/rails.rb +1 -1
- data/lib/adhearsion/tasks.rb +2 -1
- data/lib/adhearsion/tasks/deprecations.rb +59 -0
- data/lib/adhearsion/version.rb +3 -3
- data/lib/adhearsion/voip/asterisk.rb +2 -2
- data/lib/adhearsion/voip/asterisk/agi_server.rb +9 -6
- data/lib/adhearsion/voip/asterisk/commands.rb +106 -4
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
- data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
- data/lib/adhearsion/voip/call.rb +51 -2
- data/lib/adhearsion/voip/dial_plan.rb +74 -61
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +2 -6
- data/lib/adhearsion/voip/dsl/numerical_string.rb +2 -2
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +2 -2
- data/lib/theatre.rb +151 -0
- data/lib/theatre/README.markdown +64 -0
- data/lib/theatre/callback_definition_loader.rb +84 -0
- data/lib/theatre/guid.rb +23 -0
- data/lib/theatre/invocation.rb +121 -0
- data/lib/theatre/namespace_manager.rb +153 -0
- data/lib/theatre/version.rb +2 -0
- metadata +63 -138
- data/Manifest.txt +0 -149
- data/README.txt +0 -6
- data/ahn_generators/component/USAGE +0 -5
- data/ahn_generators/component/component_generator.rb +0 -57
- data/ahn_generators/component/templates/configuration.rb +0 -0
- data/ahn_generators/component/templates/lib/lib.rb.erb +0 -3
- data/ahn_generators/component/templates/test/test.rb.erb +0 -12
- data/ahn_generators/component/templates/test/test_helper.rb +0 -14
- data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +0 -14
- data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +0 -31
- data/lib/adhearsion/core_extensions/array.rb +0 -0
- data/lib/adhearsion/core_extensions/guid.rb +0 -5
- data/lib/adhearsion/core_extensions/hash.rb +0 -0
- data/lib/adhearsion/core_extensions/numeric.rb +0 -4
- data/lib/adhearsion/core_extensions/proc.rb +0 -0
- data/lib/adhearsion/core_extensions/pseudo_uuid.rb +0 -11
- data/lib/adhearsion/core_extensions/publishable.rb +0 -73
- data/lib/adhearsion/core_extensions/string.rb +0 -26
- data/lib/adhearsion/core_extensions/thread.rb +0 -13
- data/lib/adhearsion/core_extensions/time.rb +0 -0
- data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/rest_gateway.rb +0 -9
- data/lib/adhearsion/distributed/gateways/soap_gateway.rb +0 -9
- data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +0 -9
- data/lib/adhearsion/distributed/peer_finder.rb +0 -0
- data/lib/adhearsion/distributed/remote_cli.rb +0 -0
- data/lib/adhearsion/hooks.rb +0 -57
- data/lib/adhearsion/initializer/paths.rb +0 -55
- data/lib/adhearsion/services/scheduler.rb +0 -5
- data/lib/adhearsion/voip/asterisk/ami.rb +0 -147
- data/lib/adhearsion/voip/asterisk/ami/actions.rb +0 -238
- data/lib/adhearsion/voip/asterisk/ami/machine.rb +0 -871
- data/lib/adhearsion/voip/asterisk/ami/machine.rl +0 -109
- data/lib/adhearsion/voip/asterisk/ami/parser.rb +0 -262
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/spec/fixtures/dialplan.rb +0 -3
- data/spec/initializer/test_configuration.rb +0 -267
- data/spec/initializer/test_loading.rb +0 -162
- data/spec/initializer/test_paths.rb +0 -43
- data/spec/silence.rb +0 -10
- data/spec/test_ahn_command.rb +0 -149
- data/spec/test_code_quality.rb +0 -87
- data/spec/test_component_manager.rb +0 -97
- data/spec/test_constants.rb +0 -8
- data/spec/test_drb.rb +0 -104
- data/spec/test_helper.rb +0 -94
- data/spec/test_hooks.rb +0 -37
- data/spec/test_host_definitions.rb +0 -79
- data/spec/test_initialization.rb +0 -105
- data/spec/test_logging.rb +0 -80
- data/spec/test_relationship_properties.rb +0 -54
- data/spec/voip/asterisk/ami_response_definitions.rb +0 -23
- data/spec/voip/asterisk/config_file_generators/test_agents.rb +0 -253
- data/spec/voip/asterisk/config_file_generators/test_queues.rb +0 -325
- data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +0 -306
- data/spec/voip/asterisk/menu_command/test_calculated_match.rb +0 -111
- data/spec/voip/asterisk/menu_command/test_matchers.rb +0 -98
- data/spec/voip/asterisk/mock_ami_server.rb +0 -176
- data/spec/voip/asterisk/test_agi_server.rb +0 -451
- data/spec/voip/asterisk/test_ami.rb +0 -227
- data/spec/voip/asterisk/test_commands.rb +0 -2006
- data/spec/voip/asterisk/test_config_manager.rb +0 -129
- data/spec/voip/dsl/dispatcher_spec_helper.rb +0 -45
- data/spec/voip/dsl/test_dialing_dsl.rb +0 -268
- data/spec/voip/dsl/test_dispatcher.rb +0 -82
- data/spec/voip/dsl/test_parser.rb +0 -87
- data/spec/voip/freeswitch/test_basic_connection_manager.rb +0 -39
- data/spec/voip/freeswitch/test_inbound_connection_manager.rb +0 -39
- data/spec/voip/freeswitch/test_oes_server.rb +0 -9
- data/spec/voip/test_call_routing.rb +0 -127
- data/spec/voip/test_dialplan_manager.rb +0 -372
- data/spec/voip/test_numerical_string.rb +0 -48
- data/spec/voip/test_phone_number.rb +0 -36
- data/test/test_ahn_generator.rb +0 -59
- data/test/test_component_generator.rb +0 -52
- data/test/test_generator_helper.rb +0 -20
@@ -0,0 +1,47 @@
|
|
1
|
+
What is Stomp?
|
2
|
+
==============
|
3
|
+
|
4
|
+
Stomp is a very simple message-queue protocol with which two separate systems can communicate. Because the protocol is so simple, there are many Stomp server implementations from which you can choose. Some of these include
|
5
|
+
|
6
|
+
- ActiveMQ (http://activemq.com)
|
7
|
+
- Ruby "stompserver" gem (gem install stompserver)
|
8
|
+
- RabbitMQ (http://rabbitmq.com)
|
9
|
+
|
10
|
+
If you wish to get up and running with a development environment, the Ruby stompserver gem is a fantastic starting point. For a critical production system, ActiveMQ should probably be used but it bears the cumbersome paradigm of many "enterprisey" Java applications.
|
11
|
+
|
12
|
+
How does it work?
|
13
|
+
=================
|
14
|
+
|
15
|
+
Stomp is used when certain processes have defined responsibilities. For example, your Adhearsion application's responsibility is to communicate with your Asterisk machine. Other processes (e.g. a Rails web application) will probably need to instruct Adhearsion to do something. Instructions may include
|
16
|
+
|
17
|
+
- Start a new call between two given phone numbers
|
18
|
+
- Have a particular call do something based on a new event
|
19
|
+
- Hangup a call
|
20
|
+
|
21
|
+
Below is a diagram which should give you a better idea of how it works.
|
22
|
+
|
23
|
+
Process Process Process (e.g. Rails)
|
24
|
+
\ | /
|
25
|
+
\ | /
|
26
|
+
Stomp Server (e.g. ActiveMQ)
|
27
|
+
|
|
28
|
+
|
|
29
|
+
Process (e.g. Adhearsion)
|
30
|
+
|
31
|
+
Note: Adhearsion could also be the sender of messages through the Stomp server which are consumed by a number of handlers.
|
32
|
+
|
33
|
+
Setting up a Ruby Stomp server
|
34
|
+
==============================
|
35
|
+
|
36
|
+
Install the pure-Ruby Stomp server by doing "gem install stompserver". This will add the "stompserver" command to your system. When running it without any parameters, it starts without requiring authentication. If you're wanting to get a quick experiment running, I recommend simply doing that.
|
37
|
+
|
38
|
+
Open the config.yml file in the stomp_gateway component folder. Comment out the four settings at the top of the file named "user", "pass", "host" and "port" by prepending a "#" to their line. This will cause the component to choose defaults for those properties. The component's defaults will match the expected credentials for the experimental stompserver you're already running on your computer.
|
39
|
+
|
40
|
+
You also need specify a subscription name in
|
41
|
+
|
42
|
+
events.stomp.start_call.each do |event|
|
43
|
+
# The "event" variable holds a Stomp::Message object.
|
44
|
+
name = event.headers
|
45
|
+
end
|
46
|
+
|
47
|
+
You a
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Comment out any of these properties to use a default.
|
2
|
+
|
3
|
+
user: stomp_user
|
4
|
+
pass: secret_password
|
5
|
+
host: localhost
|
6
|
+
port: 61613
|
7
|
+
|
8
|
+
### Add your list of subscriptions below that this gateway should proxy to events.rb
|
9
|
+
|
10
|
+
# subscriptions:
|
11
|
+
# - start_call
|
12
|
+
# - hangup_call
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'stomp'
|
2
|
+
|
3
|
+
# TODO: Recover from a disconnect!
|
4
|
+
|
5
|
+
initialization do
|
6
|
+
user = COMPONENTS.stomp_gateway[:user] || ""
|
7
|
+
pass = COMPONENTS.stomp_gateway[:pass] || ""
|
8
|
+
host = COMPONENTS.stomp_gateway[:host] || "localhost"
|
9
|
+
port = COMPONENTS.stomp_gateway[:port] || 61613
|
10
|
+
|
11
|
+
::StompGatewayConnection = Stomp::Client.open(user, pass, host, port)
|
12
|
+
|
13
|
+
subscriptions = COMPONENTS.stomp_gateway["subscriptions"]
|
14
|
+
|
15
|
+
ahn_log.stomp_gateway "Connection established. Subscriptions: #{subscriptions.inspect}"
|
16
|
+
|
17
|
+
Events.register_namespace_name "/stomp"
|
18
|
+
|
19
|
+
subscriptions.each do |subscription|
|
20
|
+
Events.register_namespace_name "/stomp/#{subscription}"
|
21
|
+
::StompGatewayConnection.subscribe subscription do |event|
|
22
|
+
Adhearsion::Events.trigger ["stomp", subscription], event
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
methods_for :global do
|
29
|
+
def send_stomp(destination, message, headers={})
|
30
|
+
::StompGatewayConnection.send(destination, message, headers)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# In the future, I may add a methods_for(:events) method which allows synchronous messaging.
|
@@ -1,10 +1,14 @@
|
|
1
|
+
methods_for :dialplan do
|
2
|
+
def simon_game
|
3
|
+
SimonGame.new(self).start
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
1
7
|
class SimonGame
|
2
|
-
add_call_context :as => :call_context
|
3
8
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
initialize_attempt
|
9
|
+
def initialize(call)
|
10
|
+
@call = call
|
11
|
+
reset
|
8
12
|
end
|
9
13
|
|
10
14
|
def start
|
@@ -20,38 +24,29 @@ class SimonGame
|
|
20
24
|
end
|
21
25
|
|
22
26
|
def update_number
|
23
|
-
initialize_attempt
|
24
27
|
@number << random_number
|
25
28
|
end
|
26
29
|
|
27
30
|
def say_number
|
28
31
|
update_number
|
29
|
-
|
32
|
+
@call.say_digits @number
|
30
33
|
end
|
31
34
|
|
32
35
|
def collect_attempt
|
33
|
-
@attempt =
|
36
|
+
@attempt = @call.input @number.length
|
34
37
|
end
|
35
38
|
|
36
39
|
def verify_attempt
|
37
40
|
if attempt_correct?
|
38
|
-
|
41
|
+
@call.play 'good'
|
39
42
|
else
|
40
|
-
|
43
|
+
@call.play %W[#{@number.length-1} times wrong-try-again-smarty]
|
41
44
|
reset
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
45
48
|
def attempt_correct?
|
46
|
-
attempt == number
|
47
|
-
end
|
48
|
-
|
49
|
-
def initialize_attempt
|
50
|
-
@attempt ||= ''
|
51
|
-
end
|
52
|
-
|
53
|
-
def initialize_number
|
54
|
-
@number ||= ''
|
49
|
+
@attempt == @number
|
55
50
|
end
|
56
51
|
|
57
52
|
def reset
|
@@ -26,12 +26,9 @@ Adhearsion::Configuration.configure do |config|
|
|
26
26
|
|
27
27
|
# By default Asterisk is enabled with the default settings
|
28
28
|
config.enable_asterisk
|
29
|
-
# config.asterisk.enable_ami :host => "127.0.0.1", :username => "admin", :password => "password"
|
29
|
+
# config.asterisk.enable_ami :host => "127.0.0.1", :username => "admin", :password => "password", :events => true
|
30
30
|
|
31
|
-
#
|
32
|
-
# config.enable_asterisk :listening_port => 4574, :listening_host => "127.0.0.1"
|
33
|
-
|
34
|
-
# config.enable_drb
|
31
|
+
# config.enable_drb
|
35
32
|
|
36
33
|
# Streamlined Rails integration! The first argument should be a relative or absolute path to
|
37
34
|
# the Rails app folder with which you're integrating. The second argument must be one of the
|
@@ -50,4 +47,4 @@ Adhearsion::Configuration.configure do |config|
|
|
50
47
|
# :host => 'db.example.org'
|
51
48
|
end
|
52
49
|
|
53
|
-
Adhearsion::Initializer.start_from_init_file(__FILE__, File.dirname(__FILE__) + "/..")
|
50
|
+
Adhearsion::Initializer.start_from_init_file(__FILE__, File.dirname(__FILE__) + "/..")
|
@@ -0,0 +1,32 @@
|
|
1
|
+
##
|
2
|
+
# In this file you can define callbacks for different aspects of the framework. Below is an example:
|
3
|
+
##
|
4
|
+
#
|
5
|
+
# events.asterisk.before_call.each do |call|
|
6
|
+
# # This simply logs the extension for all calls going through this Adhearsion app.
|
7
|
+
# extension = call.variables[:extension]
|
8
|
+
# ahn_log "Got a new call with extension #{extension}"
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
##
|
12
|
+
# Asterisk Manager Interface example:
|
13
|
+
#
|
14
|
+
# events.asterisk.manager_interface.each do |event|
|
15
|
+
# ahn_log.events event.inspect
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# This assumes you gave :events => true to the config.asterisk.enable_ami method in config/startup.rb
|
19
|
+
#
|
20
|
+
##
|
21
|
+
# Here is a list of the events included by default:
|
22
|
+
#
|
23
|
+
# - events.asterisk.manager_interface
|
24
|
+
# - events.after_initialized
|
25
|
+
# - events.shutdown
|
26
|
+
# - events.asterisk.before_call
|
27
|
+
# - events.asterisk.failed_call
|
28
|
+
# - events.asterisk.call_hangup
|
29
|
+
#
|
30
|
+
#
|
31
|
+
# Note: events are mostly for components to register and expose to you.
|
32
|
+
##
|
data/bin/jahn
CHANGED
@@ -29,4 +29,14 @@ require 'adhearsion/cli'
|
|
29
29
|
# file from an app.
|
30
30
|
# require 'adhearsion/jruby'
|
31
31
|
|
32
|
+
abort(<<-MESSAGE) unless RUBY_PLATFORM =~ /java/
|
33
|
+
You must use jahn with JRuby! Are you running this script after installing Adhearsion with non-JRuby RubyGems?
|
34
|
+
|
35
|
+
If you don't want to install Adhearsion with the JRuby version of RubyGems, try running jahn directly with an absolute path:
|
36
|
+
|
37
|
+
#{File.expand_path(__FILE__)} start your_app_name
|
38
|
+
|
39
|
+
Note: You must have the jruby executable in your $PATH and $JRUBY_HOME set.
|
40
|
+
MESSAGE
|
41
|
+
|
32
42
|
Adhearsion::CLI::AhnCommand.execute!
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# This is a file which shows you how to use the Asterisk Manager Interface library in a standalone Ruby script.
|
2
|
+
|
3
|
+
PATH_TO_ADHEARSION = File.join(File.dirname(__FILE__), "/../..")
|
4
|
+
|
5
|
+
MANAGER_CONNECTION_INFORMATION = {
|
6
|
+
:host => "10.0.1.97",
|
7
|
+
:username => "jicksta",
|
8
|
+
:password => "roflcopter",
|
9
|
+
:events => true
|
10
|
+
}
|
11
|
+
|
12
|
+
require 'rubygems'
|
13
|
+
begin
|
14
|
+
require 'adhearsion'
|
15
|
+
rescue LoadError
|
16
|
+
begin
|
17
|
+
require File.join(PATH_TO_ADHEARSION, "/lib/adhearsion")
|
18
|
+
rescue LoadError
|
19
|
+
abort "Could not find Adhearsion! Please update the PATH_TO_ADHEARSION constant in this file"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'adhearsion/voip/asterisk/manager_interface'
|
24
|
+
|
25
|
+
# If you'd like to see the AMI protocol data, change this to :debug
|
26
|
+
Adhearsion::Logging.logging_level = :warn
|
27
|
+
|
28
|
+
# This makes addressing the ManagerInterface class a little cleaner
|
29
|
+
include Adhearsion::VoIP::Asterisk::Manager
|
30
|
+
|
31
|
+
# Let's instantiate a new ManagerInterface object and have it automatically connect using the Hash we defined above.
|
32
|
+
interface = ManagerInterface.connect MANAGER_CONNECTION_INFORMATION
|
33
|
+
|
34
|
+
# Send an AMI action with our new ManagerInterface object. This will return an Array of SIPPeer events.
|
35
|
+
sip_peers = interface.send_action "SIPPeers"
|
36
|
+
|
37
|
+
# Pretty-print the SIP peers on the server
|
38
|
+
|
39
|
+
if sip_peers.any?
|
40
|
+
sip_peers.each do |peer|
|
41
|
+
# Uncomment the following line to view all the headers for each peer.
|
42
|
+
# p peer.headers
|
43
|
+
|
44
|
+
peer_name = peer.headers["ObjectName"]
|
45
|
+
peer_status = peer.headers["Status"]
|
46
|
+
|
47
|
+
puts "#{peer_name}: #{peer_status}"
|
48
|
+
end
|
49
|
+
else
|
50
|
+
puts "This Asterisk server has no SIP peers!"
|
51
|
+
end
|
data/lib/adhearsion.rb
CHANGED
@@ -3,29 +3,35 @@ STDERR.puts "WARNING: You are running Adhearsion in an unsupported
|
|
3
3
|
version of Ruby (Ruby #{RUBY_VERSION} #{RUBY_RELEASE_DATE})!
|
4
4
|
Please upgrade to at least Ruby v1.8.5." if RUBY_VERSION < "1.8.5"
|
5
5
|
|
6
|
-
module Adhearsion
|
7
|
-
# Sets up the Gem require path.
|
8
|
-
AHN_INSTALL_DIR = File.expand_path(File.dirname(__FILE__) + "/..")
|
9
|
-
CONFIG = {}
|
10
|
-
end
|
11
|
-
|
12
6
|
$: << File.expand_path(File.dirname(__FILE__))
|
13
7
|
|
14
8
|
require 'rubygems'
|
9
|
+
|
15
10
|
require 'adhearsion/version'
|
16
11
|
require 'adhearsion/voip/call'
|
17
12
|
require 'adhearsion/voip/dial_plan'
|
18
13
|
require 'adhearsion/voip/asterisk/special_dial_plan_managers'
|
19
|
-
require 'adhearsion/
|
20
|
-
require 'adhearsion/
|
21
|
-
require 'adhearsion/hooks'
|
14
|
+
require 'adhearsion/foundation/all'
|
15
|
+
require 'adhearsion/events_support'
|
22
16
|
require 'adhearsion/logging'
|
17
|
+
require 'adhearsion/component_manager'
|
23
18
|
require 'adhearsion/initializer/configuration'
|
24
19
|
require 'adhearsion/initializer'
|
25
|
-
require 'adhearsion/initializer/paths'
|
26
20
|
require 'adhearsion/voip/dsl/numerical_string'
|
27
21
|
require 'adhearsion/voip/dsl/dialplan/parser'
|
28
22
|
require 'adhearsion/voip/commands'
|
29
23
|
require 'adhearsion/voip/asterisk/commands'
|
30
24
|
require 'adhearsion/voip/dsl/dialing_dsl'
|
31
|
-
require 'adhearsion/voip/call_routing'
|
25
|
+
require 'adhearsion/voip/call_routing'
|
26
|
+
|
27
|
+
module Adhearsion
|
28
|
+
# Sets up the Gem require path.
|
29
|
+
AHN_INSTALL_DIR = File.expand_path(File.dirname(__FILE__) + "/..")
|
30
|
+
AHN_CONFIG = Configuration.new
|
31
|
+
|
32
|
+
##
|
33
|
+
# This Array holds all the Threads whose life matters. Adhearsion will not exit until all of these have died.
|
34
|
+
#
|
35
|
+
IMPORTANT_THREADS = []
|
36
|
+
|
37
|
+
end
|
data/lib/adhearsion/cli.rb
CHANGED
@@ -6,16 +6,26 @@ module Adhearsion
|
|
6
6
|
USAGE = <<USAGE
|
7
7
|
Usage:
|
8
8
|
ahn create /path/to/directory
|
9
|
-
ahn start [daemon] [directory]
|
9
|
+
ahn start [daemon] [/path/to/directory]
|
10
10
|
ahn version|-v|--v|-version|--version
|
11
11
|
ahn help|-h|--h|--help|-help
|
12
|
-
|
13
|
-
|
14
|
-
ahn
|
12
|
+
|
13
|
+
ahn enable component COMPONENT_NAME
|
14
|
+
ahn disable component COMPONENT_NAME
|
15
|
+
ahn create component COMPONENT_NAME
|
15
16
|
USAGE
|
16
17
|
|
17
18
|
def self.execute!
|
18
19
|
CommandHandler.send(*parse_arguments)
|
20
|
+
rescue CommandHandler::CLIException => error
|
21
|
+
fail_and_print_usage error
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Provides a small abstraction of Kernel::abort().
|
26
|
+
#
|
27
|
+
def self.fail_and_print_usage(error)
|
28
|
+
Kernel.abort "#{error.message}\n\n#{USAGE}"
|
19
29
|
end
|
20
30
|
|
21
31
|
def self.parse_arguments(args=ARGV.clone)
|
@@ -23,14 +33,14 @@ USAGE
|
|
23
33
|
case action
|
24
34
|
when /^-?-?h(elp)?$/, nil then [:help]
|
25
35
|
when /^-?-?v(ersion)?$/ then [:version]
|
26
|
-
when
|
27
|
-
[:create, args
|
36
|
+
when "create"
|
37
|
+
[:create, *args]
|
28
38
|
when 'start'
|
29
39
|
pid_file_regexp = /^--pid-file=(.+)$/
|
30
40
|
if args.size > 3
|
31
|
-
|
41
|
+
fail_and_print_usage "Too many arguments supplied!" if args.size > 3
|
32
42
|
elsif args.size == 3
|
33
|
-
|
43
|
+
fail_and_print_usage "Unrecognized final argument #{args.last}" unless args.last =~ pid_file_regexp
|
34
44
|
pid_file = args.pop[pid_file_regexp, 1]
|
35
45
|
else
|
36
46
|
pid_file = nil
|
@@ -42,11 +52,19 @@ USAGE
|
|
42
52
|
elsif args.size == 1
|
43
53
|
path, daemon = args.first, false
|
44
54
|
else
|
45
|
-
|
55
|
+
fail_and_print_usage "Invalid format for the start CLI command!"
|
46
56
|
end
|
47
57
|
[:start, path, daemon, pid_file]
|
48
58
|
when '-'
|
49
59
|
[:start, Dir.pwd]
|
60
|
+
when "enable", "disable"
|
61
|
+
if args.size == 1
|
62
|
+
raise CommandHandler::UnknownCommand, "Must supply an argument for what you wish to #{action}"
|
63
|
+
elsif args.size == 2
|
64
|
+
[action, *args]
|
65
|
+
else
|
66
|
+
raise CommandHandler::UnknownCommand, "Too many arguments supplied!"
|
67
|
+
end
|
50
68
|
else
|
51
69
|
[action, *args]
|
52
70
|
end
|
@@ -54,20 +72,61 @@ USAGE
|
|
54
72
|
|
55
73
|
module CommandHandler
|
56
74
|
class << self
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
75
|
+
|
76
|
+
def create(*args)
|
77
|
+
if args.size.zero?
|
78
|
+
raise CommandHandler::UnknownCommand.new("Must specify something to create!")
|
79
|
+
elsif args.size == 1
|
80
|
+
# We're creating a project
|
81
|
+
path = args.first
|
82
|
+
require 'rubigen'
|
83
|
+
require 'rubigen/scripts/generate'
|
84
|
+
source = RubiGen::PathSource.new(:application,
|
85
|
+
File.join(File.dirname(__FILE__), "../../app_generators"))
|
86
|
+
RubiGen::Base.reset_sources
|
87
|
+
RubiGen::Base.append_sources source
|
88
|
+
RubiGen::Scripts::Generate.new.run([path], :generator => 'ahn')
|
89
|
+
elsif args.size == 2
|
90
|
+
# We're creating a feature (e.g. a component)
|
91
|
+
feature_type, component_name = args
|
92
|
+
|
93
|
+
if feature_type != "component"
|
94
|
+
# At the moment, only components can be created.
|
95
|
+
raise CommandHandler::UnknownCommand.new("Don't know how to create '#{feature_type}'")
|
96
|
+
end
|
97
|
+
|
98
|
+
if component_name !~ /^[a-z][\w_]+$/
|
99
|
+
raise CommandHandler::ComponentError.new("Component name must be lowercase alphanumeric characters " +
|
100
|
+
"and begin with a character")
|
101
|
+
end
|
102
|
+
|
103
|
+
app_path = PathString.from_application_subdirectory Dir.pwd
|
104
|
+
|
105
|
+
raise PathInvalid.new(Dir.pwd) if app_path.nil?
|
106
|
+
|
107
|
+
new_component_dir = app_path + "/components/#{component_name}"
|
108
|
+
raise ComponentError.new("Component #{component_name} already exists!") if File.exists?(new_component_dir)
|
109
|
+
|
110
|
+
# Everything's good. Let's create the component
|
111
|
+
Dir.mkdir new_component_dir
|
112
|
+
File.open(new_component_dir + "/#{component_name}.rb","w") do |file|
|
113
|
+
file.puts <<-RUBY
|
114
|
+
# See http://docs.adhearsion.com for more information on how to write components or
|
115
|
+
# look at the examples in newly-created projects.
|
116
|
+
RUBY
|
117
|
+
end
|
118
|
+
File.open(new_component_dir + "/config.yml","w") do |file|
|
119
|
+
file.puts '# You can use this file for component-specific configuration.'
|
120
|
+
end
|
121
|
+
puts "Created blank component '#{component_name}' at components/#{component_name}"
|
122
|
+
else
|
123
|
+
raise CommandHandler::UnknownCommand.new("Provided too many arguments to 'create'")
|
124
|
+
end
|
66
125
|
end
|
67
126
|
|
68
127
|
def start(path, daemon=false, pid_file=nil)
|
69
128
|
raise PathInvalid, path unless File.exists? path + "/.ahnrc"
|
70
|
-
Adhearsion::Initializer.
|
129
|
+
Adhearsion::Initializer.start path, :daemon => daemon, :pid_file => pid_file
|
71
130
|
end
|
72
131
|
|
73
132
|
def version
|
@@ -78,26 +137,84 @@ USAGE
|
|
78
137
|
puts USAGE
|
79
138
|
end
|
80
139
|
|
140
|
+
def enable(type, name)
|
141
|
+
case type
|
142
|
+
when "component"
|
143
|
+
app_path = PathString.from_application_subdirectory Dir.pwd
|
144
|
+
if app_path
|
145
|
+
disabled_component_path = File.join app_path, "components", "disabled", name
|
146
|
+
enabled_component_path = File.join app_path, "components", name
|
147
|
+
if File.directory? disabled_component_path
|
148
|
+
FileUtils.mv disabled_component_path, enabled_component_path
|
149
|
+
puts "Enabled component #{name}"
|
150
|
+
else
|
151
|
+
raise ComponentError.new("There is no components/disabled directory!")
|
152
|
+
end
|
153
|
+
else
|
154
|
+
raise PathInvalid.new(Dir.pwd)
|
155
|
+
end
|
156
|
+
else
|
157
|
+
raise UnknownCommand.new("enable #{type}")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def disable(type, name)
|
162
|
+
case type
|
163
|
+
when "component"
|
164
|
+
app_path = PathString.from_application_subdirectory Dir.pwd
|
165
|
+
if app_path
|
166
|
+
disabled_dir = File.join app_path, "components", "disabled"
|
167
|
+
|
168
|
+
disabled_component_path = File.join disabled_dir, name
|
169
|
+
enabled_component_path = File.join app_path, "components", name
|
170
|
+
|
171
|
+
Dir.mkdir disabled_dir unless File.directory?(disabled_dir)
|
172
|
+
|
173
|
+
if File.directory? enabled_component_path
|
174
|
+
if File.directory?(disabled_component_path)
|
175
|
+
raise ComponentError.new("There is already a disabled component at #{disabled_component_path}")
|
176
|
+
else
|
177
|
+
FileUtils.mv enabled_component_path, disabled_component_path
|
178
|
+
puts "Disabled component #{name}"
|
179
|
+
end
|
180
|
+
else
|
181
|
+
raise ComponentError.new("Could not find component #{name} at #{enabled_component_path} !")
|
182
|
+
end
|
183
|
+
else
|
184
|
+
raise PathInvalid.new(Dir.pwd)
|
185
|
+
end
|
186
|
+
else
|
187
|
+
raise UnknownCommand.new("disable #{type}")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
81
191
|
def method_missing(action, *args)
|
82
192
|
raise UnknownCommand, [action, *args] * " "
|
83
193
|
end
|
194
|
+
|
195
|
+
private
|
196
|
+
|
84
197
|
end
|
85
198
|
|
86
|
-
class
|
199
|
+
class CLIException < Exception; end
|
200
|
+
|
201
|
+
class UnknownCommand < CLIException
|
87
202
|
def initialize(cmd)
|
88
|
-
super "Unknown command: #{cmd}
|
203
|
+
super "Unknown command: #{cmd}"
|
89
204
|
end
|
90
205
|
end
|
91
206
|
|
92
|
-
class
|
207
|
+
class ComponentError < CLIException; end
|
208
|
+
|
209
|
+
class UnknownProject < CLIException
|
93
210
|
def initialize(project)
|
94
211
|
super "Application #{project} does not exist! Have you installed it?"
|
95
212
|
end
|
96
213
|
end
|
97
214
|
|
98
|
-
class PathInvalid <
|
215
|
+
class PathInvalid < CLIException
|
99
216
|
def initialize(path)
|
100
|
-
super "Directory #{path} does not
|
217
|
+
super "Directory #{path} does not belong to an Adhearsion project!"
|
101
218
|
end
|
102
219
|
end
|
103
220
|
end
|