punchblock 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +5 -0
- data/lib/punchblock.rb +1 -1
- data/lib/punchblock/connection.rb +1 -0
- data/lib/punchblock/connection/asterisk.rb +0 -1
- data/lib/punchblock/connection/freeswitch.rb +49 -0
- data/lib/punchblock/event/offer.rb +1 -1
- data/lib/punchblock/translator.rb +5 -0
- data/lib/punchblock/translator/asterisk.rb +16 -28
- data/lib/punchblock/translator/asterisk/call.rb +4 -21
- data/lib/punchblock/translator/asterisk/component.rb +0 -5
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +0 -3
- data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +0 -1
- data/lib/punchblock/translator/asterisk/component/input.rb +7 -97
- data/lib/punchblock/translator/asterisk/component/output.rb +0 -4
- data/lib/punchblock/translator/asterisk/component/record.rb +0 -2
- data/lib/punchblock/translator/freeswitch.rb +153 -0
- data/lib/punchblock/translator/freeswitch/call.rb +265 -0
- data/lib/punchblock/translator/freeswitch/component.rb +92 -0
- data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +57 -0
- data/lib/punchblock/translator/freeswitch/component/flite_output.rb +17 -0
- data/lib/punchblock/translator/freeswitch/component/input.rb +29 -0
- data/lib/punchblock/translator/freeswitch/component/output.rb +56 -0
- data/lib/punchblock/translator/freeswitch/component/record.rb +79 -0
- data/lib/punchblock/translator/freeswitch/component/tts_output.rb +26 -0
- data/lib/punchblock/translator/input_component.rb +108 -0
- data/lib/punchblock/version.rb +1 -1
- data/punchblock.gemspec +3 -2
- data/spec/punchblock/connection/freeswitch_spec.rb +90 -0
- data/spec/punchblock/translator/asterisk/call_spec.rb +23 -2
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +3 -3
- data/spec/punchblock/translator/asterisk_spec.rb +1 -1
- data/spec/punchblock/translator/freeswitch/call_spec.rb +922 -0
- data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +279 -0
- data/spec/punchblock/translator/freeswitch/component/input_spec.rb +312 -0
- data/spec/punchblock/translator/freeswitch/component/output_spec.rb +369 -0
- data/spec/punchblock/translator/freeswitch/component/record_spec.rb +373 -0
- data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +285 -0
- data/spec/punchblock/translator/freeswitch/component_spec.rb +118 -0
- data/spec/punchblock/translator/freeswitch_spec.rb +597 -0
- data/spec/punchblock_spec.rb +11 -0
- data/spec/spec_helper.rb +1 -0
- metadata +52 -7
|
@@ -54,13 +54,11 @@ module Punchblock
|
|
|
54
54
|
when :unimrcp
|
|
55
55
|
send_ref
|
|
56
56
|
@call.send_agi_action! 'EXEC MRCPSynth', escaped_doc, mrcpsynth_options do |complete_event|
|
|
57
|
-
pb_logger.debug "MRCPSynth completed with #{complete_event}."
|
|
58
57
|
output_component.send_complete_event! success_reason
|
|
59
58
|
end
|
|
60
59
|
when :swift
|
|
61
60
|
send_ref
|
|
62
61
|
@call.send_agi_action! 'EXEC Swift', swift_doc do |complete_event|
|
|
63
|
-
pb_logger.debug "Swift completed with #{complete_event}."
|
|
64
62
|
output_component.send_complete_event! success_reason
|
|
65
63
|
end
|
|
66
64
|
end
|
|
@@ -89,10 +87,8 @@ module Punchblock
|
|
|
89
87
|
end
|
|
90
88
|
|
|
91
89
|
def playback(path)
|
|
92
|
-
pb_logger.debug "Playing an audio file (#{path}) via Playback"
|
|
93
90
|
op = current_actor
|
|
94
91
|
@call.send_agi_action! 'EXEC Playback', path do |complete_event|
|
|
95
|
-
pb_logger.debug "File playback completed with #{complete_event}. Sending complete event"
|
|
96
92
|
op.send_complete_event! success_reason
|
|
97
93
|
end
|
|
98
94
|
end
|
|
@@ -31,7 +31,6 @@ module Punchblock
|
|
|
31
31
|
send_ref
|
|
32
32
|
|
|
33
33
|
if @component_node.start_beep
|
|
34
|
-
pb_logger.debug "Playing a beep via STREAM FILE before recording"
|
|
35
34
|
@call.send_agi_action! 'STREAM FILE', 'beep', '""' do
|
|
36
35
|
component.signal! :beep_finished
|
|
37
36
|
end
|
|
@@ -41,7 +40,6 @@ module Punchblock
|
|
|
41
40
|
call.send_ami_action! 'Monitor', 'Channel' => call.channel, 'File' => filename, 'Format' => @format, 'Mix' => true
|
|
42
41
|
unless max_duration == -1
|
|
43
42
|
after max_duration/1000 do
|
|
44
|
-
pb_logger.trace "Max duration encountered, stopping recording"
|
|
45
43
|
call.send_ami_action! 'StopMonitor', 'Channel' => call.channel
|
|
46
44
|
end
|
|
47
45
|
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'celluloid'
|
|
4
|
+
require 'ruby_fs'
|
|
5
|
+
|
|
6
|
+
module Punchblock
|
|
7
|
+
module Translator
|
|
8
|
+
class Freeswitch
|
|
9
|
+
include Celluloid
|
|
10
|
+
include HasGuardedHandlers
|
|
11
|
+
|
|
12
|
+
extend ActiveSupport::Autoload
|
|
13
|
+
|
|
14
|
+
autoload :Call
|
|
15
|
+
autoload :Component
|
|
16
|
+
|
|
17
|
+
attr_reader :connection, :media_engine, :default_voice, :calls
|
|
18
|
+
|
|
19
|
+
trap_exit :actor_died
|
|
20
|
+
|
|
21
|
+
def initialize(connection, media_engine = nil, default_voice = nil)
|
|
22
|
+
@connection, @media_engine, @default_voice = connection, media_engine, default_voice
|
|
23
|
+
@calls, @components = {}, {}
|
|
24
|
+
setup_handlers
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def register_call(call)
|
|
28
|
+
@calls[call.id] ||= call
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def deregister_call(call)
|
|
32
|
+
@calls.delete call.id
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def call_with_id(call_id)
|
|
36
|
+
@calls[call_id]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def register_component(component)
|
|
40
|
+
@components[component.id] ||= component
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def component_with_id(component_id)
|
|
44
|
+
@components[component_id]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def setup_handlers
|
|
48
|
+
register_handler :es, RubyFS::Stream::Connected do
|
|
49
|
+
handle_pb_event Connection::Connected.new
|
|
50
|
+
throw :halt
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
register_handler :es, RubyFS::Stream::Disconnected do
|
|
54
|
+
throw :halt
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
register_handler :es, :event_name => 'CHANNEL_PARK' do |event|
|
|
58
|
+
throw :pass if es_event_known_call? event
|
|
59
|
+
call = Call.new event[:unique_id], current_actor, event.content.select { |k,v| k.to_s =~ /variable/ }, stream, @media_engine, @default_voice
|
|
60
|
+
link call
|
|
61
|
+
register_call call
|
|
62
|
+
call.send_offer!
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
register_handler :es, [:has_key?, :other_leg_unique_id] => true do |event|
|
|
66
|
+
call = call_with_id event[:other_leg_unique_id]
|
|
67
|
+
call.handle_es_event! event if call
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
register_handler :es, lambda { |event| es_event_known_call? event } do |event|
|
|
71
|
+
call = call_with_id event[:unique_id]
|
|
72
|
+
call.handle_es_event! event
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def stream
|
|
77
|
+
connection.stream
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def finalize
|
|
81
|
+
@calls.values.each(&:terminate)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def handle_es_event(event)
|
|
85
|
+
trigger_handler :es, event
|
|
86
|
+
end
|
|
87
|
+
exclusive :handle_es_event
|
|
88
|
+
|
|
89
|
+
def handle_pb_event(event)
|
|
90
|
+
connection.handle_event event
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def execute_command(command, options = {})
|
|
94
|
+
command.request!
|
|
95
|
+
|
|
96
|
+
command.target_call_id ||= options[:call_id]
|
|
97
|
+
command.component_id ||= options[:component_id]
|
|
98
|
+
|
|
99
|
+
if command.target_call_id
|
|
100
|
+
execute_call_command command
|
|
101
|
+
elsif command.component_id
|
|
102
|
+
execute_component_command command
|
|
103
|
+
else
|
|
104
|
+
execute_global_command command
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def execute_call_command(command)
|
|
109
|
+
if call = call_with_id(command.target_call_id)
|
|
110
|
+
call.execute_command! command
|
|
111
|
+
else
|
|
112
|
+
command.response = ProtocolError.new.setup :item_not_found, "Could not find a call with ID #{command.target_call_id}", command.target_call_id
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def execute_component_command(command)
|
|
117
|
+
if (component = component_with_id(command.component_id))
|
|
118
|
+
component.execute_command! command
|
|
119
|
+
else
|
|
120
|
+
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
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def execute_global_command(command)
|
|
125
|
+
case command
|
|
126
|
+
when Punchblock::Command::Dial
|
|
127
|
+
call = Call.new_link Punchblock.new_uuid, current_actor, nil, stream, @media_engine, @default_voice
|
|
128
|
+
register_call call
|
|
129
|
+
call.dial! command
|
|
130
|
+
else
|
|
131
|
+
command.response = ProtocolError.new.setup 'command-not-acceptable', "Did not understand command"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def actor_died(actor, reason)
|
|
136
|
+
return unless reason
|
|
137
|
+
pb_logger.error "A linked actor (#{actor.inspect}) died due to #{reason.inspect}"
|
|
138
|
+
if id = @calls.key(actor)
|
|
139
|
+
@calls.delete id
|
|
140
|
+
end_event = Punchblock::Event::End.new :target_call_id => id,
|
|
141
|
+
:reason => :error
|
|
142
|
+
handle_pb_event end_event
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
private
|
|
147
|
+
|
|
148
|
+
def es_event_known_call?(event)
|
|
149
|
+
event[:unique_id] && call_with_id(event[:unique_id])
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
module Translator
|
|
5
|
+
class Freeswitch
|
|
6
|
+
class Call
|
|
7
|
+
include HasGuardedHandlers
|
|
8
|
+
include Celluloid
|
|
9
|
+
include DeadActorSafety
|
|
10
|
+
|
|
11
|
+
HANGUP_CAUSE_TO_END_REASON = Hash.new :error
|
|
12
|
+
|
|
13
|
+
HANGUP_CAUSE_TO_END_REASON['USER_BUSY'] = :busy
|
|
14
|
+
|
|
15
|
+
%w{
|
|
16
|
+
NORMAL_CLEARING ORIGINATOR_CANCEL SYSTEM_SHUTDOWN MANAGER_REQUEST
|
|
17
|
+
BLIND_TRANSFER ATTENDED_TRANSFER PICKED_OFF NORMAL_UNSPECIFIED
|
|
18
|
+
}.each { |c| HANGUP_CAUSE_TO_END_REASON[c] = :hangup }
|
|
19
|
+
|
|
20
|
+
%w{
|
|
21
|
+
NO_USER_RESPONSE NO_ANSWER SUBSCRIBER_ABSENT ALLOTTED_TIMEOUT
|
|
22
|
+
MEDIA_TIMEOUT PROGRESS_TIMEOUT
|
|
23
|
+
}.each { |c| HANGUP_CAUSE_TO_END_REASON[c] = :timeout }
|
|
24
|
+
|
|
25
|
+
%w{CALL_REJECTED NUMBER_CHANGED
|
|
26
|
+
REDIRECTION_TO_NEW_DESTINATION FACILITY_REJECTED NORMAL_CIRCUIT_CONGESTION
|
|
27
|
+
SWITCH_CONGESTION USER_NOT_REGISTERED FACILITY_NOT_SUBSCRIBED
|
|
28
|
+
OUTGOING_CALL_BARRED INCOMING_CALL_BARRED BEARERCAPABILITY_NOTAUTH
|
|
29
|
+
BEARERCAPABILITY_NOTAVAIL SERVICE_UNAVAILABLE BEARERCAPABILITY_NOTIMPL
|
|
30
|
+
CHAN_NOT_IMPLEMENTED FACILITY_NOT_IMPLEMENTED SERVICE_NOT_IMPLEMENTED
|
|
31
|
+
}.each { |c| HANGUP_CAUSE_TO_END_REASON[c] = :reject }
|
|
32
|
+
|
|
33
|
+
REJECT_TO_HANGUP_REASON = Hash.new 'NORMAL_TEMPORARY_FAILURE'
|
|
34
|
+
REJECT_TO_HANGUP_REASON.merge! :busy => 'USER_BUSY', :decline => 'CALL_REJECTED'
|
|
35
|
+
|
|
36
|
+
attr_reader :id, :translator, :es_env, :direction, :stream, :media_engine, :default_voice
|
|
37
|
+
|
|
38
|
+
trap_exit :actor_died
|
|
39
|
+
|
|
40
|
+
def initialize(id, translator, es_env = nil, stream = nil, media_engine = nil, default_voice = nil)
|
|
41
|
+
@id, @translator, @stream, @media_engine, @default_voice = id, translator, stream, media_engine, default_voice
|
|
42
|
+
@es_env = es_env || {}
|
|
43
|
+
@components = {}
|
|
44
|
+
@pending_joins, @pending_unjoins = {}, {}
|
|
45
|
+
@answered = false
|
|
46
|
+
setup_handlers
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def register_component(component)
|
|
50
|
+
@components[component.id] ||= component
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def component_with_id(component_id)
|
|
54
|
+
@components[component_id]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def send_offer
|
|
58
|
+
@direction = :inbound
|
|
59
|
+
send_pb_event offer_event
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def to_s
|
|
63
|
+
"#<#{self.class}:#{id}>"
|
|
64
|
+
end
|
|
65
|
+
alias :inspect :to_s
|
|
66
|
+
|
|
67
|
+
def setup_handlers
|
|
68
|
+
register_handler :es, :event_name => 'CHANNEL_ANSWER' do
|
|
69
|
+
@answered = true
|
|
70
|
+
send_pb_event Event::Answered.new
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
register_handler :es, :event_name => 'CHANNEL_STATE', [:[], :channel_call_state] => 'RINGING' do
|
|
74
|
+
send_pb_event Event::Ringing.new
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
register_handler :es, :event_name => 'CHANNEL_HANGUP' do |event|
|
|
78
|
+
@components.dup.each_pair do |id, component|
|
|
79
|
+
safe_from_dead_actors do
|
|
80
|
+
component.call_ended if component.alive?
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
send_end_event HANGUP_CAUSE_TO_END_REASON[event[:hangup_cause]]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
register_handler :es, :event_name => 'CHANNEL_BRIDGE' do |event|
|
|
87
|
+
command = @pending_joins[event[:other_leg_unique_id]]
|
|
88
|
+
command.response = true if command
|
|
89
|
+
|
|
90
|
+
other_call_id = event[:unique_id] == id ? event[:other_leg_unique_id] : event[:unique_id]
|
|
91
|
+
send_pb_event Event::Joined.new(:call_id => other_call_id)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
register_handler :es, :event_name => 'CHANNEL_UNBRIDGE' do |event|
|
|
95
|
+
command = @pending_unjoins[event[:other_leg_unique_id]]
|
|
96
|
+
command.response = true if command
|
|
97
|
+
|
|
98
|
+
other_call_id = event[:unique_id] == id ? event[:other_leg_unique_id] : event[:unique_id]
|
|
99
|
+
send_pb_event Event::Unjoined.new(:call_id => other_call_id)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
register_handler :es, [:has_key?, :scope_variable_punchblock_component_id] => true do |event|
|
|
104
|
+
if component = component_with_id(event[:scope_variable_punchblock_component_id])
|
|
105
|
+
safe_from_dead_actors { component.handle_es_event event }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def handle_es_event(event)
|
|
111
|
+
trigger_handler :es, event
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def application(*args)
|
|
115
|
+
stream.application id, *args
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def sendmsg(*args)
|
|
119
|
+
stream.sendmsg id, *args
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def uuid_foo(app, args = '')
|
|
123
|
+
stream.bgapi "uuid_#{app} #{id} #{args}"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def dial(dial_command)
|
|
127
|
+
@direction = :outbound
|
|
128
|
+
|
|
129
|
+
cid_number, cid_name = dial_command.from, nil
|
|
130
|
+
dial_command.from.match(/(?<cid_name>.*) <(?<cid_number>.*)>/) do |m|
|
|
131
|
+
cid_name = m[:cid_name]
|
|
132
|
+
cid_number = m[:cid_number]
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
options = {
|
|
136
|
+
:return_ring_ready => true,
|
|
137
|
+
:origination_uuid => id,
|
|
138
|
+
:origination_caller_id_number => "'#{cid_number}'"
|
|
139
|
+
}
|
|
140
|
+
options[:origination_caller_id_name] = "'#{cid_name}'" if cid_name
|
|
141
|
+
options[:originate_timeout] = dial_command.timeout/1000 if dial_command.timeout
|
|
142
|
+
opts = options.inject([]) do |a, (k, v)|
|
|
143
|
+
a << "#{k}=#{v}"
|
|
144
|
+
end.join(',')
|
|
145
|
+
|
|
146
|
+
stream.bgapi "originate {#{opts}}#{dial_command.to} &park()"
|
|
147
|
+
|
|
148
|
+
dial_command.response = Ref.new :id => id
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def outbound?
|
|
152
|
+
direction == :outbound
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def inbound?
|
|
156
|
+
direction == :inbound
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def answered?
|
|
160
|
+
@answered
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def execute_command(command)
|
|
164
|
+
if command.component_id
|
|
165
|
+
if component = component_with_id(command.component_id)
|
|
166
|
+
component.execute_command command
|
|
167
|
+
else
|
|
168
|
+
command.response = ProtocolError.new.setup :item_not_found, "Could not find a component with ID #{command.component_id} for call #{id}", id, command.component_id
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
case command
|
|
172
|
+
when Command::Accept
|
|
173
|
+
application 'respond', '180 Ringing'
|
|
174
|
+
command.response = true
|
|
175
|
+
when Command::Answer
|
|
176
|
+
command_id = Punchblock.new_uuid
|
|
177
|
+
register_tmp_handler :es, :event_name => 'CHANNEL_ANSWER', [:[], :scope_variable_punchblock_command_id] => command_id do
|
|
178
|
+
@answered = true
|
|
179
|
+
command.response = true
|
|
180
|
+
end
|
|
181
|
+
application 'answer', "%[punchblock_command_id=#{command_id}]"
|
|
182
|
+
when Command::Hangup
|
|
183
|
+
hangup
|
|
184
|
+
command.response = true
|
|
185
|
+
when Command::Join
|
|
186
|
+
@pending_joins[command.call_id] = command
|
|
187
|
+
uuid_foo :bridge, command.call_id
|
|
188
|
+
when Command::Unjoin
|
|
189
|
+
@pending_unjoins[command.call_id] = command
|
|
190
|
+
uuid_foo :transfer, '-both park inline'
|
|
191
|
+
when Command::Reject
|
|
192
|
+
hangup REJECT_TO_HANGUP_REASON[command.reason]
|
|
193
|
+
command.response = true
|
|
194
|
+
when Punchblock::Component::Output
|
|
195
|
+
case media_engine
|
|
196
|
+
when :freeswitch, :native, nil
|
|
197
|
+
execute_component Component::Output, command
|
|
198
|
+
when :flite
|
|
199
|
+
execute_component Component::FliteOutput, command, media_engine, default_voice
|
|
200
|
+
else
|
|
201
|
+
execute_component Component::TTSOutput, command, media_engine, default_voice
|
|
202
|
+
end
|
|
203
|
+
when Punchblock::Component::Input
|
|
204
|
+
execute_component Component::Input, command
|
|
205
|
+
when Punchblock::Component::Record
|
|
206
|
+
execute_component Component::Record, command
|
|
207
|
+
else
|
|
208
|
+
command.response = ProtocolError.new.setup 'command-not-acceptable', "Did not understand command for call #{id}", id
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def hangup(reason = 'NORMAL_CLEARING')
|
|
213
|
+
sendmsg :call_command => 'hangup', :hangup_cause => reason
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def logger_id
|
|
217
|
+
"#{self.class}: #{id}"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def actor_died(actor, reason)
|
|
221
|
+
return unless reason
|
|
222
|
+
pb_logger.error "A linked actor (#{actor.inspect}) died due to #{reason.inspect}"
|
|
223
|
+
if id = @components.key(actor)
|
|
224
|
+
@components.delete id
|
|
225
|
+
complete_event = Punchblock::Event::Complete.new :component_id => id, :reason => Punchblock::Event::Complete::Error.new
|
|
226
|
+
send_pb_event complete_event
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
private
|
|
231
|
+
|
|
232
|
+
def send_end_event(reason)
|
|
233
|
+
send_pb_event Event::End.new(:reason => reason)
|
|
234
|
+
translator.deregister_call current_actor
|
|
235
|
+
after(5) { terminate }
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def execute_component(type, command, *execute_args)
|
|
239
|
+
type.new_link(command, current_actor).tap do |component|
|
|
240
|
+
register_component component
|
|
241
|
+
component.execute!(*execute_args)
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def send_pb_event(event)
|
|
246
|
+
event.target_call_id = id
|
|
247
|
+
translator.handle_pb_event event
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def offer_event
|
|
251
|
+
Event::Offer.new :to => es_env[:variable_sip_to_uri],
|
|
252
|
+
:from => "#{es_env[:variable_effective_caller_id_name]} <#{es_env[:variable_sip_from_uri]}>",
|
|
253
|
+
:headers => headers
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def headers
|
|
257
|
+
es_env.to_a.inject({}) do |accumulator, element|
|
|
258
|
+
accumulator[('x_' + element[0].to_s).to_sym] = element[1] || ''
|
|
259
|
+
accumulator
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|