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
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
module Adhearsion
|
|
2
|
-
module VoIP
|
|
3
|
-
module FreeSwitch
|
|
4
|
-
|
|
5
|
-
# Subclass this to register a new event handler
|
|
6
|
-
class EventHandler
|
|
7
|
-
|
|
8
|
-
@@events = {}
|
|
9
|
-
@@compound_events = {}
|
|
10
|
-
|
|
11
|
-
@@connection = nil
|
|
12
|
-
|
|
13
|
-
def self.start!(hash=nil)
|
|
14
|
-
login hash if hash
|
|
15
|
-
raise "You must login to the FreeSWITCH EventSocket!" unless @@connection
|
|
16
|
-
loop do
|
|
17
|
-
# debug "Waiting for an event"
|
|
18
|
-
dispatch_event! @@connection.get_header
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def self.dispatch_event!(data)
|
|
23
|
-
#puts "\nHandling an event! #{data.inspect}"
|
|
24
|
-
name = data['Event-Name']
|
|
25
|
-
normal_event = name && @@events[name.underscore.to_sym]
|
|
26
|
-
# puts "THIS IS WHAT I THINK IT MIGHT BE : #{normal_event.inspect} (with #{name.underscore.to_sym.inspect})"
|
|
27
|
-
if normal_event then normal_event.call(data)
|
|
28
|
-
else
|
|
29
|
-
#debug "Trying compound events"
|
|
30
|
-
@@compound_events.each do |(event, block)|
|
|
31
|
-
mini_event = {}
|
|
32
|
-
event.keys.each { |k| mini_event[k] = data[k] }
|
|
33
|
-
block.call(data) if event == mini_event
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
rescue => e
|
|
37
|
-
p e
|
|
38
|
-
puts e.backtrace.map { |x| " " * 4 + x }
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
protected
|
|
42
|
-
|
|
43
|
-
# Can be specified in the subclass
|
|
44
|
-
def self.login(hash)
|
|
45
|
-
debug "Creating a new event connection manager"
|
|
46
|
-
@@connection = InboundConnectionManager.new hash
|
|
47
|
-
debug "Enabling events"
|
|
48
|
-
@@connection.enable_events!
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def self.on(event, &block)
|
|
52
|
-
event = event.underscore.to_sym if event.is_a? String
|
|
53
|
-
(event.kind_of?(Hash) ? @@compound_events : @@events)[event] = block
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
require 'adhearsion/voip/dsl/dialplan/dispatcher'
|
|
2
|
-
|
|
3
|
-
module Adhearsion
|
|
4
|
-
module VoIP
|
|
5
|
-
module FreeSwitch
|
|
6
|
-
class FreeSwitchDialplanCommandFactory
|
|
7
|
-
|
|
8
|
-
def initialize(context=nil)
|
|
9
|
-
@context = context
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# These should all return those objects...
|
|
13
|
-
def speak(text, hash={})
|
|
14
|
-
voice, engine = hash[:voice] || "Dianne", hash[:engine] || "cepstral"
|
|
15
|
-
|
|
16
|
-
dtmf = hash[:on_keypress]
|
|
17
|
-
speak_cmd = cmd 'speak', "#{engine}|#{voice}|%p" % text, :on_keypress => dtmf
|
|
18
|
-
|
|
19
|
-
if hash[:timeout] == 0
|
|
20
|
-
[speak_cmd, DSL::Dialplan::NoOpEventCommand.new(hash[:timeout], :on_keypress => dtmf)]
|
|
21
|
-
else
|
|
22
|
-
puts "Returning the normal speak command"
|
|
23
|
-
speak_cmd
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def set(key, value)
|
|
28
|
-
cmd 'set', "#{key}=#{value}"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def play(*files)
|
|
32
|
-
hash = files.last.kind_of?(Hash) ? files.pop : {}
|
|
33
|
-
conference, to = hash[:conference], hash[:to]
|
|
34
|
-
puts "conference: #{conference.inspect}, to: #{to.inspect}, hash: #{hash.inspect}, files: #{files.inspect}"
|
|
35
|
-
if conference
|
|
36
|
-
# Normal (inbound) event socket playing to a conference
|
|
37
|
-
files.map do |file|
|
|
38
|
-
cmd "conference", "#{conference} play #{file} #{to}"
|
|
39
|
-
end
|
|
40
|
-
elsif to
|
|
41
|
-
# Normal event socket syntax
|
|
42
|
-
files.map do |file|
|
|
43
|
-
# TODO: Support playing to an individual leg of the call.
|
|
44
|
-
cmd "broadcast", "#{to} #{file} both"
|
|
45
|
-
end
|
|
46
|
-
else
|
|
47
|
-
# Outbound event sockets
|
|
48
|
-
files.map { |file| cmd('playback', file) }
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def join(id)
|
|
53
|
-
DSL::Dialplan::ExitingEventCommand.new "conference", id.to_s
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def hangup!
|
|
57
|
-
cmd "exit"
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def return!(obj)
|
|
61
|
-
raise DSL::Dialplan::ReturnValue.new(obj)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def hangup!
|
|
65
|
-
raise DSL::Dialplan::Hangup
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def wait(seconds=nil, &block)
|
|
69
|
-
DSL::Dialplan::NoOpEventCommand.new(seconds)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def record(hash={}, &block)
|
|
73
|
-
# TODO: Could want to record a conference or a UUID
|
|
74
|
-
p hash
|
|
75
|
-
if hash[:stop]
|
|
76
|
-
cmd 'stop_record_session', hash[:stop]
|
|
77
|
-
else
|
|
78
|
-
file = hash[:file] || File.join(Dir::tmpdir, String.random(32), '.wav')
|
|
79
|
-
|
|
80
|
-
raise "Cannot supply both a timeout and a block!" if hash[:timeout] && block_given?
|
|
81
|
-
|
|
82
|
-
dtmf_breaker = lambda do |digit|
|
|
83
|
-
return! file if digit == hash[:break_on]
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
rec_cmd = cmd "record", file, :on_keypress => dtmf_breaker
|
|
87
|
-
[].tap do |cmds|
|
|
88
|
-
cmds << play('beep') if hash[:beep]
|
|
89
|
-
cmds << rec_cmd
|
|
90
|
-
if hash[:timeout]
|
|
91
|
-
cmds << DSL::Dialplan::NoOpEventCommand.new(hash[:timeout])
|
|
92
|
-
elsif block_given?
|
|
93
|
-
cmds << block
|
|
94
|
-
cmds << record(:stop => file)
|
|
95
|
-
end
|
|
96
|
-
cmds << file
|
|
97
|
-
p cmds
|
|
98
|
-
cmds
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def input(number=nil, hash={})
|
|
104
|
-
timeout, file = hash[:timeout], hash[:play] || hash[:file]
|
|
105
|
-
break_on = hash[:break_on] || '#'
|
|
106
|
-
|
|
107
|
-
# TODO: compile play() and set its DTMF callback to this one
|
|
108
|
-
digits = []
|
|
109
|
-
dtmf_hook = lambda do |digit|
|
|
110
|
-
puts "RECEIVED #{digit} WITH #{digits}"
|
|
111
|
-
return! digits.to_s if digit.to_s == break_on.to_s
|
|
112
|
-
digits << digit
|
|
113
|
-
return! digits.to_s if number && digits.size >= number
|
|
114
|
-
end
|
|
115
|
-
DSL::Dialplan::NoOpEventCommand.new.tap do |command|
|
|
116
|
-
command.on_keypress &dtmf_hook
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
private
|
|
121
|
-
|
|
122
|
-
def cmd(*args, &block)
|
|
123
|
-
DSL::Dialplan::EventCommand.new(*args, &block)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
end
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
require 'adhearsion/voip/freeswitch/basic_connection_manager'
|
|
2
|
-
module Adhearsion
|
|
3
|
-
module VoIP
|
|
4
|
-
module FreeSwitch
|
|
5
|
-
class InboundConnectionManager < BasicConnectionManager
|
|
6
|
-
|
|
7
|
-
DEFAULTS = { :pass => "ClueCon", :host => '127.0.0.1', :port => 8021 }
|
|
8
|
-
|
|
9
|
-
def initialize(arg)
|
|
10
|
-
if arg.kind_of? Hash
|
|
11
|
-
@opts = DEFAULTS.merge arg
|
|
12
|
-
@io = TCPSocket.new(@opts[:host], @opts[:port])
|
|
13
|
-
super @io
|
|
14
|
-
unless login(@opts[:pass])
|
|
15
|
-
raise "Your FreeSwitch Event Socket password for #{@opts[:host]} was invalid!"
|
|
16
|
-
end
|
|
17
|
-
else arg.kind_of? IO
|
|
18
|
-
@io = arg
|
|
19
|
-
super @io
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def enable_events!(which='ALL')
|
|
24
|
-
self << "event plain #{which}"
|
|
25
|
-
get_raw_header
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Only called when nothing has been sent over the socket.
|
|
29
|
-
def login(pass)
|
|
30
|
-
get_raw_header
|
|
31
|
-
self << "auth #{pass}"
|
|
32
|
-
get_raw_header.include? "+OK"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
require 'gserver'
|
|
2
|
-
|
|
3
|
-
require 'adhearsion/voip/dsl/dialplan/thread_mixin'
|
|
4
|
-
require 'adhearsion/voip/dsl/dialplan/parser'
|
|
5
|
-
require 'adhearsion/voip/dsl/dialplan/dispatcher'
|
|
6
|
-
require 'adhearsion/voip/freeswitch/basic_connection_manager'
|
|
7
|
-
require 'adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory'
|
|
8
|
-
|
|
9
|
-
module Adhearsion
|
|
10
|
-
module VoIP
|
|
11
|
-
module FreeSwitch
|
|
12
|
-
class OesServer < GServer
|
|
13
|
-
|
|
14
|
-
def initialize(port, host=nil)
|
|
15
|
-
@port, @host = port || 4572, host || "0.0.0.0"
|
|
16
|
-
@cache_lock = Mutex.new
|
|
17
|
-
super @port, @host, (1.0/0.0)
|
|
18
|
-
log "Starting FreeSwitch OES Server"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def serve(io)
|
|
22
|
-
|
|
23
|
-
log "Incoming call on the FreeSwitch outbound event socket..."
|
|
24
|
-
Thread.me.extend DSL::Dialplan::ThreadMixin
|
|
25
|
-
Thread.me.call.io = io
|
|
26
|
-
conn = BasicConnectionManager.new io
|
|
27
|
-
|
|
28
|
-
Thread.my.call.mgr = conn
|
|
29
|
-
conn << "connect"
|
|
30
|
-
@vars = conn.get_header
|
|
31
|
-
answered = @vars['variable_endpoint_disposition'] == "ANSWER"
|
|
32
|
-
|
|
33
|
-
conn << "myevents"
|
|
34
|
-
myevents_response = conn.get_header
|
|
35
|
-
answered ||= myevents_response['Event-Name'] == 'CHANNEL_ANSWER'
|
|
36
|
-
|
|
37
|
-
log "Connected to Freeswitch. Waiting for answer state."
|
|
38
|
-
|
|
39
|
-
until answered
|
|
40
|
-
answered ||= conn.get_header['Event-Name'] == 'CHANNEL_ANSWER'
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
log "Loading cached dialplan"
|
|
44
|
-
contexts, dispatcher = cached_dialplan_data
|
|
45
|
-
log "Finished loading cached dialplans"
|
|
46
|
-
|
|
47
|
-
first_context_name = @vars['variable_context'] || @vars["Channel-Context"]
|
|
48
|
-
first_context = contexts[first_context_name.to_sym]
|
|
49
|
-
|
|
50
|
-
log "Found context #{first_context_name} from call variables."
|
|
51
|
-
|
|
52
|
-
# If the target context does not exist, warn and don't handle the call
|
|
53
|
-
unless first_context
|
|
54
|
-
log "No context '#{first_context_name}' found in " +
|
|
55
|
-
"#{AHN_CONFIG.files_from_setting("paths", "").to_sentence(:connector => "or")}. Ignoring request!"
|
|
56
|
-
return
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Enable events
|
|
60
|
-
|
|
61
|
-
# Now that we have the code, let's dispatch it back.
|
|
62
|
-
|
|
63
|
-
pretty_vars = rubyize_keys_for @vars
|
|
64
|
-
dispatcher.def_keys! pretty_vars
|
|
65
|
-
dispatcher.instance_eval(&first_context.block)
|
|
66
|
-
|
|
67
|
-
rescue => e
|
|
68
|
-
p e
|
|
69
|
-
puts e.backtrace.map {|x| " " * 4 + x }
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def cached_dialplan_data
|
|
73
|
-
@cache_lock.synchronize do
|
|
74
|
-
log "Checking whether the contexts should be reloaded"
|
|
75
|
-
if should_reload_contexts?
|
|
76
|
-
log "Getting the contexts"
|
|
77
|
-
@abstract_contexts = DSL::Dialplan::DialplanParser.get_contexts
|
|
78
|
-
log "Creating a new OesDispatcher"
|
|
79
|
-
@abstract_dispatcher = OesDispatcher.new @vars['Channel-Unique-ID']
|
|
80
|
-
log "Done creating it"
|
|
81
|
-
@abstract_dispatcher.def_keys! @abstract_contexts
|
|
82
|
-
else
|
|
83
|
-
log "Should not reload context."
|
|
84
|
-
@abstract_dispatcher.instance_variable_set :@uuid, @vars['Channel-Unique-ID']
|
|
85
|
-
end
|
|
86
|
-
return [@abstract_contexts.clone, @abstract_dispatcher.clone]
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# TODO. This is broken. Always returns true. Should cache the last reload
|
|
91
|
-
# time.
|
|
92
|
-
def should_reload_contexts?
|
|
93
|
-
!@abstract_contexts || !@abstract_dispatcher ||
|
|
94
|
-
AHN_CONFIG.files_from_setting("paths", "dialplan").map { |x| File.mtime(x) }.max < Time.now
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def rubyize_keys_for(hash)
|
|
98
|
-
{}.tap do |pretty|
|
|
99
|
-
hash.each { |k,v| pretty[k.to_s.underscore] = v }
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
class OesDispatcher < DSL::Dialplan::CommandDispatcher
|
|
104
|
-
|
|
105
|
-
def initialize(uuid=nil)
|
|
106
|
-
super FreeSwitchDialplanCommandFactory, uuid
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def dispatch!(event)
|
|
110
|
-
if event.kind_of?(DSL::Dialplan::NoOpEventCommand) && event.on_keypress
|
|
111
|
-
return_value = nil
|
|
112
|
-
dispatch = lambda do
|
|
113
|
-
loop do
|
|
114
|
-
Thread.my.call.mgr.get_raw_header
|
|
115
|
-
async_event = Thread.my.call.mgr.get_header
|
|
116
|
-
if async_event['Event-Name'] == 'DTMF'
|
|
117
|
-
key = async_event['DTMF-String']
|
|
118
|
-
return_value = event.on_keypress.call(('0'..'9').include?(key) ? key.to_i : key)
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
if event.timeout
|
|
123
|
-
begin
|
|
124
|
-
Timeout.timeout event.timeout, &dispatch
|
|
125
|
-
rescue Timeout::Error
|
|
126
|
-
break!
|
|
127
|
-
return_value
|
|
128
|
-
end
|
|
129
|
-
else dispatch.call
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
else
|
|
133
|
-
log "Not a noop. Sending #{event.app}(#{event.args.to_a * " "})"
|
|
134
|
-
Thread.my.call.mgr << "SendMsg\ncall-command: execute\nexecute-app-name: " +
|
|
135
|
-
"#{event.app}\nexecute-app-arg: #{event.args.to_a * " "}"
|
|
136
|
-
|
|
137
|
-
if event.kind_of? DSL::Dialplan::ExitingEventCommand
|
|
138
|
-
Thread.my.call.io.close
|
|
139
|
-
Thread.me.exit
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Useless "command/reply" +OK and content-length headers
|
|
143
|
-
lambda do
|
|
144
|
-
Thread.my.call.mgr.get_raw_header
|
|
145
|
-
redo if Thread.my.call.mgr.get_header['Event-Name'] == "CHANNEL_EXECUTE_COMPLETE"
|
|
146
|
-
end.call
|
|
147
|
-
|
|
148
|
-
# Main event information. Keep track of the Core-UUID and wait for
|
|
149
|
-
# it to come back to us as a CHANNEL_EXECUTE_COMPLETE event.
|
|
150
|
-
execution_header = Thread.my.call.mgr.get_header
|
|
151
|
-
execution_uuid = execution_header['Core-UUID']
|
|
152
|
-
|
|
153
|
-
loop do
|
|
154
|
-
log "Waiting for either a DTMF or the app to finish"
|
|
155
|
-
hdr = Thread.my.call.mgr.get_raw_header
|
|
156
|
-
log "Got head #{hdr}"
|
|
157
|
-
|
|
158
|
-
if hdr == "Content-Type: api/response\nContent-Length: 0"
|
|
159
|
-
break
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
async_event = Thread.my.call.mgr.get_header
|
|
163
|
-
event_name = async_event['Event-Name']
|
|
164
|
-
if event_name == 'DTMF' && event.on_keypress
|
|
165
|
-
key = async_event['DTMF-String']
|
|
166
|
-
event.on_keypress.call(('0'..'9') === key ? key.to_i : key)
|
|
167
|
-
elsif event_name == 'CHANNEL_EXECUTE_COMPLETE' && async_event['Core-UUID'] == execution_uuid
|
|
168
|
-
break async_event
|
|
169
|
-
else
|
|
170
|
-
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
rescue DSL::Dialplan::ReturnValue => r
|
|
175
|
-
log "Dispatch!: Got a return value with #{r.obj}"
|
|
176
|
-
break!
|
|
177
|
-
raise r
|
|
178
|
-
rescue DSL::Dialplan::Hangup
|
|
179
|
-
Thread.my.call.mgr << "SendMsg\ncall-command: hangup"
|
|
180
|
-
Thread.my.call.mgr.io.close rescue nil
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def break!(uuid=@context)
|
|
184
|
-
log "Breaking with #{uuid}"
|
|
185
|
-
Thread.my.call.mgr << "api break #{uuid}"
|
|
186
|
-
Thread.my.call.mgr.get_raw_header
|
|
187
|
-
# Thread.my.call.mgr.get_raw_header
|
|
188
|
-
# Thread.my.call.mgr.get_raw_header
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
end
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
module Adhearsion
|
|
2
|
-
module VoIP
|
|
3
|
-
class CalculatedMatch
|
|
4
|
-
|
|
5
|
-
# Convenience method for instantiating failed matches
|
|
6
|
-
def self.failed_match!(pattern, query, match_payload)
|
|
7
|
-
new :pattern => pattern, :query => query, :match_payload => match_payload
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
attr_reader :match_payload, :potential_matches, :exact_matches, :pattern, :query
|
|
11
|
-
|
|
12
|
-
def initialize(options={})
|
|
13
|
-
@pattern, @query, @match_payload = options.values_at :pattern, :query, :match_payload
|
|
14
|
-
@potential_matches = options[:potential_matches] ? Array(options[:potential_matches]) : []
|
|
15
|
-
@exact_matches = options[:exact_matches] ? Array(options[:exact_matches]) : []
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def exact_match?
|
|
19
|
-
exact_matches.any?
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def potential_match?
|
|
23
|
-
potential_matches.any?
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def failed_match?
|
|
27
|
-
!potential_match? && !exact_match?
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def type_of_match
|
|
31
|
-
if exact_match?
|
|
32
|
-
:exact
|
|
33
|
-
elsif potential_match?
|
|
34
|
-
:potential
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
class CalculatedMatchCollection
|
|
41
|
-
|
|
42
|
-
attr_reader :calculated_matches, :potential_matches, :exact_matches,
|
|
43
|
-
:actual_potential_matches, :actual_exact_matches
|
|
44
|
-
|
|
45
|
-
def initialize
|
|
46
|
-
@calculated_matches = []
|
|
47
|
-
@potential_matches = []
|
|
48
|
-
@exact_matches = []
|
|
49
|
-
@actual_potential_matches = []
|
|
50
|
-
@actual_exact_matches = []
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def <<(calculated_match)
|
|
54
|
-
calculated_matches << calculated_match
|
|
55
|
-
actual_potential_matches.concat calculated_match.potential_matches
|
|
56
|
-
actual_exact_matches.concat calculated_match.exact_matches
|
|
57
|
-
|
|
58
|
-
potential_matches << calculated_match if calculated_match.potential_match?
|
|
59
|
-
exact_matches << calculated_match if calculated_match.exact_match?
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def potential_match_count
|
|
63
|
-
actual_potential_matches.size
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def exact_match_count
|
|
67
|
-
actual_exact_matches.size
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def potential_match?
|
|
71
|
-
potential_match_count > 0
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def exact_match?
|
|
75
|
-
exact_match_count > 0
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|