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.
- data/CHANGELOG +3 -0
- data/LICENSE +456 -0
- data/Manifest.txt +149 -0
- data/README.txt +6 -0
- data/Rakefile +48 -0
- data/ahn_generators/component/USAGE +5 -0
- data/ahn_generators/component/component_generator.rb +57 -0
- data/ahn_generators/component/templates/configuration.rb +0 -0
- data/ahn_generators/component/templates/lib/lib.rb.erb +3 -0
- data/ahn_generators/component/templates/test/test.rb.erb +12 -0
- data/ahn_generators/component/templates/test/test_helper.rb +14 -0
- data/app_generators/ahn/USAGE +5 -0
- data/app_generators/ahn/ahn_generator.rb +76 -0
- data/app_generators/ahn/templates/.ahnrc +12 -0
- data/app_generators/ahn/templates/README +8 -0
- data/app_generators/ahn/templates/Rakefile +3 -0
- data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
- data/app_generators/ahn/templates/components/simon_game/lib/simon_game.rb +61 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +14 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +31 -0
- data/app_generators/ahn/templates/config/startup.rb +53 -0
- data/app_generators/ahn/templates/dialplan.rb +4 -0
- data/bin/ahn +28 -0
- data/bin/ahnctl +68 -0
- data/bin/jahn +32 -0
- data/lib/adhearsion/blank_slate.rb +5 -0
- data/lib/adhearsion/cli.rb +106 -0
- data/lib/adhearsion/component_manager.rb +277 -0
- data/lib/adhearsion/core_extensions/all.rb +9 -0
- data/lib/adhearsion/core_extensions/array.rb +0 -0
- data/lib/adhearsion/core_extensions/custom_daemonizer.rb +45 -0
- data/lib/adhearsion/core_extensions/global.rb +1 -0
- data/lib/adhearsion/core_extensions/guid.rb +5 -0
- data/lib/adhearsion/core_extensions/hash.rb +0 -0
- data/lib/adhearsion/core_extensions/metaprogramming.rb +17 -0
- data/lib/adhearsion/core_extensions/numeric.rb +4 -0
- data/lib/adhearsion/core_extensions/proc.rb +0 -0
- data/lib/adhearsion/core_extensions/pseudo_uuid.rb +11 -0
- data/lib/adhearsion/core_extensions/publishable.rb +73 -0
- data/lib/adhearsion/core_extensions/relationship_properties.rb +40 -0
- data/lib/adhearsion/core_extensions/string.rb +26 -0
- data/lib/adhearsion/core_extensions/thread.rb +13 -0
- data/lib/adhearsion/core_extensions/thread_safety.rb +7 -0
- 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 +9 -0
- data/lib/adhearsion/distributed/gateways/soap_gateway.rb +9 -0
- data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +9 -0
- data/lib/adhearsion/distributed/peer_finder.rb +0 -0
- data/lib/adhearsion/distributed/remote_cli.rb +0 -0
- data/lib/adhearsion/hooks.rb +57 -0
- data/lib/adhearsion/host_definitions.rb +63 -0
- data/lib/adhearsion/initializer/asterisk.rb +59 -0
- data/lib/adhearsion/initializer/configuration.rb +202 -0
- data/lib/adhearsion/initializer/database.rb +92 -0
- data/lib/adhearsion/initializer/drb.rb +25 -0
- data/lib/adhearsion/initializer/freeswitch.rb +22 -0
- data/lib/adhearsion/initializer/paths.rb +55 -0
- data/lib/adhearsion/initializer/rails.rb +40 -0
- data/lib/adhearsion/initializer.rb +217 -0
- data/lib/adhearsion/logging.rb +92 -0
- data/lib/adhearsion/services/scheduler.rb +5 -0
- data/lib/adhearsion/tasks/database.rb +5 -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 +15 -0
- data/lib/adhearsion/version.rb +9 -0
- data/lib/adhearsion/voip/asterisk/agi_server.rb +78 -0
- data/lib/adhearsion/voip/asterisk/ami/actions.rb +238 -0
- data/lib/adhearsion/voip/asterisk/ami/machine.rb +871 -0
- data/lib/adhearsion/voip/asterisk/ami/machine.rl +109 -0
- data/lib/adhearsion/voip/asterisk/ami/parser.rb +262 -0
- data/lib/adhearsion/voip/asterisk/ami.rb +147 -0
- data/lib/adhearsion/voip/asterisk/commands.rb +1186 -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/special_dial_plan_managers.rb +80 -0
- data/lib/adhearsion/voip/asterisk.rb +4 -0
- data/lib/adhearsion/voip/call.rb +402 -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 +205 -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 +75 -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 +31 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/fixtures/dialplan.rb +3 -0
- data/spec/initializer/test_configuration.rb +267 -0
- data/spec/initializer/test_loading.rb +162 -0
- data/spec/initializer/test_paths.rb +43 -0
- data/spec/silence.rb +10 -0
- data/spec/test_ahn_command.rb +149 -0
- data/spec/test_code_quality.rb +87 -0
- data/spec/test_component_manager.rb +97 -0
- data/spec/test_constants.rb +8 -0
- data/spec/test_drb.rb +104 -0
- data/spec/test_helper.rb +94 -0
- data/spec/test_hooks.rb +37 -0
- data/spec/test_host_definitions.rb +79 -0
- data/spec/test_initialization.rb +105 -0
- data/spec/test_logging.rb +80 -0
- data/spec/test_relationship_properties.rb +54 -0
- data/spec/voip/asterisk/ami_response_definitions.rb +23 -0
- data/spec/voip/asterisk/config_file_generators/test_agents.rb +253 -0
- data/spec/voip/asterisk/config_file_generators/test_queues.rb +325 -0
- data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +306 -0
- data/spec/voip/asterisk/menu_command/test_calculated_match.rb +111 -0
- data/spec/voip/asterisk/menu_command/test_matchers.rb +98 -0
- data/spec/voip/asterisk/mock_ami_server.rb +176 -0
- data/spec/voip/asterisk/test_agi_server.rb +453 -0
- data/spec/voip/asterisk/test_ami.rb +227 -0
- data/spec/voip/asterisk/test_commands.rb +2006 -0
- data/spec/voip/asterisk/test_config_manager.rb +129 -0
- data/spec/voip/dsl/dispatcher_spec_helper.rb +45 -0
- data/spec/voip/dsl/test_dialing_dsl.rb +268 -0
- data/spec/voip/dsl/test_dispatcher.rb +82 -0
- data/spec/voip/dsl/test_parser.rb +87 -0
- data/spec/voip/freeswitch/test_basic_connection_manager.rb +39 -0
- data/spec/voip/freeswitch/test_inbound_connection_manager.rb +39 -0
- data/spec/voip/freeswitch/test_oes_server.rb +9 -0
- data/spec/voip/test_call_routing.rb +127 -0
- data/spec/voip/test_dialplan_manager.rb +372 -0
- data/spec/voip/test_numerical_string.rb +48 -0
- data/spec/voip/test_phone_number.rb +36 -0
- data/test/test_ahn_generator.rb +59 -0
- data/test/test_component_generator.rb +52 -0
- data/test/test_generator_helper.rb +20 -0
- metadata +254 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'calculated_match')
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
module VoIP
|
5
|
+
class MatchCalculator
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def build_with_pattern(pattern, match_payload, &block)
|
10
|
+
class_for_pattern_type(pattern.class.name).new(pattern, match_payload, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def inherited(klass)
|
14
|
+
subclasses << klass
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def class_for_pattern_type(pattern_type)
|
20
|
+
sought_class_name = "Adhearsion::VoIP::#{pattern_type.camelize}MatchCalculator"
|
21
|
+
subclasses.find { |klass| klass.name == sought_class_name }
|
22
|
+
end
|
23
|
+
|
24
|
+
def subclasses
|
25
|
+
@@subclasses ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :pattern, :match_payload
|
31
|
+
def initialize(pattern, match_payload)
|
32
|
+
@pattern, @match_payload = pattern, match_payload
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def new_calculated_match(options)
|
38
|
+
CalculatedMatch.new({:pattern => pattern, :match_payload => match_payload}.merge(options))
|
39
|
+
end
|
40
|
+
|
41
|
+
def coerce_to_numeric(victim)
|
42
|
+
victim.kind_of?(Numeric) ? victim : (victim.to_s =~ /^\d+$/ ? victim.to_s.to_i : nil )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class RangeMatchCalculator < MatchCalculator
|
47
|
+
|
48
|
+
def initialize(pattern, match_payload)
|
49
|
+
raise unless pattern.first.kind_of?(Numeric) && pattern.last.kind_of?(Numeric)
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def match(query)
|
54
|
+
numerical_query = coerce_to_numeric query
|
55
|
+
if numerical_query
|
56
|
+
exact_match = pattern.include?(numerical_query) ? query : nil
|
57
|
+
potential_matches = numbers_in_range_like numerical_query
|
58
|
+
potential_matches.reject! { |m| m.to_s == exact_match.to_s } if exact_match
|
59
|
+
|
60
|
+
new_calculated_match :query => query, :exact_matches => exact_match,
|
61
|
+
:potential_matches => potential_matches
|
62
|
+
else
|
63
|
+
CalculatedMatch.failed_match!(pattern, query, match_payload)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Returns all numbers in the range (@pattern) that +begin with+ the number given
|
70
|
+
# as the first argument.
|
71
|
+
#
|
72
|
+
# NOTE! If you're having trouble reading what this method is actually doing, it's
|
73
|
+
# effectively a much more efficient version of this:
|
74
|
+
#
|
75
|
+
# pattern.to_a.select { |x| x.to_s.starts_with? num.to_s }.flatten
|
76
|
+
#
|
77
|
+
# Huge thanks to Dave Troy (http://davetroy.blogspot.com) for this awesomely
|
78
|
+
# efficient code!
|
79
|
+
def numbers_in_range_like(num)
|
80
|
+
return (pattern === 0 ? [0] : nil) if num == 0
|
81
|
+
raise ArgumentError unless num.kind_of?(Numeric)
|
82
|
+
returning Array.new do |matches|
|
83
|
+
first, last = pattern.first, pattern.last
|
84
|
+
power = 0
|
85
|
+
while num < last
|
86
|
+
ones_count = 10**power - 1
|
87
|
+
matches.concat((([num, first].max)..[(num+ones_count), last].min).to_a)
|
88
|
+
num *= 10
|
89
|
+
power += 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class FixnumMatchCalculator < MatchCalculator
|
96
|
+
def match(query)
|
97
|
+
numeric_query = coerce_to_numeric query
|
98
|
+
exact_match, potential_match = nil
|
99
|
+
if pattern == numeric_query
|
100
|
+
exact_match = pattern
|
101
|
+
elsif pattern.to_s.starts_with? query.to_s
|
102
|
+
potential_match = pattern
|
103
|
+
end
|
104
|
+
new_calculated_match :query => query, :exact_matches => exact_match, :potential_matches => potential_match
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class StringMatchCalculator < MatchCalculator
|
109
|
+
def match(query)
|
110
|
+
args = { :query => query, :exact_matches => nil,
|
111
|
+
:potential_matches => nil }
|
112
|
+
|
113
|
+
if pattern == query.to_s
|
114
|
+
args[:exact_matches] = [pattern]
|
115
|
+
elsif pattern.starts_with? query.to_s
|
116
|
+
args[:potential_matches] = [pattern]
|
117
|
+
end
|
118
|
+
|
119
|
+
new_calculated_match args
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'matchers.rb')
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
module VoIP
|
5
|
+
class MenuBuilder
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@patterns = []
|
9
|
+
@menu_callbacks = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(match_payload, *patterns, &block)
|
13
|
+
name_string = match_payload.to_s
|
14
|
+
if patterns.any?
|
15
|
+
patterns.each do |pattern|
|
16
|
+
@patterns << MatchCalculator.build_with_pattern(pattern, match_payload)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
raise ArgumentError, "You cannot call this method without patterns!"
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def weighted_match_calculators
|
25
|
+
@patterns
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute_hook_for(symbol, input)
|
29
|
+
callback = @menu_callbacks[symbol]
|
30
|
+
callback.call input if callback
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_invalid(&block)
|
34
|
+
raise LocalJumpError, "Must supply a block!" unless block_given?
|
35
|
+
@menu_callbacks[:invalid] = block
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_premature_timeout(&block)
|
39
|
+
raise LocalJumpError, "Must supply a block!" unless block_given?
|
40
|
+
@menu_callbacks[:premature_timeout] = block
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_failure(&block)
|
44
|
+
raise LocalJumpError, "Must supply a block!" unless block_given?
|
45
|
+
@menu_callbacks[:failure] = block
|
46
|
+
end
|
47
|
+
|
48
|
+
def calculate_matches_for(result)
|
49
|
+
returning CalculatedMatchCollection.new do |collection|
|
50
|
+
weighted_match_calculators.each do |pattern|
|
51
|
+
collection << pattern.match(result)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'adhearsion/voip/menu_state_machine/menu_builder'
|
2
|
+
module Adhearsion
|
3
|
+
module VoIP
|
4
|
+
class Menu
|
5
|
+
|
6
|
+
DEFAULT_MAX_NUMBER_OF_TRIES = 1
|
7
|
+
DEFAULT_TIMEOUT = 5 # seconds
|
8
|
+
|
9
|
+
relationships :menu_builder => MenuBuilder
|
10
|
+
|
11
|
+
attr_reader :builder, :timeout, :tries_count, :max_number_of_tries
|
12
|
+
def initialize(options={}, &block)
|
13
|
+
@tries_count = 0 # Counts the number of tries the menu's been executed
|
14
|
+
|
15
|
+
@timeout = options[:timeout] || DEFAULT_TIMEOUT
|
16
|
+
@max_number_of_tries = options[:tries] || DEFAULT_MAX_NUMBER_OF_TRIES
|
17
|
+
|
18
|
+
@builder = menu_builder.new
|
19
|
+
yield @builder
|
20
|
+
|
21
|
+
initialize_digit_buffer
|
22
|
+
end
|
23
|
+
|
24
|
+
def <<(other)
|
25
|
+
digit_buffer << other
|
26
|
+
end
|
27
|
+
|
28
|
+
def digit_buffer
|
29
|
+
@digit_buffer
|
30
|
+
end
|
31
|
+
|
32
|
+
def digit_buffer_string
|
33
|
+
digit_buffer.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def digit_buffer_empty?
|
37
|
+
digit_buffer.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def continue
|
41
|
+
raise MenuGetAnotherDigitOrTimeout if digit_buffer_empty?
|
42
|
+
|
43
|
+
calculated_matches = builder.calculate_matches_for digit_buffer_string
|
44
|
+
|
45
|
+
if calculated_matches.exact_match_count >= 1
|
46
|
+
first_exact_match = calculated_matches.exact_matches.first
|
47
|
+
if calculated_matches.potential_match_count.zero?
|
48
|
+
# Match found with no extenuating ambiguities! Go with the first exact match
|
49
|
+
menu_result_found! first_exact_match.match_payload, digit_buffer_string
|
50
|
+
else
|
51
|
+
get_another_digit_or_finish!(first_exact_match.match_payload, first_exact_match.query)
|
52
|
+
end
|
53
|
+
elsif calculated_matches.potential_match_count >= 1
|
54
|
+
get_another_digit_or_timeout!
|
55
|
+
else
|
56
|
+
invalid!
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def should_continue?
|
61
|
+
tries_count < max_number_of_tries
|
62
|
+
end
|
63
|
+
|
64
|
+
def restart!
|
65
|
+
@tries_count += 1
|
66
|
+
digit_buffer.clear!
|
67
|
+
end
|
68
|
+
|
69
|
+
def execute_invalid_hook
|
70
|
+
builder.execute_hook_for(:invalid, digit_buffer_string)
|
71
|
+
end
|
72
|
+
|
73
|
+
def execute_timeout_hook
|
74
|
+
builder.execute_hook_for(:premature_timeout, digit_buffer_string)
|
75
|
+
end
|
76
|
+
|
77
|
+
def execute_failure_hook
|
78
|
+
builder.execute_hook_for(:failure, digit_buffer_string)
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
# If you're using a more complex class in subclasses, you may want to override this method in addition to the
|
84
|
+
# digit_buffer, digit_buffer_empty, and digit_buffer_string methods
|
85
|
+
def initialize_digit_buffer
|
86
|
+
@digit_buffer = ClearableStringBuffer.new
|
87
|
+
end
|
88
|
+
|
89
|
+
def invalid!
|
90
|
+
raise MenuResultInvalid
|
91
|
+
end
|
92
|
+
|
93
|
+
def menu_result_found!(match_payload, new_extension)
|
94
|
+
raise MenuResultFound.new(match_payload, new_extension)
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_another_digit_or_finish!(match_payload, new_extension)
|
98
|
+
raise MenuGetAnotherDigitOrFinish.new(match_payload, new_extension)
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_another_digit_or_timeout!
|
102
|
+
raise MenuGetAnotherDigitOrTimeout
|
103
|
+
end
|
104
|
+
|
105
|
+
# The superclass from which all message-like exceptions decend. It should never
|
106
|
+
# be instantiated directly.
|
107
|
+
class MenuResult < Exception; end
|
108
|
+
|
109
|
+
# Raised when the user's input matches
|
110
|
+
class MenuResultFound < MenuResult
|
111
|
+
attr_reader :match_payload, :new_extension
|
112
|
+
def initialize(match_payload, new_extension)
|
113
|
+
super()
|
114
|
+
@match_payload = match_payload
|
115
|
+
@new_extension = new_extension
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
module MenuGetAnotherDigit; end
|
120
|
+
|
121
|
+
class MenuGetAnotherDigitOrFinish < MenuResultFound
|
122
|
+
include MenuGetAnotherDigit
|
123
|
+
end
|
124
|
+
|
125
|
+
class MenuGetAnotherDigitOrTimeout < MenuResult
|
126
|
+
include MenuGetAnotherDigit
|
127
|
+
end
|
128
|
+
|
129
|
+
class MenuResultFound < MenuResult; end
|
130
|
+
|
131
|
+
# Raised when the user's input matches no patterns
|
132
|
+
class MenuResultInvalid < MenuResult; end
|
133
|
+
|
134
|
+
# For our default purposes, we need the digit_buffer to behave much like a normal String except that it should
|
135
|
+
# handle its own resetting (clearing).
|
136
|
+
class ClearableStringBuffer < String
|
137
|
+
def clear!
|
138
|
+
replace ""
|
139
|
+
end
|
140
|
+
|
141
|
+
def <<(other)
|
142
|
+
super other.to_s
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/lib/adhearsion.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Check the Ruby version
|
2
|
+
STDERR.puts "WARNING: You are running Adhearsion in an unsupported
|
3
|
+
version of Ruby (Ruby #{RUBY_VERSION} #{RUBY_RELEASE_DATE})!
|
4
|
+
Please upgrade to at least Ruby v1.8.5." if RUBY_VERSION < "1.8.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
|
+
$: << File.expand_path(File.dirname(__FILE__))
|
13
|
+
|
14
|
+
require 'rubygems'
|
15
|
+
require 'adhearsion/version'
|
16
|
+
require 'adhearsion/voip/call'
|
17
|
+
require 'adhearsion/voip/dial_plan'
|
18
|
+
require 'adhearsion/voip/asterisk/special_dial_plan_managers'
|
19
|
+
require 'adhearsion/core_extensions/all'
|
20
|
+
require 'adhearsion/blank_slate'
|
21
|
+
require 'adhearsion/hooks'
|
22
|
+
require 'adhearsion/logging'
|
23
|
+
require 'adhearsion/initializer/configuration'
|
24
|
+
require 'adhearsion/initializer'
|
25
|
+
require 'adhearsion/initializer/paths'
|
26
|
+
require 'adhearsion/voip/dsl/numerical_string'
|
27
|
+
require 'adhearsion/voip/dsl/dialplan/parser'
|
28
|
+
require 'adhearsion/voip/commands'
|
29
|
+
require 'adhearsion/voip/asterisk/commands'
|
30
|
+
require 'adhearsion/voip/dsl/dialing_dsl'
|
31
|
+
require 'adhearsion/voip/call_routing'
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.join(File.dirname(__FILE__), '..')
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, "test_unit"]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.join(File.dirname(__FILE__), '..')
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, "test_unit"]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,267 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../test_helper"
|
2
|
+
|
3
|
+
context "Configuration defaults" do
|
4
|
+
include ConfigurationTestHelper
|
5
|
+
attr_reader :config
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@config = default_config
|
9
|
+
end
|
10
|
+
|
11
|
+
test "incoming calls are answered by default" do
|
12
|
+
assert config.automatically_answer_incoming_calls
|
13
|
+
end
|
14
|
+
|
15
|
+
test "calls are ended when hung up" do
|
16
|
+
assert config.end_call_on_hangup
|
17
|
+
end
|
18
|
+
|
19
|
+
test "if an error occurs, a call is hungup" do
|
20
|
+
assert config.end_call_on_error
|
21
|
+
end
|
22
|
+
|
23
|
+
test "asterisk is enabled by default" do
|
24
|
+
assert config.asterisk_enabled?
|
25
|
+
end
|
26
|
+
|
27
|
+
test "default asterisk configuration is available" do
|
28
|
+
assert_kind_of Adhearsion::Configuration::AsteriskConfiguration, config.asterisk
|
29
|
+
end
|
30
|
+
|
31
|
+
test "database access is NOT enabled by default" do
|
32
|
+
assert !config.database_enabled?
|
33
|
+
end
|
34
|
+
|
35
|
+
test "freeswith is NOT enabled by default" do
|
36
|
+
assert !config.freeswitch_enabled?
|
37
|
+
end
|
38
|
+
|
39
|
+
test "AMI is NOT enabled by default" do
|
40
|
+
assert !config.asterisk.ami_enabled?
|
41
|
+
end
|
42
|
+
|
43
|
+
test "Drb is NOT enabled by default" do
|
44
|
+
assert !config.drb_enabled?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "Asterisk AGI configuration defaults" do
|
49
|
+
attr_reader :config
|
50
|
+
|
51
|
+
setup do
|
52
|
+
@config = Adhearsion::Configuration::AsteriskConfiguration.new
|
53
|
+
end
|
54
|
+
|
55
|
+
test "asterisk configuration sets default listening port" do
|
56
|
+
config.listening_port.should.equal Adhearsion::Configuration::AsteriskConfiguration.default_listening_port
|
57
|
+
end
|
58
|
+
|
59
|
+
test "asterisk configuration sets default listening host" do
|
60
|
+
config.listening_host.should.equal Adhearsion::Configuration::AsteriskConfiguration.default_listening_host
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'Logging configuration' do
|
65
|
+
|
66
|
+
attr_reader :config
|
67
|
+
before :each do
|
68
|
+
@config = Adhearsion::Configuration.new
|
69
|
+
end
|
70
|
+
|
71
|
+
after :each do
|
72
|
+
Adhearsion::Logging.logging_level = :fatal
|
73
|
+
end
|
74
|
+
|
75
|
+
test 'the logging level should translate from symbols into Log4r constants' do
|
76
|
+
Adhearsion::Logging.logging_level.should.not.equal Log4r::WARN
|
77
|
+
config.logging :level => :warn
|
78
|
+
Adhearsion::Logging.logging_level.should.equal Log4r::WARN
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
context "AMI configuration defaults" do
|
84
|
+
attr_reader :config
|
85
|
+
|
86
|
+
setup do
|
87
|
+
@config = Adhearsion::Configuration::AsteriskConfiguration::AMIConfiguration.new
|
88
|
+
end
|
89
|
+
|
90
|
+
test "ami configuration sets default port" do
|
91
|
+
config.port.should.equal Adhearsion::Configuration::AsteriskConfiguration::AMIConfiguration.default_port
|
92
|
+
end
|
93
|
+
|
94
|
+
test "ami allows you to configure a username and a password, both of which default to nil" do
|
95
|
+
config.username.should.be.nil
|
96
|
+
config.password.should.be.nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "Rails configuration defaults" do
|
101
|
+
test "should require the path to the Rails app in the constructor" do
|
102
|
+
config = Adhearsion::Configuration::RailsConfiguration.new :path => "path here doesn't matter right now", :env => :development
|
103
|
+
config.rails_root.should.not.be.nil
|
104
|
+
end
|
105
|
+
|
106
|
+
test "should expand_path() the first constructor parameter" do
|
107
|
+
rails_root = "gui"
|
108
|
+
flexmock(File).should_receive(:expand_path).once.with(rails_root)
|
109
|
+
config = Adhearsion::Configuration::RailsConfiguration.new :path => rails_root, :env => :development
|
110
|
+
end
|
111
|
+
|
112
|
+
test "should ensure that the environment provided is one supported by Rails" do
|
113
|
+
the_following_code {
|
114
|
+
Adhearsion::Configuration::RailsConfiguration.new :path => "doesnt matter", :env => :this_is_not_a_rails_env
|
115
|
+
}.should.raise ArgumentError
|
116
|
+
|
117
|
+
the_following_code {
|
118
|
+
Adhearsion::Configuration::RailsConfiguration.new :path => "doesnt matter", :env => :development
|
119
|
+
Adhearsion::Configuration::RailsConfiguration.new :path => "doesnt matter", :env => :production
|
120
|
+
Adhearsion::Configuration::RailsConfiguration.new :path => "doesnt matter", :env => :test
|
121
|
+
}.should.not.raise ArgumentError
|
122
|
+
end
|
123
|
+
|
124
|
+
test "should convert the environment into a Symbol" do
|
125
|
+
Adhearsion::Configuration::RailsConfiguration::SUPPORTED_RAILS_ENVIRONMENTS.should.not.be.empty
|
126
|
+
Adhearsion::Configuration::RailsConfiguration::SUPPORTED_RAILS_ENVIRONMENTS.each do |env|
|
127
|
+
config = Adhearsion::Configuration::RailsConfiguration.new :path => "doesnt matter", :env => env.to_s
|
128
|
+
config.environment.should.equal env
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "Database configuration defaults" do
|
134
|
+
|
135
|
+
setup do
|
136
|
+
Adhearsion.send(:remove_const, :AHN_CONFIG) if Adhearsion.const_defined?(:AHN_CONFIG)
|
137
|
+
Adhearsion::Configuration.configure {}
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should store the constructor's argument in connection_options()" do
|
141
|
+
sample_options = { :adapter => "sqlite3", :dbfile => "foo.sqlite3" }
|
142
|
+
config = Adhearsion::Configuration::DatabaseConfiguration.new(sample_options)
|
143
|
+
config.connection_options.should.equal sample_options
|
144
|
+
end
|
145
|
+
it "should remove the :orm key from the connection options" do
|
146
|
+
sample_options = { :orm => :active_record, :adapter => "mysql", :host => "::1",
|
147
|
+
:user => "a", :pass => "b", :database => "ahn" }
|
148
|
+
config = Adhearsion::Configuration::DatabaseConfiguration.new(sample_options.clone)
|
149
|
+
config.orm.should.equal sample_options.delete(:orm)
|
150
|
+
config.connection_options.should.equal sample_options
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "Freeswitch configuration defaults" do
|
155
|
+
attr_reader :config
|
156
|
+
|
157
|
+
setup do
|
158
|
+
@config = Adhearsion::Configuration::FreeswitchConfiguration.new
|
159
|
+
end
|
160
|
+
|
161
|
+
test "freeswitch configuration sets default listening port" do
|
162
|
+
config.listening_port.should.equal Adhearsion::Configuration::FreeswitchConfiguration.default_listening_port
|
163
|
+
end
|
164
|
+
|
165
|
+
test "freeswitch configuration sets default listening host" do
|
166
|
+
config.listening_host.should.equal Adhearsion::Configuration::FreeswitchConfiguration.default_listening_host
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "Configuration scenarios" do
|
171
|
+
include ConfigurationTestHelper
|
172
|
+
|
173
|
+
test "enabling AMI using all its defaults" do
|
174
|
+
config = enable_ami
|
175
|
+
|
176
|
+
assert config.asterisk.ami_enabled?
|
177
|
+
config.asterisk.ami.should.be.kind_of Adhearsion::Configuration::AsteriskConfiguration::AMIConfiguration
|
178
|
+
end
|
179
|
+
|
180
|
+
test "enabling AMI with custom configuration overrides the defaults" do
|
181
|
+
overridden_port = 911
|
182
|
+
config = enable_ami :port => overridden_port
|
183
|
+
config.asterisk.ami.port.should.equal overridden_port
|
184
|
+
end
|
185
|
+
|
186
|
+
test "enabling Drb without any configuration" do
|
187
|
+
config = enable_drb
|
188
|
+
assert config.drb
|
189
|
+
config.drb.should.be.kind_of Adhearsion::Configuration::DrbConfiguration
|
190
|
+
end
|
191
|
+
|
192
|
+
test "enabling Drb with a port specified sets the port" do
|
193
|
+
target_port = 911
|
194
|
+
config = enable_drb :port => target_port
|
195
|
+
config.drb.port.should.be.equal target_port
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
199
|
+
def enable_ami(*overrides)
|
200
|
+
default_config do |config|
|
201
|
+
config.asterisk.enable_ami(*overrides)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def enable_drb(*overrides)
|
206
|
+
default_config do |config|
|
207
|
+
config.enable_drb *overrides
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context "AHN_CONFIG" do
|
213
|
+
setup do
|
214
|
+
Adhearsion.send(:remove_const, :AHN_CONFIG) if Adhearsion.const_defined?(:AHN_CONFIG)
|
215
|
+
end
|
216
|
+
|
217
|
+
test "Running configure sets configuration to Adhearsion::AHN_CONFIG" do
|
218
|
+
assert !Adhearsion.const_defined?(:AHN_CONFIG)
|
219
|
+
Adhearsion::Configuration.configure do |config|
|
220
|
+
# Nothing needs to happen here
|
221
|
+
end
|
222
|
+
|
223
|
+
assert Adhearsion.const_defined?(:AHN_CONFIG)
|
224
|
+
Adhearsion::AHN_CONFIG.should.be.kind_of(Adhearsion::Configuration)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
context "DRb configuration" do
|
229
|
+
test "should not add any ACL rules when :raw_acl is passed in" do
|
230
|
+
config = Adhearsion::Configuration::DrbConfiguration.new :raw_acl => :this_is_an_acl
|
231
|
+
config.acl.should.equal :this_is_an_acl
|
232
|
+
end
|
233
|
+
|
234
|
+
test "should, by default, allow only localhost connections" do
|
235
|
+
config = Adhearsion::Configuration::DrbConfiguration.new
|
236
|
+
config.acl.should == %w[allow 127.0.0.1]
|
237
|
+
end
|
238
|
+
|
239
|
+
test "should add ACL 'deny' rules before 'allow' rules" do
|
240
|
+
config = Adhearsion::Configuration::DrbConfiguration.new :allow => %w[1.1.1.1 2.2.2.2],
|
241
|
+
:deny => %w[9.9.9.9]
|
242
|
+
config.acl.should == %w[deny 9.9.9.9 allow 1.1.1.1 allow 2.2.2.2]
|
243
|
+
end
|
244
|
+
|
245
|
+
test "should allow both an Array and a String to be passed as an allow/deny ACL rule" do
|
246
|
+
config = Adhearsion::Configuration::DrbConfiguration.new :allow => "1.1.1.1", :deny => "9.9.9.9"
|
247
|
+
config.acl.should == %w[deny 9.9.9.9 allow 1.1.1.1]
|
248
|
+
end
|
249
|
+
|
250
|
+
test "should have a default host and port" do
|
251
|
+
config = Adhearsion::Configuration::DrbConfiguration.new
|
252
|
+
config.host.should.not.equal nil
|
253
|
+
config.port.should.not.equal nil
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
BEGIN {
|
259
|
+
module ConfigurationTestHelper
|
260
|
+
def default_config(&block)
|
261
|
+
Adhearsion::Configuration.new do |config|
|
262
|
+
config.enable_asterisk
|
263
|
+
yield config if block_given?
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
}
|