jicksta-adhearsion 0.7.999
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.
- data/CHANGELOG +6 -0
- data/EVENTS +11 -0
- data/LICENSE +456 -0
- data/README.txt +5 -0
- data/Rakefile +120 -0
- data/adhearsion.gemspec +146 -0
- data/app_generators/ahn/USAGE +5 -0
- data/app_generators/ahn/ahn_generator.rb +87 -0
- data/app_generators/ahn/templates/.ahnrc +34 -0
- data/app_generators/ahn/templates/README +8 -0
- data/app_generators/ahn/templates/Rakefile +23 -0
- 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/restful_rpc/README.markdown +11 -0
- data/app_generators/ahn/templates/components/restful_rpc/config.yml +34 -0
- data/app_generators/ahn/templates/components/restful_rpc/example-client.rb +48 -0
- data/app_generators/ahn/templates/components/restful_rpc/restful_rpc.rb +87 -0
- data/app_generators/ahn/templates/components/simon_game/simon_game.rb +56 -0
- data/app_generators/ahn/templates/config/startup.rb +53 -0
- data/app_generators/ahn/templates/dialplan.rb +3 -0
- data/app_generators/ahn/templates/events.rb +32 -0
- data/bin/ahn +28 -0
- data/bin/ahnctl +68 -0
- data/bin/jahn +42 -0
- data/examples/asterisk_manager_interface/standalone.rb +51 -0
- data/lib/adhearsion/cli.rb +223 -0
- data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
- data/lib/adhearsion/component_manager.rb +208 -0
- data/lib/adhearsion/events_support.rb +84 -0
- data/lib/adhearsion/foundation/all.rb +9 -0
- data/lib/adhearsion/foundation/blank_slate.rb +5 -0
- data/lib/adhearsion/foundation/custom_daemonizer.rb +45 -0
- data/lib/adhearsion/foundation/event_socket.rb +203 -0
- data/lib/adhearsion/foundation/future_resource.rb +36 -0
- data/lib/adhearsion/foundation/global.rb +1 -0
- data/lib/adhearsion/foundation/metaprogramming.rb +17 -0
- data/lib/adhearsion/foundation/numeric.rb +13 -0
- data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
- data/lib/adhearsion/foundation/relationship_properties.rb +42 -0
- data/lib/adhearsion/foundation/string.rb +26 -0
- data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
- data/lib/adhearsion/foundation/thread_safety.rb +7 -0
- data/lib/adhearsion/host_definitions.rb +67 -0
- data/lib/adhearsion/initializer/asterisk.rb +81 -0
- data/lib/adhearsion/initializer/configuration.rb +254 -0
- data/lib/adhearsion/initializer/database.rb +49 -0
- data/lib/adhearsion/initializer/drb.rb +31 -0
- data/lib/adhearsion/initializer/freeswitch.rb +22 -0
- data/lib/adhearsion/initializer/rails.rb +40 -0
- data/lib/adhearsion/initializer.rb +373 -0
- data/lib/adhearsion/logging.rb +92 -0
- data/lib/adhearsion/tasks/database.rb +5 -0
- data/lib/adhearsion/tasks/deprecations.rb +59 -0
- data/lib/adhearsion/tasks/generating.rb +20 -0
- data/lib/adhearsion/tasks/lint.rb +4 -0
- data/lib/adhearsion/tasks/testing.rb +37 -0
- data/lib/adhearsion/tasks.rb +16 -0
- data/lib/adhearsion/version.rb +9 -0
- data/lib/adhearsion/voip/asterisk/agi_server.rb +81 -0
- data/lib/adhearsion/voip/asterisk/commands.rb +1284 -0
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +101 -0
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
- data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -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/manager_interface.rb +562 -0
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
- data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
- data/lib/adhearsion/voip/asterisk.rb +4 -0
- data/lib/adhearsion/voip/call.rb +440 -0
- data/lib/adhearsion/voip/call_routing.rb +64 -0
- data/lib/adhearsion/voip/commands.rb +9 -0
- data/lib/adhearsion/voip/constants.rb +39 -0
- data/lib/adhearsion/voip/conveniences.rb +18 -0
- data/lib/adhearsion/voip/dial_plan.rb +218 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +71 -0
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
- data/lib/adhearsion/voip/dsl/numerical_string.rb +117 -0
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +58 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
- data/lib/adhearsion.rb +37 -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
- data/lib/theatre.rb +151 -0
- metadata +177 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def unindent
|
4
|
+
gsub(/^\s*/,'')
|
5
|
+
end
|
6
|
+
|
7
|
+
def unindent!
|
8
|
+
gsub!(/^\s*/,'')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.random_char
|
12
|
+
case random_digit = rand(62)
|
13
|
+
when 0...10 : random_digit.to_s
|
14
|
+
when 10...36 : (random_digit + 55).chr
|
15
|
+
when 36...62 : (random_digit + 61).chr
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.random(length_of_string=8)
|
20
|
+
Array.new(length_of_string) { random_char }.join
|
21
|
+
end
|
22
|
+
|
23
|
+
def nameify() downcase.gsub(/[^\w]/, '') end
|
24
|
+
def nameify!() replace nameify end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
##
|
2
|
+
# Implementation of a Thread-safe Hash. Works by delegating methods to a Hash behind-the-scenes after obtaining an exclusive # lock. Use exactly as you would a normal Hash.
|
3
|
+
#
|
4
|
+
class SynchronizedHash
|
5
|
+
|
6
|
+
def self.atomically_delegate(method_name)
|
7
|
+
class_eval(<<-RUBY, __FILE__, __LINE__)
|
8
|
+
def #{method_name}(*args, &block)
|
9
|
+
@lock.synchronize do
|
10
|
+
@delegate.send(#{method_name.inspect}, *args, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
RUBY
|
14
|
+
end
|
15
|
+
|
16
|
+
# Hash-related methods
|
17
|
+
|
18
|
+
atomically_delegate :[]
|
19
|
+
atomically_delegate :[]=
|
20
|
+
atomically_delegate :all?
|
21
|
+
atomically_delegate :any?
|
22
|
+
atomically_delegate :clear
|
23
|
+
atomically_delegate :collect
|
24
|
+
atomically_delegate :default
|
25
|
+
atomically_delegate :default=
|
26
|
+
atomically_delegate :delete
|
27
|
+
atomically_delegate :delete_if
|
28
|
+
atomically_delegate :detect
|
29
|
+
atomically_delegate :each
|
30
|
+
atomically_delegate :each_key
|
31
|
+
atomically_delegate :each_pair
|
32
|
+
atomically_delegate :each_value
|
33
|
+
atomically_delegate :each_with_index
|
34
|
+
atomically_delegate :empty?
|
35
|
+
atomically_delegate :entries
|
36
|
+
atomically_delegate :fetch
|
37
|
+
atomically_delegate :find
|
38
|
+
atomically_delegate :find_all
|
39
|
+
atomically_delegate :grep
|
40
|
+
atomically_delegate :has_key?
|
41
|
+
atomically_delegate :has_value?
|
42
|
+
atomically_delegate :include?
|
43
|
+
atomically_delegate :index
|
44
|
+
atomically_delegate :indexes
|
45
|
+
atomically_delegate :indices
|
46
|
+
atomically_delegate :inject
|
47
|
+
atomically_delegate :invert
|
48
|
+
atomically_delegate :key?
|
49
|
+
atomically_delegate :keys
|
50
|
+
atomically_delegate :length
|
51
|
+
atomically_delegate :map
|
52
|
+
atomically_delegate :max
|
53
|
+
atomically_delegate :member?
|
54
|
+
atomically_delegate :merge
|
55
|
+
atomically_delegate :merge!
|
56
|
+
atomically_delegate :min
|
57
|
+
atomically_delegate :partition
|
58
|
+
atomically_delegate :rehash
|
59
|
+
atomically_delegate :reject
|
60
|
+
atomically_delegate :reject!
|
61
|
+
atomically_delegate :replace
|
62
|
+
atomically_delegate :select
|
63
|
+
atomically_delegate :shift
|
64
|
+
atomically_delegate :size
|
65
|
+
atomically_delegate :sort
|
66
|
+
atomically_delegate :sort_by
|
67
|
+
atomically_delegate :store
|
68
|
+
atomically_delegate :to_hash
|
69
|
+
atomically_delegate :update
|
70
|
+
atomically_delegate :value?
|
71
|
+
atomically_delegate :values
|
72
|
+
atomically_delegate :values_at
|
73
|
+
atomically_delegate :zip
|
74
|
+
|
75
|
+
# Object-related methods
|
76
|
+
|
77
|
+
atomically_delegate :inspect
|
78
|
+
atomically_delegate :to_s
|
79
|
+
atomically_delegate :marshal_dump
|
80
|
+
|
81
|
+
def initialize(*args, &block)
|
82
|
+
@delegate = Hash.new(*args, &block)
|
83
|
+
@lock = Mutex.new
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# If you need to do many operations atomically (a la transaction), you can call this method and access the yielded Hash
|
88
|
+
# which can be safely modified for the duration of your block.
|
89
|
+
#
|
90
|
+
# @yield [Hash] the Hash on which you can safely operate during your block.
|
91
|
+
#
|
92
|
+
def with_lock(&block)
|
93
|
+
@lock.synchronize { yield @delegate }
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
|
5
|
+
##
|
6
|
+
# This class isn't yet tied into Adhearsion.
|
7
|
+
#
|
8
|
+
class HostDefinition
|
9
|
+
|
10
|
+
SUPPORTED_KEYS = [:host, :username, :password, :key, :name]
|
11
|
+
|
12
|
+
cattr_reader :definitions
|
13
|
+
@@definitions ||= []
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def import_from_data_structure(local_definitions)
|
17
|
+
case local_definitions
|
18
|
+
when Array
|
19
|
+
local_definitions.each do |definition|
|
20
|
+
raise HostDefinitionException, "Unrecognized definition: #{definition}" unless definition.is_a?(Hash)
|
21
|
+
end
|
22
|
+
local_definitions.map { |definition| new definition }
|
23
|
+
when Hash
|
24
|
+
local_definitions.map do |(name,definition)|
|
25
|
+
new definition.merge(:name => name)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
raise HostDefinitionException, "Unrecognized definition #{local_definitions}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def import_from_yaml(yaml_string)
|
33
|
+
import_from_data_structure YAML.load(yaml_string)
|
34
|
+
end
|
35
|
+
|
36
|
+
def import_from_yaml_file(file)
|
37
|
+
import_from_yaml YAML.load_file(file)
|
38
|
+
end
|
39
|
+
|
40
|
+
def clear_definitions!
|
41
|
+
definitions.clear
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :name, :host, :username, :password, :key
|
46
|
+
def initialize(hash)
|
47
|
+
@host, @username, @password, @key, @name = hash.values_at(*SUPPORTED_KEYS)
|
48
|
+
@name ||= new_guid
|
49
|
+
|
50
|
+
unrecognized_keys = hash.keys - SUPPORTED_KEYS
|
51
|
+
raise HostDefinitionException, "Unrecognized key(s): #{unrecognized_keys.map(&:inspect).to_sentence}" if unrecognized_keys.any?
|
52
|
+
raise HostDefinitionException, "You must supply a password or key!" if username && !(password || key)
|
53
|
+
raise HostDefinitionException, "You must supply a username!" unless username
|
54
|
+
raise HostDefinitionException, 'You cannot supply both a password and key!' if password && key
|
55
|
+
raise HostDefinitionException, 'You must supply a host!' unless host
|
56
|
+
|
57
|
+
self.class.definitions << self
|
58
|
+
end
|
59
|
+
|
60
|
+
class HostDefinitionException < Exception
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'adhearsion/voip/asterisk'
|
2
|
+
module Adhearsion
|
3
|
+
class Initializer
|
4
|
+
|
5
|
+
class AsteriskInitializer
|
6
|
+
|
7
|
+
cattr_accessor :config, :agi_server, :ami_client
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def start
|
11
|
+
self.config = AHN_CONFIG.asterisk
|
12
|
+
self.agi_server = initialize_agi
|
13
|
+
self.ami_client = VoIP::Asterisk.manager_interface = initialize_ami if config.ami_enabled?
|
14
|
+
join_server_thread_after_initialized
|
15
|
+
end
|
16
|
+
|
17
|
+
def stop
|
18
|
+
agi_server.stop
|
19
|
+
ami_client.disconnect! if ami_client
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def initialize_agi
|
25
|
+
VoIP::Asterisk::AGI::Server.new :host => config.listening_host,
|
26
|
+
:port => config.listening_port
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize_ami
|
30
|
+
options = ami_options
|
31
|
+
start_ami_after_initialized
|
32
|
+
returning VoIP::Asterisk::Manager::ManagerInterface.new(options) do
|
33
|
+
class << VoIP::Asterisk
|
34
|
+
if respond_to?(:manager_interface)
|
35
|
+
ahn_log.warn "Asterisk.manager_interface already initialized?"
|
36
|
+
else
|
37
|
+
def manager_interface
|
38
|
+
# ahn_log.ami.warn "Warning! This Asterisk.manager_interface() notation is for Adhearsion version 0.8.0 only. Subsequent versions of Adhearsion will use a feature called SuperManager. Migrating to use SuperManager will be very simple. See http://docs.adhearsion.com/AMI for more information."
|
39
|
+
Adhearsion::Initializer::AsteriskInitializer.ami_client
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def ami_options
|
47
|
+
%w(host port username password events).inject({}) do |options, property|
|
48
|
+
options[property.to_sym] = config.ami.send property
|
49
|
+
options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def join_server_thread_after_initialized
|
54
|
+
Events.register_callback(:after_initialized) do
|
55
|
+
begin
|
56
|
+
agi_server.start
|
57
|
+
rescue => e
|
58
|
+
ahn_log.fatal "Failed to start AGI server! #{e.inspect}"
|
59
|
+
abort
|
60
|
+
end
|
61
|
+
end
|
62
|
+
IMPORTANT_THREADS << agi_server
|
63
|
+
end
|
64
|
+
|
65
|
+
def start_ami_after_initialized
|
66
|
+
Events.register_callback(:after_initialized) do
|
67
|
+
begin
|
68
|
+
self.ami_client.connect!
|
69
|
+
rescue Errno::ECONNREFUSED
|
70
|
+
ahn_log.ami.error "Connection refused when connecting to AMI! Please check your configuration."
|
71
|
+
rescue => e
|
72
|
+
ahn_log.ami.error "Error connecting to AMI! #{e.inspect}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
class Configuration
|
3
|
+
module ConfigurationEntryPoint
|
4
|
+
def add_configuration_for(name)
|
5
|
+
configuration_class_name = "#{name}Configuration"
|
6
|
+
lowercased_name = name.to_s.underscore
|
7
|
+
|
8
|
+
class_eval(<<-EVAL, __FILE__, __LINE__)
|
9
|
+
def enable_#{lowercased_name}(configuration_options = {})
|
10
|
+
@#{lowercased_name}_configuration = #{configuration_class_name}.new(configuration_options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def #{lowercased_name}
|
14
|
+
@#{lowercased_name}_configuration
|
15
|
+
end
|
16
|
+
|
17
|
+
def #{lowercased_name}_enabled?
|
18
|
+
!#{lowercased_name}.nil?
|
19
|
+
end
|
20
|
+
EVAL
|
21
|
+
end
|
22
|
+
end
|
23
|
+
extend ConfigurationEntryPoint
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def configure(&block)
|
27
|
+
if Adhearsion.const_defined?(:AHN_CONFIG)
|
28
|
+
yield AHN_CONFIG if block_given?
|
29
|
+
else
|
30
|
+
Adhearsion.const_set(:AHN_CONFIG, new(&block))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :automatically_answer_incoming_calls
|
36
|
+
attr_accessor :end_call_on_hangup
|
37
|
+
attr_accessor :end_call_on_error
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
@automatically_answer_incoming_calls = true
|
41
|
+
@end_call_on_hangup = true
|
42
|
+
@end_call_on_error = true
|
43
|
+
yield self if block_given?
|
44
|
+
end
|
45
|
+
|
46
|
+
def ahnrc
|
47
|
+
@ahnrc
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Load the contents of an .ahnrc file into this Configuration.
|
52
|
+
#
|
53
|
+
# @param [String, Hash] ahnrc String of YAML .ahnrc data or a Hash of the pre-loaded YAML data structure
|
54
|
+
#
|
55
|
+
def ahnrc=(new_ahnrc)
|
56
|
+
case new_ahnrc
|
57
|
+
when Hash
|
58
|
+
@raw_ahnrc = new_ahnrc.to_yaml.freeze
|
59
|
+
@ahnrc = new_ahnrc.clone.freeze
|
60
|
+
when String
|
61
|
+
@raw_ahnrc = new_ahnrc.clone.freeze
|
62
|
+
@ahnrc = YAML.load(new_ahnrc).freeze
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def logging(options)
|
67
|
+
Adhearsion::Logging.logging_level = options[:level]
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Adhearsion's .ahnrc file is used to define paths to certain parts of the framework. For example, the name dialplan.rb
|
72
|
+
# is actually specified in .ahnrc. This file can actually be just a filename, a filename with a glob (.e.g "*.rb"), an
|
73
|
+
# Array of filenames or even an Array of globs.
|
74
|
+
#
|
75
|
+
# @param [String,Array] String segments which convey the nesting of Hash keys through .ahnrc
|
76
|
+
# @raise [RuntimeError] If ahnrc has not been set yet with #ahnrc=()
|
77
|
+
# @raise [NameError] If the path through the ahnrc is invalid
|
78
|
+
#
|
79
|
+
def files_from_setting(*path_through_config)
|
80
|
+
raise RuntimeError, "No ahnrc has been set yet!" unless @ahnrc
|
81
|
+
queried_nested_setting = path_through_config.flatten.inject(@ahnrc) do |hash,key_name|
|
82
|
+
if hash.kind_of?(Hash) && hash.has_key?(key_name)
|
83
|
+
hash[key_name]
|
84
|
+
else
|
85
|
+
raise NameError, "Paths #{path_through_config.inspect} not found in .ahnrc!"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
raise NameError, "Paths #{path_through_config.inspect} not found in .ahnrc!" unless queried_nested_setting
|
89
|
+
queried_nested_setting = Array queried_nested_setting
|
90
|
+
queried_nested_setting.map { |filename| files_from_glob(filename) }.flatten.uniq
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def files_from_glob(glob)
|
96
|
+
Dir.glob "#{AHN_ROOT}/#{glob}"
|
97
|
+
end
|
98
|
+
|
99
|
+
class AbstractConfiguration
|
100
|
+
extend ConfigurationEntryPoint
|
101
|
+
|
102
|
+
class << self
|
103
|
+
private
|
104
|
+
def abstract_method!
|
105
|
+
raise "Must be implemented in subclasses"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def initialize(overrides = {})
|
110
|
+
overrides.each_pair do |attribute, value|
|
111
|
+
send("#{attribute}=", value)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Abstract superclass for AsteriskConfiguration and FreeSwitchConfiguration.
|
117
|
+
class TelephonyPlatformConfiguration < AbstractConfiguration
|
118
|
+
attr_accessor :listening_port
|
119
|
+
attr_accessor :listening_host
|
120
|
+
|
121
|
+
class << self
|
122
|
+
def default_listening_port
|
123
|
+
abstract_method!
|
124
|
+
end
|
125
|
+
|
126
|
+
def default_listening_host
|
127
|
+
'0.0.0.0'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def initialize(overrides = {})
|
132
|
+
@listening_port = self.class.default_listening_port
|
133
|
+
@listening_host = self.class.default_listening_host
|
134
|
+
super
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class AsteriskConfiguration < TelephonyPlatformConfiguration
|
139
|
+
class << self
|
140
|
+
attr_accessor :speech_engine
|
141
|
+
|
142
|
+
def default_listening_port
|
143
|
+
4573
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class AMIConfiguration < AbstractConfiguration
|
148
|
+
attr_accessor :port, :username, :password, :events, :host
|
149
|
+
|
150
|
+
class << self
|
151
|
+
def default_port
|
152
|
+
5038
|
153
|
+
end
|
154
|
+
|
155
|
+
def default_events
|
156
|
+
false
|
157
|
+
end
|
158
|
+
|
159
|
+
def default_host
|
160
|
+
'localhost'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def initialize(overrides = {})
|
165
|
+
self.host = self.class.default_host
|
166
|
+
self.port = self.class.default_port
|
167
|
+
self.events = self.class.default_events
|
168
|
+
super
|
169
|
+
end
|
170
|
+
end
|
171
|
+
add_configuration_for :AMI
|
172
|
+
end
|
173
|
+
add_configuration_for :Asterisk
|
174
|
+
|
175
|
+
class FreeswitchConfiguration < TelephonyPlatformConfiguration
|
176
|
+
class << self
|
177
|
+
def default_listening_port
|
178
|
+
4572
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
add_configuration_for :Freeswitch
|
183
|
+
|
184
|
+
class DatabaseConfiguration < AbstractConfiguration
|
185
|
+
attr_accessor :connection_options, :orm
|
186
|
+
def initialize(options)
|
187
|
+
@orm = options.delete(:orm) || :active_record # TODO: ORM is a misnomer
|
188
|
+
@connection_options = options
|
189
|
+
end
|
190
|
+
end
|
191
|
+
add_configuration_for :Database
|
192
|
+
|
193
|
+
class DrbConfiguration < AbstractConfiguration
|
194
|
+
attr_accessor :port
|
195
|
+
attr_accessor :host
|
196
|
+
attr_accessor :acl
|
197
|
+
|
198
|
+
# ACL = Access Control List
|
199
|
+
|
200
|
+
class << self
|
201
|
+
def default_port
|
202
|
+
9050
|
203
|
+
end
|
204
|
+
|
205
|
+
def default_host
|
206
|
+
'localhost'
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def initialize(overrides = {})
|
211
|
+
self.port = overrides[:port] || self.class.default_port
|
212
|
+
self.host = overrides[:host] || self.class.default_host
|
213
|
+
self.acl = overrides[:raw_acl]
|
214
|
+
|
215
|
+
unless acl
|
216
|
+
self.acl = []
|
217
|
+
overrides[ :deny].to_a.each { |ip| acl << 'deny' << ip }
|
218
|
+
overrides[:allow].to_a.each { |ip| acl << 'allow' << ip }
|
219
|
+
acl.concat %w[allow 127.0.0.1] if acl.empty?
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
add_configuration_for :Drb
|
224
|
+
|
225
|
+
class RailsConfiguration < AbstractConfiguration
|
226
|
+
|
227
|
+
SUPPORTED_RAILS_ENVIRONMENTS = [:development, :test, :production]
|
228
|
+
|
229
|
+
attr_accessor :rails_root, :environment
|
230
|
+
def initialize(options)
|
231
|
+
path_to_rails, environment = check_options options
|
232
|
+
@rails_root = File.expand_path(path_to_rails)
|
233
|
+
@environment = environment.to_sym
|
234
|
+
raise ArgumentError, "Unrecognized environment type #@environment. Supported: " +
|
235
|
+
SUPPORTED_RAILS_ENVIRONMENTS.to_sentence unless SUPPORTED_RAILS_ENVIRONMENTS.include?(@environment)
|
236
|
+
end
|
237
|
+
|
238
|
+
private
|
239
|
+
|
240
|
+
def check_options(options)
|
241
|
+
options = options.clone
|
242
|
+
path = options.delete :path
|
243
|
+
env = options.delete :env
|
244
|
+
raise ArgumentError, "Unrecognied argument(s) #{options.keys.to_sentence} in Rails initializer!" unless options.size.zero?
|
245
|
+
raise ArgumentError, "Must supply an :env argument to the Rails initializer!" unless env
|
246
|
+
raise ArgumentError, "Must supply an :path argument to the Rails initializer!" unless path
|
247
|
+
[path, env]
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
add_configuration_for :Rails
|
252
|
+
|
253
|
+
end
|
254
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# TODO: Have all of the initializer modules required and then traverse the subclasses, asking them if they're enabled. If they are enabled, then they should do their initialization stuff. Is this really necessary to develop this entirely new system when the components system exists?
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
class Initializer
|
5
|
+
|
6
|
+
class DatabaseInitializer
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def start
|
11
|
+
require_dependencies
|
12
|
+
require_models
|
13
|
+
@@config = Adhearsion::AHN_CONFIG.database
|
14
|
+
ActiveRecord::Base.allow_concurrency = true
|
15
|
+
establish_connection
|
16
|
+
create_call_hook_for_connection_cleanup
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
ActiveRecord::Base.remove_connection
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def create_call_hook_for_connection_cleanup
|
26
|
+
Events.register_callback([:asterisk, :before_call]) do
|
27
|
+
ActiveRecord::Base.verify_active_connections!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def require_dependencies
|
32
|
+
require 'active_record'
|
33
|
+
end
|
34
|
+
|
35
|
+
def require_models
|
36
|
+
AHN_CONFIG.files_from_setting("paths", "models").each do |model|
|
37
|
+
load model
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def establish_connection
|
42
|
+
ActiveRecord::Base.establish_connection @@config.connection_options
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'drb/acl'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Adhearsion
|
6
|
+
class Initializer
|
7
|
+
|
8
|
+
class DrbInitializer
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def start
|
13
|
+
config = Adhearsion::AHN_CONFIG.drb
|
14
|
+
DRb.install_acl ACL.new(config.acl) if config.acl
|
15
|
+
|
16
|
+
drb_door = Object.new
|
17
|
+
Components.component_manager.extend_object_with(drb_door, :rpc)
|
18
|
+
|
19
|
+
DRb.start_service "druby://#{config.host}:#{config.port}", drb_door
|
20
|
+
|
21
|
+
ahn_log "Starting DRb on #{config.host}:#{config.port}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
DRb.stop_service
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# THIS FREESWITCH LIBRARY HASN'T BEEN INTEGRATED INTO THE REFACTORED 0.8.0 YET.
|
2
|
+
# WHAT EXISTS HERE IS OLD, MUST BE CHANGED, AND DOES NOT EVEN GET LOADED AT THE MOMENT.
|
3
|
+
require "adhearsion/voip/freeswitch/oes_server"
|
4
|
+
require "adhearsion/voip/freeswitch/event_handler"
|
5
|
+
require "adhearsion/voip/freeswitch/inbound_connection_manager"
|
6
|
+
require "adhearsion/voip/dsl/dialplan/control_passing_exception"
|
7
|
+
|
8
|
+
oes_enabled = Adhearsion::Configuration.core.voip.freeswitch.oes && Adhearsion::Configuration.core.voip.freeswitch.oes.port
|
9
|
+
|
10
|
+
|
11
|
+
if oes_enabled
|
12
|
+
|
13
|
+
port = Adhearsion::Configuration.core.voip.freeswitch.oes.port
|
14
|
+
host = Adhearsion::Configuration.core.voip.freeswitch.oes.host
|
15
|
+
|
16
|
+
server = Adhearsion::VoIP::FreeSwitch::OesServer.new port, host
|
17
|
+
|
18
|
+
Events.register_callback(:after_initialized) { server.start }
|
19
|
+
Events.register_callback(:shutdown) { server.stop }
|
20
|
+
IMPORTANT_THREADS << server
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'adhearsion/voip/asterisk'
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
class Initializer
|
5
|
+
class RailsInitializer
|
6
|
+
|
7
|
+
cattr_accessor :rails_root, :config, :environment
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def start
|
11
|
+
ahn_config = Adhearsion::AHN_CONFIG
|
12
|
+
self.config = ahn_config.rails
|
13
|
+
self.rails_root = config.rails_root
|
14
|
+
self.environment = config.environment
|
15
|
+
raise "You cannot enable the database and Rails at the same time!" if ahn_config.database_enabled?
|
16
|
+
raise "Error loading Rails environment in #{rails_root.inspect}. " +
|
17
|
+
"It's not a directory!" unless File.directory?(rails_root)
|
18
|
+
load_rails
|
19
|
+
if defined? ActiveRecord
|
20
|
+
ActiveRecord::Base.allow_concurrency = true
|
21
|
+
Events.register_callback([:asterisk, :before_call]) do
|
22
|
+
ActiveRecord::Base.verify_active_connections!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def load_rails
|
30
|
+
environment_file = File.expand_path(rails_root + "/config/environment.rb")
|
31
|
+
raise "There is no config/environment.rb file!" unless File.exists?(environment_file)
|
32
|
+
ENV['RAILS_ENV'] = environment.to_s
|
33
|
+
require environment_file
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|