adhearsion 1.2.6 → 2.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -10
- data/CHANGELOG.md +273 -0
- data/Gemfile +1 -1
- data/Guardfile +17 -0
- data/README.markdown +61 -9
- data/Rakefile +16 -48
- data/adhearsion.gemspec +21 -7
- data/bin/ahn +3 -1
- data/cucumber.yml +4 -0
- data/features/app_generator.feature +42 -0
- data/features/cli.feature +108 -0
- data/features/step_definitions/app_generator_steps.rb +6 -0
- data/features/step_definitions/cli_steps.rb +74 -0
- data/features/support/aruba_helper.rb +22 -0
- data/features/support/env.rb +37 -0
- data/features/support/utils.rb +8 -0
- data/lib/adhearsion.rb +85 -41
- data/lib/adhearsion/call.rb +176 -0
- data/lib/adhearsion/call_controller.rb +134 -0
- data/lib/adhearsion/call_controller/dial.rb +70 -0
- data/lib/adhearsion/call_controller/input.rb +173 -0
- data/lib/adhearsion/call_controller/menu.rb +124 -0
- data/lib/adhearsion/call_controller/output.rb +267 -0
- data/lib/adhearsion/call_controller/record.rb +42 -0
- data/lib/adhearsion/call_controller/utility.rb +60 -0
- data/lib/adhearsion/calls.rb +81 -0
- data/lib/adhearsion/cli.rb +1 -3
- data/lib/adhearsion/cli_commands.rb +142 -0
- data/lib/adhearsion/configuration.rb +149 -0
- data/lib/adhearsion/console.rb +19 -8
- data/lib/adhearsion/dialplan_controller.rb +9 -0
- data/lib/adhearsion/events.rb +84 -0
- data/lib/adhearsion/foundation/all.rb +0 -7
- data/lib/adhearsion/foundation/custom_daemonizer.rb +4 -6
- data/lib/adhearsion/foundation/exception_handler.rb +9 -0
- data/lib/adhearsion/foundation/object.rb +26 -8
- data/lib/adhearsion/foundation/synchronized_hash.rb +3 -6
- data/lib/adhearsion/foundation/thread_safety.rb +17 -1
- data/lib/adhearsion/generators/app/app_generator.rb +4 -13
- data/lib/adhearsion/generators/app/templates/Gemfile +10 -5
- data/lib/adhearsion/generators/app/templates/Procfile +1 -0
- data/lib/adhearsion/generators/app/templates/README.md +28 -0
- data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +41 -0
- data/lib/adhearsion/generators/app/templates/{components/simon_game → lib}/simon_game.rb +6 -18
- data/lib/adhearsion/generators/app/templates/script/ahn +2 -2
- data/lib/adhearsion/initializer.rb +151 -293
- data/lib/adhearsion/initializer/logging.rb +33 -0
- data/lib/adhearsion/logging.rb +65 -69
- data/lib/adhearsion/menu_dsl.rb +15 -0
- data/lib/adhearsion/menu_dsl/calculated_match.rb +39 -0
- data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +41 -0
- data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +18 -0
- data/lib/adhearsion/menu_dsl/match_calculator.rb +36 -0
- data/lib/adhearsion/{voip/menu_state_machine/menu_class.rb → menu_dsl/menu.rb} +38 -40
- data/lib/adhearsion/menu_dsl/menu_builder.rb +69 -0
- data/lib/adhearsion/menu_dsl/range_match_calculator.rb +55 -0
- data/lib/adhearsion/menu_dsl/string_match_calculator.rb +21 -0
- data/lib/adhearsion/outbound_call.rb +64 -0
- data/lib/adhearsion/plugin.rb +319 -0
- data/lib/adhearsion/plugin/collection.rb +19 -0
- data/lib/adhearsion/plugin/initializer.rb +37 -0
- data/lib/adhearsion/plugin/methods_container.rb +6 -0
- data/lib/adhearsion/process.rb +94 -0
- data/lib/adhearsion/punchblock_plugin.rb +29 -0
- data/lib/adhearsion/punchblock_plugin/initializer.rb +137 -0
- data/lib/adhearsion/router.rb +30 -0
- data/lib/adhearsion/router/route.rb +42 -0
- data/lib/adhearsion/script_ahn_loader.rb +2 -2
- data/lib/adhearsion/tasks.rb +14 -9
- data/lib/adhearsion/tasks/configuration.rb +26 -0
- data/lib/adhearsion/tasks/plugins.rb +17 -0
- data/lib/adhearsion/version.rb +8 -14
- data/spec/adhearsion/call_controller/dial_spec.rb +138 -0
- data/spec/adhearsion/call_controller/input_spec.rb +278 -0
- data/spec/adhearsion/call_controller/menu_spec.rb +120 -0
- data/spec/adhearsion/call_controller/output_spec.rb +466 -0
- data/spec/adhearsion/call_controller/record_spec.rb +125 -0
- data/spec/adhearsion/call_controller_spec.rb +395 -0
- data/spec/adhearsion/call_spec.rb +438 -0
- data/spec/adhearsion/calls_spec.rb +47 -0
- data/spec/adhearsion/configuration_spec.rb +308 -0
- data/spec/adhearsion/dialplan_controller_spec.rb +26 -0
- data/spec/adhearsion/events_spec.rb +112 -0
- data/spec/adhearsion/initializer/logging_spec.rb +58 -0
- data/spec/adhearsion/initializer_spec.rb +209 -122
- data/spec/adhearsion/logging_spec.rb +58 -47
- data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +56 -0
- data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +57 -0
- data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +33 -0
- data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +13 -0
- data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +118 -0
- data/spec/adhearsion/menu_dsl/menu_spec.rb +210 -0
- data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +28 -0
- data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +36 -0
- data/spec/adhearsion/menu_dsl_spec.rb +12 -0
- data/spec/adhearsion/outbound_call_spec.rb +174 -0
- data/spec/adhearsion/plugin_spec.rb +489 -0
- data/spec/adhearsion/process_spec.rb +34 -0
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +294 -0
- data/spec/adhearsion/router/route_spec.rb +99 -0
- data/spec/adhearsion/router_spec.rb +106 -0
- data/spec/adhearsion_spec.rb +46 -0
- data/spec/spec_helper.rb +14 -14
- data/spec/support/call_controller_test_helpers.rb +48 -0
- data/spec/support/initializer_stubs.rb +8 -13
- data/spec/support/punchblock_mocks.rb +6 -0
- metadata +255 -253
- data/CHANGELOG +0 -174
- data/bin/ahnctl +0 -68
- data/bin/jahn +0 -43
- data/examples/asterisk_manager_interface/standalone.rb +0 -51
- data/lib/adhearsion/commands.rb +0 -302
- data/lib/adhearsion/component_manager.rb +0 -278
- data/lib/adhearsion/component_manager/component_tester.rb +0 -54
- data/lib/adhearsion/component_manager/spec_framework.rb +0 -18
- data/lib/adhearsion/events_support.rb +0 -65
- data/lib/adhearsion/foundation/blank_slate.rb +0 -3
- data/lib/adhearsion/foundation/event_socket.rb +0 -205
- data/lib/adhearsion/foundation/future_resource.rb +0 -36
- data/lib/adhearsion/foundation/metaprogramming.rb +0 -17
- data/lib/adhearsion/foundation/numeric.rb +0 -13
- data/lib/adhearsion/foundation/pseudo_guid.rb +0 -10
- data/lib/adhearsion/foundation/relationship_properties.rb +0 -42
- data/lib/adhearsion/foundation/string.rb +0 -26
- data/lib/adhearsion/generators/app/templates/.ahnrc +0 -34
- data/lib/adhearsion/generators/app/templates/README +0 -8
- data/lib/adhearsion/generators/app/templates/components/ami_remote/ami_remote.rb +0 -15
- data/lib/adhearsion/generators/app/templates/components/disabled/HOW_TO_ENABLE +0 -7
- data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/README.markdown +0 -47
- data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.rb +0 -34
- data/lib/adhearsion/generators/app/templates/components/disabled/stomp_gateway/stomp_gateway.yml +0 -12
- data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/README.markdown +0 -3
- data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +0 -11
- data/lib/adhearsion/generators/app/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
- data/lib/adhearsion/generators/app/templates/config/startup.rb +0 -81
- data/lib/adhearsion/generators/app/templates/dialplan.rb +0 -3
- data/lib/adhearsion/generators/app/templates/events.rb +0 -33
- data/lib/adhearsion/host_definitions.rb +0 -67
- data/lib/adhearsion/initializer/asterisk.rb +0 -86
- data/lib/adhearsion/initializer/configuration.rb +0 -324
- data/lib/adhearsion/initializer/database.rb +0 -60
- data/lib/adhearsion/initializer/drb.rb +0 -31
- data/lib/adhearsion/initializer/freeswitch.rb +0 -22
- data/lib/adhearsion/initializer/ldap.rb +0 -57
- data/lib/adhearsion/initializer/rails.rb +0 -41
- data/lib/adhearsion/initializer/xmpp.rb +0 -42
- data/lib/adhearsion/tasks/components.rb +0 -32
- data/lib/adhearsion/tasks/database.rb +0 -5
- data/lib/adhearsion/tasks/deprecations.rb +0 -59
- data/lib/adhearsion/tasks/generating.rb +0 -20
- data/lib/adhearsion/tasks/lint.rb +0 -4
- data/lib/adhearsion/voip/asterisk.rb +0 -4
- data/lib/adhearsion/voip/asterisk/agi_server.rb +0 -121
- data/lib/adhearsion/voip/asterisk/commands.rb +0 -1966
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +0 -140
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +0 -102
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +0 -250
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +0 -240
- data/lib/adhearsion/voip/asterisk/config_manager.rb +0 -64
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +0 -697
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +0 -1681
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +0 -341
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +0 -78
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +0 -87
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +0 -80
- data/lib/adhearsion/voip/call.rb +0 -521
- data/lib/adhearsion/voip/call_routing.rb +0 -64
- data/lib/adhearsion/voip/commands.rb +0 -17
- data/lib/adhearsion/voip/constants.rb +0 -39
- data/lib/adhearsion/voip/conveniences.rb +0 -18
- data/lib/adhearsion/voip/dial_plan.rb +0 -252
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +0 -151
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +0 -37
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +0 -27
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +0 -124
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +0 -69
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +0 -16
- data/lib/adhearsion/voip/dsl/numerical_string.rb +0 -128
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +0 -48
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +0 -58
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +0 -129
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +0 -38
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +0 -195
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +0 -80
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +0 -123
- data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +0 -57
- data/lib/adhearsion/xmpp/connection.rb +0 -61
- data/lib/theatre.rb +0 -147
- data/lib/theatre/README.markdown +0 -64
- data/lib/theatre/callback_definition_loader.rb +0 -86
- data/lib/theatre/guid.rb +0 -23
- data/lib/theatre/invocation.rb +0 -131
- data/lib/theatre/namespace_manager.rb +0 -153
- data/lib/theatre/version.rb +0 -2
- data/spec/adhearsion/cli_spec.rb +0 -306
- data/spec/adhearsion/component_manager_spec.rb +0 -292
- data/spec/adhearsion/constants_spec.rb +0 -8
- data/spec/adhearsion/drb_spec.rb +0 -65
- data/spec/adhearsion/fixtures/dialplan.rb +0 -3
- data/spec/adhearsion/foundation/event_socket_spec.rb +0 -168
- data/spec/adhearsion/host_definitions_spec.rb +0 -79
- data/spec/adhearsion/initializer/configuration_spec.rb +0 -291
- data/spec/adhearsion/initializer/loading_spec.rb +0 -154
- data/spec/adhearsion/initializer/paths_spec.rb +0 -74
- data/spec/adhearsion/relationship_properties_spec.rb +0 -54
- data/spec/adhearsion/voip/asterisk/agi_server_spec.rb +0 -473
- data/spec/adhearsion/voip/asterisk/ami/ami_spec.rb +0 -550
- data/spec/adhearsion/voip/asterisk/ami/lexer/ami_fixtures.yml +0 -30
- data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story +0 -291
- data/spec/adhearsion/voip/asterisk/ami/lexer/lexer_story.rb +0 -241
- data/spec/adhearsion/voip/asterisk/ami/lexer/story_helper.rb +0 -124
- data/spec/adhearsion/voip/asterisk/commands_spec.rb +0 -3241
- data/spec/adhearsion/voip/asterisk/config_file_generators/agents_spec.rb +0 -251
- data/spec/adhearsion/voip/asterisk/config_file_generators/queues_spec.rb +0 -323
- data/spec/adhearsion/voip/asterisk/config_file_generators/voicemail_spec.rb +0 -306
- data/spec/adhearsion/voip/asterisk/config_manager_spec.rb +0 -127
- data/spec/adhearsion/voip/asterisk/menu_command/calculated_match_spec.rb +0 -109
- data/spec/adhearsion/voip/asterisk/menu_command/matchers_spec.rb +0 -97
- data/spec/adhearsion/voip/call_routing_spec.rb +0 -125
- data/spec/adhearsion/voip/dialplan_manager_spec.rb +0 -468
- data/spec/adhearsion/voip/dsl/dialing_dsl_spec.rb +0 -270
- data/spec/adhearsion/voip/dsl/dispatcher_spec.rb +0 -82
- data/spec/adhearsion/voip/dsl/dispatcher_spec_helper.rb +0 -45
- data/spec/adhearsion/voip/dsl/parser_spec.rb +0 -69
- data/spec/adhearsion/voip/freeswitch/basic_connection_manager_spec.rb +0 -39
- data/spec/adhearsion/voip/freeswitch/inbound_connection_manager_spec.rb +0 -39
- data/spec/adhearsion/voip/freeswitch/oes_server_spec.rb +0 -9
- data/spec/adhearsion/voip/numerical_string_spec.rb +0 -61
- data/spec/adhearsion/voip/phone_number_spec.rb +0 -45
- data/spec/support/the_following_code.rb +0 -3
- data/spec/theatre/dsl_examples/simple_before_call.rb +0 -7
- data/spec/theatre/dsl_spec.rb +0 -69
- data/spec/theatre/invocation_spec.rb +0 -182
- data/spec/theatre/namespace_spec.rb +0 -125
- data/spec/theatre/spec_helper_spec.rb +0 -28
- data/spec/theatre/theatre_class_spec.rb +0 -148
@@ -0,0 +1,69 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
module MenuDSL
|
3
|
+
|
4
|
+
class MenuBuilder
|
5
|
+
|
6
|
+
attr_accessor :patterns, :menu_callbacks
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@patterns = []
|
10
|
+
@menu_callbacks = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def build(&block)
|
14
|
+
@context = eval "self", block.binding
|
15
|
+
instance_eval &block
|
16
|
+
end
|
17
|
+
|
18
|
+
def match(*args, &block)
|
19
|
+
payload = if block_given?
|
20
|
+
raise ArgumentError, "You cannot specify both a block and a controller name." if args.last.is_a? Class
|
21
|
+
nil
|
22
|
+
else
|
23
|
+
raise ArgumentError, "You need to provide a block or a controller name." unless args.last.is_a? Class
|
24
|
+
args.pop
|
25
|
+
end
|
26
|
+
|
27
|
+
raise ArgumentError, "You cannot call this method without patterns." if args.empty?
|
28
|
+
|
29
|
+
args.each do |pattern|
|
30
|
+
@patterns << MatchCalculator.build_with_pattern(pattern, payload, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def weighted_match_calculators
|
35
|
+
@patterns
|
36
|
+
end
|
37
|
+
|
38
|
+
def execute_hook_for(symbol, input)
|
39
|
+
callback = @menu_callbacks[symbol]
|
40
|
+
@context.instance_exec input, &callback
|
41
|
+
end
|
42
|
+
|
43
|
+
def invalid(&block)
|
44
|
+
raise LocalJumpError, "Must supply a block!" unless block_given?
|
45
|
+
@menu_callbacks[:invalid] = block
|
46
|
+
end
|
47
|
+
|
48
|
+
def timeout(&block)
|
49
|
+
raise LocalJumpError, "Must supply a block!" unless block_given?
|
50
|
+
@menu_callbacks[:timeout] = block
|
51
|
+
end
|
52
|
+
|
53
|
+
def failure(&block)
|
54
|
+
raise LocalJumpError, "Must supply a block!" unless block_given?
|
55
|
+
@menu_callbacks[:failure] = block
|
56
|
+
end
|
57
|
+
|
58
|
+
def calculate_matches_for(result)
|
59
|
+
CalculatedMatchCollection.new.tap do |collection|
|
60
|
+
weighted_match_calculators.each do |pattern|
|
61
|
+
collection << pattern.match(result)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end # class MenuBuilder
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
module MenuDSL
|
3
|
+
|
4
|
+
class RangeMatchCalculator < MatchCalculator
|
5
|
+
|
6
|
+
def initialize(pattern, match_payload)
|
7
|
+
raise unless pattern.first.kind_of?(Numeric) && pattern.last.kind_of?(Numeric)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def match(query)
|
12
|
+
numerical_query = coerce_to_numeric query
|
13
|
+
if numerical_query
|
14
|
+
exact_match = pattern.include?(numerical_query) ? query : nil
|
15
|
+
potential_matches = numbers_in_range_like numerical_query
|
16
|
+
potential_matches.reject! { |m| m.to_s == exact_match.to_s } if exact_match
|
17
|
+
|
18
|
+
new_calculated_match :query => query, :exact_matches => exact_match,
|
19
|
+
:potential_matches => potential_matches
|
20
|
+
else
|
21
|
+
CalculatedMatch.failed_match! pattern, query, match_payload
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Returns all numbers in the range (@pattern) that +begin with+ the number given
|
28
|
+
# as the first arguement.
|
29
|
+
#
|
30
|
+
# NOTE: If you're having trouble reading what this method is actually doing. It's
|
31
|
+
# effectively a much more efficient version of this:
|
32
|
+
#
|
33
|
+
# pattern.to_a.select { |x| x.to_s.starts_with? num.to_s }.flatten
|
34
|
+
#
|
35
|
+
# Huge thanks to Dave Troy (http://davetroy.blogspot.com) for this awesomely
|
36
|
+
# efficient code!
|
37
|
+
def numbers_in_range_like(num)
|
38
|
+
return (pattern === 0 ? [0] : nil) if num == 0
|
39
|
+
raise ArgumentError unless num.kind_of?(Numeric)
|
40
|
+
Array.new.tap do |matches|
|
41
|
+
first, last = pattern.first, pattern.last
|
42
|
+
power = 0
|
43
|
+
while num < last
|
44
|
+
ones_count = 10**power - 1
|
45
|
+
matches.concat ([num, first].max..[num + ones_count, last].min).to_a
|
46
|
+
num *= 10
|
47
|
+
power += 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end # class RangeMatchCalculator
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
module MenuDSL
|
3
|
+
|
4
|
+
class StringMatchCalculator < MatchCalculator
|
5
|
+
|
6
|
+
def match(query)
|
7
|
+
args = { :query => query, :exact_matches => nil, :potential_matches => nil }
|
8
|
+
|
9
|
+
if pattern == query.to_s
|
10
|
+
args[:exact_matches] = [pattern]
|
11
|
+
elsif pattern.starts_with? query.to_s
|
12
|
+
args[:potential_matches] = [pattern]
|
13
|
+
end
|
14
|
+
|
15
|
+
new_calculated_match args
|
16
|
+
end
|
17
|
+
|
18
|
+
end # class StringMatchCalculator
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
class OutboundCall < Call
|
3
|
+
attr_reader :dial_command
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def originate(to, opts = {})
|
7
|
+
new.tap do |call|
|
8
|
+
call.run_router_on_answer
|
9
|
+
call.dial to, opts
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def id
|
15
|
+
dial_command.call_id if dial_command
|
16
|
+
end
|
17
|
+
|
18
|
+
def variables
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
|
22
|
+
def client
|
23
|
+
PunchblockPlugin::Initializer.client
|
24
|
+
end
|
25
|
+
|
26
|
+
def accept(*args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def answer(*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def reject(*args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def dial(to, options = {})
|
36
|
+
options.merge! :to => to
|
37
|
+
write_and_await_response(Punchblock::Command::Dial.new(options)).tap do |dial_command|
|
38
|
+
@dial_command = dial_command
|
39
|
+
Adhearsion.active_calls << self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def run_router
|
44
|
+
catching_standard_errors do
|
45
|
+
dispatcher = Adhearsion.router.handle self
|
46
|
+
dispatcher.call self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def run_router_on_answer
|
51
|
+
register_event_handler :class => Punchblock::Event::Answered do |event|
|
52
|
+
run_router
|
53
|
+
throw :pass
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def on_answer(&block)
|
58
|
+
register_event_handler :class => Punchblock::Event::Answered do |event|
|
59
|
+
block.call event
|
60
|
+
throw :pass
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
|
3
|
+
# Plugin is the core of extension of Adhearsion framework and provides the easiest
|
4
|
+
# path to add new functionality, configuration or modify the initialization process.
|
5
|
+
#
|
6
|
+
# Its behavior is based on Rails::Railtie, so if you are familiar with Rails
|
7
|
+
# this will be easier for you to start using Adhearsion::Plugin, but of course
|
8
|
+
# no previous knowledge is required.
|
9
|
+
#
|
10
|
+
# With an Adhearsion Plugin you can:
|
11
|
+
#
|
12
|
+
# * create initializers
|
13
|
+
# * add rake tasks to Adhearsion
|
14
|
+
# * add/modify configuration files
|
15
|
+
# * add dialplan, rpc, console and events methods
|
16
|
+
#
|
17
|
+
# == How to create your Adhearsion Plugin
|
18
|
+
#
|
19
|
+
# Create a class that inherits from Adhearsion::Plugin within your plugin namespace.
|
20
|
+
# This class shall be loaded during your awesome Adhearsion application boot process.
|
21
|
+
#
|
22
|
+
# # lib/my_plugin/plugin.rb
|
23
|
+
# module MyPlugin
|
24
|
+
# class Plugin < Adhearsion::Plugin
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# == How to add a new dialplan method
|
29
|
+
#
|
30
|
+
# module MyPlugin
|
31
|
+
# class Plugin < Adhearsion::Plugin
|
32
|
+
# dialplan :my_new_dialplan_method do
|
33
|
+
# logger.info "this dialplan method is really awesome #{call.inspect}. It says 'hello world'"
|
34
|
+
# speak "hello world"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# Create a new rpc, console or events methods is as ease just following this approach
|
40
|
+
#
|
41
|
+
# == Execute a specific code while initializing Adhearison
|
42
|
+
#
|
43
|
+
# module MyPlugin
|
44
|
+
# class Plugin < Adhearsion::Plugin
|
45
|
+
# init :my_plugin do
|
46
|
+
# logger.warn "I want to ensure my plugin is being loaded!!!"
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# As Rails::Railtie does, you can define the exact point when you want to load your plugin
|
52
|
+
# during the initilization process
|
53
|
+
#
|
54
|
+
# module MyPlugin
|
55
|
+
# class Plugin < Adhearsion::Plugin
|
56
|
+
# init :my_plugin, :after => :my_other_plugin do
|
57
|
+
# logger.warn "My Plugin depends on My Other Plugin, so it must be loaded after"
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
class Plugin
|
63
|
+
|
64
|
+
extend ActiveSupport::Autoload
|
65
|
+
|
66
|
+
METHODS_OPTIONS = {:load => true, :scope => false}
|
67
|
+
|
68
|
+
SCOPE_NAMES = [:dialplan, :rpc, :events, :console]
|
69
|
+
|
70
|
+
autoload :Configuration
|
71
|
+
autoload :Collection
|
72
|
+
autoload :Initializer
|
73
|
+
autoload :MethodsContainer
|
74
|
+
|
75
|
+
class << self
|
76
|
+
# Metaprogramming to create the class methods that can be used in user defined plugins to
|
77
|
+
# create specific scope methods
|
78
|
+
SCOPE_NAMES.each do |name|
|
79
|
+
|
80
|
+
# This block will create the relevant methods to handle how to add new methods
|
81
|
+
# to Adhearsion scopes via an Adhearsion Plugin.
|
82
|
+
# The scope method should have a name and a lambda block that will be executed in the
|
83
|
+
# call ExecutionEnvironment context.
|
84
|
+
#
|
85
|
+
# class AhnPluginDemo < Adhearsion::Plugin
|
86
|
+
# dialplan :adh_plugin_demo do
|
87
|
+
# speak "hello world"
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# You could also defined a dialplan or other scope method as above, but you cannot access
|
92
|
+
# the ExecutionEnvironment methods from your specific method due to ruby restrictions
|
93
|
+
# when defining methods (the above lambda version should fit any requirement)
|
94
|
+
#
|
95
|
+
# class AhnPluginDemo < Adhearsion::Plugin
|
96
|
+
# dialplan :adh_plugin_demo
|
97
|
+
#
|
98
|
+
# def self.adh_plugin_demo
|
99
|
+
# logger.debug "I can do fun stuff here, but I cannot access methods as speak"
|
100
|
+
# logger.debug "I can make an HTTP request"
|
101
|
+
# logger.debug "I can log to a specific logging system"
|
102
|
+
# logger.debug "I can access database..."
|
103
|
+
# logger.debug "but I cannot access call control methods"
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
define_method name do |method_name, &block|
|
109
|
+
case method_name
|
110
|
+
when Array
|
111
|
+
method_name.each do |method|
|
112
|
+
send name, method
|
113
|
+
end
|
114
|
+
return
|
115
|
+
when Hash
|
116
|
+
args = method_name
|
117
|
+
method_name = method_name[:name]
|
118
|
+
end
|
119
|
+
|
120
|
+
options = args.nil? ? METHODS_OPTIONS : METHODS_OPTIONS.merge(args)
|
121
|
+
options[:load] or return
|
122
|
+
logger.debug "Adding method #{method_name} to scope #{name}"
|
123
|
+
@@methods_container[name].store({:class => self, :method => method_name}, block.nil? ? nil : block)
|
124
|
+
end
|
125
|
+
|
126
|
+
# This method is a helper to retrieve the specific module that holds the user
|
127
|
+
# defined scope methods
|
128
|
+
define_method "#{name.to_s}_module" do
|
129
|
+
Adhearsion::Plugin.methods_scope[name]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Helper to add scope methods to any class/instance
|
133
|
+
define_method "add_#{name.to_s}_methods" do |object|
|
134
|
+
if object.kind_of?(Module)
|
135
|
+
object.send :include, Adhearsion::Plugin.methods_scope[name]
|
136
|
+
else
|
137
|
+
object.extend Adhearsion::Plugin.methods_scope[name]
|
138
|
+
end
|
139
|
+
object
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Class method that allows any subclass (any Adhearsion plugin) to register rake tasks.
|
145
|
+
#
|
146
|
+
# * Example 1:
|
147
|
+
#
|
148
|
+
# FooBar = Class.new Adhearsion::Plugin do
|
149
|
+
# tasks do
|
150
|
+
# namespace :foo_bar do
|
151
|
+
# desc "Prints the FooBar plugin version"
|
152
|
+
# task :version do
|
153
|
+
# STDOUT.puts "FooBar plugin v0.1"
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# * Example 2:
|
160
|
+
#
|
161
|
+
# FooBar = Class.new Adhearsion::Plugin do
|
162
|
+
# tasks do
|
163
|
+
# load "tasks/foo_bar.rake"
|
164
|
+
# end
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# = tasks/foo_bar.rake
|
168
|
+
#
|
169
|
+
# namespace :foo_bar do
|
170
|
+
# desc "Prints the FooBar plugin version"
|
171
|
+
# task :version do
|
172
|
+
# STDOUT.puts "FooBar plugin v0.1"
|
173
|
+
# end
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
def tasks
|
177
|
+
@@rake_tasks << Proc.new if block_given?
|
178
|
+
@@rake_tasks
|
179
|
+
end
|
180
|
+
|
181
|
+
def reset_rake_tasks
|
182
|
+
@@rake_tasks = []
|
183
|
+
end
|
184
|
+
|
185
|
+
def load_tasks
|
186
|
+
o = Object.new.tap { |o| o.extend Rake::DSL if defined? Rake::DSL }
|
187
|
+
tasks.each do |block|
|
188
|
+
o.instance_eval &block
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def methods_scope
|
193
|
+
@methods_scope ||= Hash.new { |hash, key| hash[key] = Module.new }
|
194
|
+
end
|
195
|
+
|
196
|
+
# Keep methods to be added
|
197
|
+
@@methods_container = Hash.new { |hash, key| hash[key] = MethodsContainer.new }
|
198
|
+
|
199
|
+
def subclasses
|
200
|
+
@subclasses ||= []
|
201
|
+
end
|
202
|
+
|
203
|
+
def inherited(base)
|
204
|
+
logger.debug "Detected new plugin: #{base.name}"
|
205
|
+
subclasses << base
|
206
|
+
end
|
207
|
+
|
208
|
+
def plugin_name(name = nil)
|
209
|
+
if name.nil?
|
210
|
+
@plugin_name ||= ActiveSupport::Inflector.underscore(self.name)
|
211
|
+
else
|
212
|
+
self.plugin_name = name
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def plugin_name=(name)
|
217
|
+
@plugin_name = name
|
218
|
+
end
|
219
|
+
|
220
|
+
def config name = nil
|
221
|
+
if block_given?
|
222
|
+
if name.nil?
|
223
|
+
name = self.plugin_name
|
224
|
+
else
|
225
|
+
self.plugin_name = name
|
226
|
+
end
|
227
|
+
::Loquacious::Configuration.defaults_for name, &Proc.new
|
228
|
+
end
|
229
|
+
|
230
|
+
::Loquacious.configuration_for plugin_name
|
231
|
+
end
|
232
|
+
|
233
|
+
def show_description
|
234
|
+
::Loquacious::Configuration.help_for plugin_name
|
235
|
+
end
|
236
|
+
|
237
|
+
def load_plugins
|
238
|
+
load_methods
|
239
|
+
init_plugins
|
240
|
+
end
|
241
|
+
|
242
|
+
# Load plugins scope methods (scope = dialplan, console, etc)
|
243
|
+
def load_methods
|
244
|
+
unless @@methods_container.empty?
|
245
|
+
|
246
|
+
@@methods_container.each_pair do |scope, methods|
|
247
|
+
|
248
|
+
logger.debug "Loading #{methods.length} #{scope} methods"
|
249
|
+
|
250
|
+
methods.each_pair do |class_method, block|
|
251
|
+
klass, method = class_method[:class], class_method[:method]
|
252
|
+
if block.nil?
|
253
|
+
if klass.respond_to?(method)
|
254
|
+
block = klass.method(method).to_proc
|
255
|
+
elsif klass.instance_methods.include?(method)
|
256
|
+
block = klass.instance_method(method).bind(klass.new)
|
257
|
+
else
|
258
|
+
logger.warn "Unable to load #{scope} method #{method} from plugin class #{klass}"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
logger.debug "Defining method #{method}"
|
263
|
+
block.nil? and raise NoMethodError.new "Invalid #{scope} method: <#{method}>"
|
264
|
+
self.send("#{scope}_module").send(:define_method, method, &block)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# We need to extend Console class with the plugin defined methods
|
269
|
+
Adhearsion::Console.extend(self.console_module) unless self.console_module.instance_methods.empty?
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# Recursively initialization of all the loaded plugins
|
274
|
+
def init_plugins *args
|
275
|
+
initializers.tsort.each do |initializer|
|
276
|
+
initializer.run *args
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def initializers
|
281
|
+
@initializers ||= Collection.new
|
282
|
+
end
|
283
|
+
|
284
|
+
# Class method that will be used by subclasses to initialize the plugin
|
285
|
+
# @param name Symbol plugin initializer name
|
286
|
+
# @param opts Hash
|
287
|
+
# * :before specify the plugin to be loaded before another plugin
|
288
|
+
# * :after specify the plugin to be loaded after another plugin
|
289
|
+
def init(name, opts = {})
|
290
|
+
block_given? or raise ArgumentError, "A block must be passed while defining the Plugin initialization process"
|
291
|
+
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
|
292
|
+
Adhearsion::Plugin.initializers << Initializer.new(name, nil, opts, &Proc.new)
|
293
|
+
end
|
294
|
+
|
295
|
+
def count
|
296
|
+
subclasses.length
|
297
|
+
end
|
298
|
+
|
299
|
+
def add(klass)
|
300
|
+
klass.ancestors.include?(self) and subclasses << klass
|
301
|
+
end
|
302
|
+
|
303
|
+
def delete(plugin_name)
|
304
|
+
plugin_name.ancestors.include?(self) and plugin_name = plugin_name.plugin_name
|
305
|
+
subclasses.delete_if { |plugin| plugin.plugin_name.eql? plugin_name }
|
306
|
+
end
|
307
|
+
|
308
|
+
def delete_all
|
309
|
+
@subclasses = nil
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
reset_rake_tasks
|
314
|
+
|
315
|
+
[:plugin_name, :plugin_name=].each do |method|
|
316
|
+
delegate method, :to => "self.class"
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|