adhearsion 1.2.6 → 2.0.0.alpha1
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/.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
|