Skip to content

Commit

Permalink
[BUGFIX] Asterisk translator calls/components are no longer actors
Browse files Browse the repository at this point in the history
  • Loading branch information
benlangfeld committed Jan 8, 2014
1 parent cad18ed commit f939eca
Show file tree
Hide file tree
Showing 24 changed files with 150 additions and 294 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
@@ -1,4 +1,5 @@
# [develop](https://github.com/adhearsion/punchblock)
* Bugfix: Remove per-call/component actors from Asterisk translator for performance/stability super-charge

# [v2.1.1](https://github.com/adhearsion/punchblock/compare/v2.1.0...v2.1.1) - [2013-12-19](https://rubygems.org/gems/punchblock/versions/2.1.1)
* Bugfix: Allow sending string SSML docs via Rayo
Expand Down
2 changes: 1 addition & 1 deletion lib/punchblock/connection/asterisk.rb
Expand Up @@ -21,7 +21,7 @@ def run
end

def stop
translator.async.shutdown
translator.terminate
ami_client.terminate
end

Expand Down
26 changes: 12 additions & 14 deletions lib/punchblock/translator/asterisk.rb
Expand Up @@ -59,11 +59,6 @@ def component_with_id(component_id)
@components[component_id]
end

def shutdown
@calls.values.each { |call| call.async.shutdown }
terminate
end

def handle_ami_event(event)
return unless event.is_a? RubyAMI::Event

Expand All @@ -81,7 +76,6 @@ def handle_ami_event(event)
handle_pb_event Event::Asterisk::AMI::Event.new(name: event.name, headers: event.headers)
end
end
exclusive :handle_ami_event

def handle_pb_event(event)
connection.handle_event event
Expand All @@ -104,15 +98,19 @@ def execute_command(command, options = {})

def execute_call_command(command)
if call = call_with_id(command.target_call_id)
call.async.execute_command command
begin
call.execute_command command
rescue => e
deregister_call call.id, call.channel
end
else
command.response = ProtocolError.new.setup :item_not_found, "Could not find a call with ID #{command.target_call_id}", command.target_call_id
end
end

def execute_component_command(command)
if (component = component_with_id(command.component_id))
component.async.execute_command command
component.execute_command command
else
command.response = ProtocolError.new.setup :item_not_found, "Could not find a component with ID #{command.component_id}", command.target_call_id, command.component_id
end
Expand All @@ -123,11 +121,11 @@ def execute_global_command(command)
when Punchblock::Component::Asterisk::AMI::Action
component = Component::Asterisk::AMIAction.new command, current_actor, ami_client
register_component component
component.async.execute
component.execute
when Punchblock::Command::Dial
call = Call.new_link command.to, current_actor, ami_client, connection
call = Call.new command.to, current_actor, ami_client, connection
register_call call
call.async.dial command
call.dial command
else
command.response = ProtocolError.new.setup 'command-not-acceptable', "Did not understand command"
end
Expand Down Expand Up @@ -182,7 +180,7 @@ def ami_dispatch_to_or_create_call(event)
if !calls_for_event.empty?
calls_for_event.each_pair do |channel, call|
next if channel.bridged? && !EVENTS_ALLOWED_BRIDGED.include?(event.name)
call.async.process_ami_event event
call.process_ami_event event
end
elsif event.name == "AsyncAGI" && event['SubEvent'] == "Start"
handle_async_agi_start_event event
Expand All @@ -204,9 +202,9 @@ def handle_async_agi_start_event(event)

return if env[:agi_extension] == 'h' || env[:agi_type] == 'Kill'

call = Call.new_link event['Channel'], current_actor, ami_client, connection, env
call = Call.new event['Channel'], current_actor, ami_client, connection, env
register_call call
call.async.send_offer
call.send_offer
end
end
end
Expand Down
36 changes: 10 additions & 26 deletions lib/punchblock/translator/asterisk/call.rb
Expand Up @@ -7,12 +7,8 @@ module Translator
class Asterisk
class Call
include HasGuardedHandlers
include Celluloid
include DeadActorSafety

extend ActorHasGuardedHandlers
execute_guarded_handlers_on_receiver

InvalidCommandError = Class.new Punchblock::Error

OUTBOUND_CHANNEL_MATCH = /.* <(?<channel>.*)>/.freeze
Expand All @@ -29,8 +25,6 @@ class Call
HANGUP_CAUSE_TO_END_REASON[22] = :reject
HANGUP_CAUSE_TO_END_REASON[102] = :timeout

trap_exit :actor_died

def initialize(channel, translator, ami_client, connection, agi_env = nil)
@channel, @translator, @ami_client, @connection = channel, translator, ami_client, connection
@agi_env = agi_env || {}
Expand All @@ -47,6 +41,10 @@ def register_component(component)
@components[component.id] ||= component
end

def deregister_component(id)
@components.delete id
end

def component_with_id(component_id)
@components[component_id]
end
Expand All @@ -56,10 +54,6 @@ def send_offer
send_pb_event offer_event
end

def shutdown
terminate
end

def channel_var(variable)
@channel_variables[variable] || fetch_channel_var(variable)
end
Expand Down Expand Up @@ -258,8 +252,6 @@ def execute_agi_command(command, *params)
event = condition.wait
return unless event
agi.parse_result event
rescue ChannelGoneError, RubyAMI::Error => e
abort e
end

def logger_id
Expand All @@ -285,21 +277,14 @@ def redirect_back(other_call = nil)
def handle_hangup_event(code = 16)
reason = @hangup_cause || HANGUP_CAUSE_TO_END_REASON[code]
@block_commands = true
@components.dup.each_pair do |id, component|
safe_from_dead_actors do
component.call_ended if component.alive?
end
@components.each_pair do |id, component|
component.call_ended
end
send_end_event reason, code
end

def actor_died(actor, reason)
if id = @components.key(actor)
@components.delete id
return unless reason
complete_event = Punchblock::Event::Complete.new :component_id => id, source_uri: id, :reason => Punchblock::Event::Complete::Error.new
send_pb_event complete_event
end
def after(*args, &block)
translator.after(*args, &block)
end

private
Expand All @@ -320,13 +305,12 @@ def send_ami_action(name, headers = {})
def send_end_event(reason, code = nil)
send_pb_event Event::End.new(reason: reason, platform_code: code)
translator.deregister_call id, channel
terminate
end

def execute_component(type, command, options = {})
type.new_link(command, current_actor).tap do |component|
type.new(command, self).tap do |component|
register_component component
component.async.execute
component.execute
end
end

Expand Down
11 changes: 4 additions & 7 deletions lib/punchblock/translator/asterisk/component.rb
Expand Up @@ -17,14 +17,11 @@ module Component
autoload :StopByRedirect

class Component
include Celluloid
include DeadActorSafety

attr_reader :id, :call, :call_id

def initialize(component_node, call = nil)
@component_node, @call = component_node, call
@call_id = safe_from_dead_actors { call.id } if call
@call_id = call.id if call
@id = Punchblock.new_uuid
@complete = false
setup
Expand All @@ -37,19 +34,19 @@ def execute_command(command)
command.response = ProtocolError.new.setup 'command-not-acceptable', "Did not understand command for component #{id}", call_id, id
end

def send_complete_event(reason, recording = nil, should_terminate = true)
def send_complete_event(reason, recording = nil)
return if @complete
@complete = true
event = Punchblock::Event::Complete.new reason: reason, recording: recording
send_event event
terminate if should_terminate
call.deregister_component id if call
end

def send_event(event)
event.component_id = id
event.target_call_id = call_id
event.source_uri = id
safe_from_dead_actors { translator.handle_pb_event event }
translator.handle_pb_event event
end

def logger_id
Expand Down
Expand Up @@ -15,20 +15,16 @@ def execute
send_ref
rescue RubyAMI::Error
set_node_response false
terminate
rescue ChannelGoneError
set_node_response ProtocolError.new.setup(:item_not_found, "Could not find a call with ID #{call_id}", call_id)
terminate
end
exclusive :execute

def handle_ami_event(event)
if event.name == 'AsyncAGI' && event['SubEvent'] == 'Exec'
send_complete_event success_reason(event), nil, false
send_complete_event success_reason(event)
if @component_node.name == 'ASYNCAGI BREAK' && @call.channel_var('PUNCHBLOCK_END_ON_ASYNCAGI_BREAK')
@call.handle_hangup_event
end
terminate
end
end

Expand Down
11 changes: 5 additions & 6 deletions lib/punchblock/translator/asterisk/component/composed_prompt.rb
Expand Up @@ -15,9 +15,9 @@ def execute

@output_incomplete = true

output_component = Output.new_link(output_command, @call)
output_component = Output.new(output_command, @call)
call.register_component output_component
fut = output_component.future.execute
fut = Thread.new { output_component.execute }

case output_command.response
when Ref
Expand All @@ -41,7 +41,7 @@ def execute

def process_dtmf(digit)
if @component_node.barge_in && @output_incomplete
call.async.redirect_back
call.redirect_back
@barged = true
end
super
Expand All @@ -58,14 +58,13 @@ def input_node
end

def register_dtmf_event_handler
component = current_actor
@dtmf_handler_id = call.register_handler :ami, :name => 'DTMF', [:[], 'End'] => 'Yes' do |event|
component.process_dtmf event['Digit']
process_dtmf event['Digit']
end
end

def unregister_dtmf_event_handler
call.async.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
call.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
end
end
end
Expand Down
5 changes: 2 additions & 3 deletions lib/punchblock/translator/asterisk/component/input.rb
Expand Up @@ -17,14 +17,13 @@ def execute
private

def register_dtmf_event_handler
component = current_actor
call.register_handler :ami, :name => 'DTMF', [:[], 'End'] => 'Yes' do |event|
component.process_dtmf event['Digit']
process_dtmf event['Digit']
end
end

def unregister_dtmf_event_handler
call.async.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
call.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
end
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/punchblock/translator/asterisk/component/output.rb
Expand Up @@ -42,9 +42,8 @@ def execute
@call.send_progress if early

if interrupt
output_component = current_actor
call.register_handler :ami, :name => 'DTMF', [:[], 'End'] => 'Yes' do |event|
output_component.stop_by_redirect finish_reason
stop_by_redirect finish_reason
end
end

Expand Down
5 changes: 2 additions & 3 deletions lib/punchblock/translator/asterisk/component/record.rb
Expand Up @@ -22,9 +22,8 @@ def execute

@format = @component_node.format || 'wav'

component = current_actor
call.register_tmp_handler :ami, :name => 'MonitorStop' do |event|
component.finished
finished
end

if @component_node.start_beep
Expand All @@ -33,7 +32,7 @@ def execute

ami_client.send_action 'Monitor', 'Channel' => call.channel, 'File' => filename, 'Format' => @format, 'Mix' => true
unless max_duration == -1
after max_duration/1000 do
call.after max_duration/1000 do
ami_client.send_action 'StopMonitor', 'Channel' => call.channel
end
end
Expand Down
Expand Up @@ -18,11 +18,10 @@ def execute_command(command)
end

def stop_by_redirect(complete_reason)
component_actor = current_actor
call.register_handler :ami, lambda { |e| e['SubEvent'] == 'Start' }, :name => 'AsyncAGI' do |event|
component_actor.async.send_complete_event complete_reason
send_complete_event complete_reason
end
call.async.redirect_back
call.redirect_back
end
end
end
Expand Down
6 changes: 2 additions & 4 deletions lib/punchblock/translator/dtmf_recognizer.rb
Expand Up @@ -23,6 +23,8 @@ def cache
end
end

include Celluloid

def initialize(responder, grammar, initial_timeout = nil, inter_digit_timeout = nil, terminator = nil)
@responder = responder
self.initial_timeout = initial_timeout || -1
Expand Down Expand Up @@ -68,10 +70,6 @@ def get_match
@matcher.match @buffer.dup
end

def after(*args, &block)
@responder.after *args, &block
end

def initial_timeout=(other)
raise OptionError, 'An initial timeout value that is negative (and not -1) is invalid.' if other < -1
@initial_timeout = other
Expand Down
2 changes: 1 addition & 1 deletion spec/punchblock/connection/asterisk_spec.rb
Expand Up @@ -60,7 +60,7 @@ module Connection
end

it 'shuts down the translator' do
subject.translator.async.should_receive(:shutdown).once
subject.translator.should_receive(:terminate).once
subject.stop
end
end
Expand Down

0 comments on commit f939eca

Please sign in to comment.