signalwire 1.4.0 → 2.0.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.
- checksums.yaml +4 -4
- data/.gitignore +55 -0
- data/.rubocop.yml +14 -2
- data/AUTHORS.md +1 -0
- data/CHANGELOG.md +30 -5
- data/Gemfile +4 -18
- data/LICENSE +21 -0
- data/README.md +22 -82
- data/Rakefile +0 -17
- data/examples/relay/inbound_consumer.rb +26 -0
- data/examples/relay/inbound_dial.rb +28 -0
- data/examples/relay/outbound_collect.rb +27 -0
- data/examples/relay/outbound_consumer.rb +22 -0
- data/examples/relay/outbound_record.rb +25 -0
- data/lib/signalwire.rb +13 -0
- data/lib/signalwire/blade.rb +12 -0
- data/lib/signalwire/blade/connection.rb +200 -0
- data/lib/signalwire/blade/event_handler.rb +15 -0
- data/lib/signalwire/blade/message.rb +38 -0
- data/lib/signalwire/blade/message/connect.rb +18 -0
- data/lib/signalwire/blade/message/execute.rb +16 -0
- data/lib/signalwire/blade/message/subscribe.rb +15 -0
- data/lib/signalwire/common.rb +6 -0
- data/lib/signalwire/logger.rb +27 -0
- data/lib/signalwire/relay.rb +40 -0
- data/lib/signalwire/relay/calling.rb +82 -0
- data/lib/signalwire/relay/calling/action.rb +16 -0
- data/lib/signalwire/relay/calling/action/connect_action.rb +11 -0
- data/lib/signalwire/relay/calling/action/play_action.rb +15 -0
- data/lib/signalwire/relay/calling/action/prompt_action.rb +15 -0
- data/lib/signalwire/relay/calling/action/record_action.rb +15 -0
- data/lib/signalwire/relay/calling/call.rb +210 -0
- data/lib/signalwire/relay/calling/call_convenience_methods.rb +79 -0
- data/lib/signalwire/relay/calling/component.rb +115 -0
- data/lib/signalwire/relay/calling/component/answer.rb +27 -0
- data/lib/signalwire/relay/calling/component/await.rb +20 -0
- data/lib/signalwire/relay/calling/component/connect.rb +45 -0
- data/lib/signalwire/relay/calling/component/dial.rb +34 -0
- data/lib/signalwire/relay/calling/component/hangup.rb +41 -0
- data/lib/signalwire/relay/calling/component/play.rb +46 -0
- data/lib/signalwire/relay/calling/component/prompt.rb +62 -0
- data/lib/signalwire/relay/calling/component/record.rb +53 -0
- data/lib/signalwire/relay/calling/control_component.rb +35 -0
- data/lib/signalwire/relay/calling/result.rb +16 -0
- data/lib/signalwire/relay/calling/result/answer_result.rb +6 -0
- data/lib/signalwire/relay/calling/result/connect_result.rb +9 -0
- data/lib/signalwire/relay/calling/result/dial_result.rb +7 -0
- data/lib/signalwire/relay/calling/result/hangup_result.rb +7 -0
- data/lib/signalwire/relay/calling/result/play_result.rb +6 -0
- data/lib/signalwire/relay/calling/result/prompt_result.rb +11 -0
- data/lib/signalwire/relay/calling/result/record_result.rb +7 -0
- data/lib/signalwire/relay/client.rb +147 -0
- data/lib/signalwire/relay/constants.rb +109 -0
- data/lib/signalwire/relay/consumer.rb +88 -0
- data/lib/signalwire/relay/event.rb +41 -0
- data/lib/signalwire/relay/request.rb +6 -0
- data/lib/signalwire/rest/client.rb +5 -5
- data/lib/signalwire/sdk/fax_response.rb +3 -3
- data/lib/signalwire/sdk/messaging_response.rb +0 -2
- data/lib/signalwire/sdk/twilio_set_fax.rb +9 -8
- data/lib/signalwire/sdk/twilio_set_host.rb +8 -3
- data/lib/signalwire/version.rb +5 -0
- data/signalwire.gemspec +36 -106
- metadata +173 -76
- data/LICENSE.txt +0 -20
- data/VERSION +0 -1
- data/spec/signalwire/rest/client_spec.rb +0 -30
- data/spec/signalwire/rest/integration_spec.rb +0 -102
- data/spec/signalwire/sdk/configuration_spec.rb +0 -28
- data/spec/signalwire/sdk/fax_response_spec.rb +0 -26
- data/spec/signalwire/sdk/messaging_response_spec.rb +0 -18
- data/spec/signalwire/sdk/voice_response_spec.rb +0 -20
- data/spec/signalwire/sdk_spec.rb +0 -27
- data/spec/spec_helper.rb +0 -119
- data/spec/vcr_cassettes/accounts.yml +0 -27
- data/spec/vcr_cassettes/applications.yml +0 -29
- data/spec/vcr_cassettes/get_fax.yml +0 -25
- data/spec/vcr_cassettes/get_fax_media_instance.yml +0 -27
- data/spec/vcr_cassettes/get_fax_media_list.yml +0 -47
- data/spec/vcr_cassettes/list_faxes.yml +0 -25
- data/spec/vcr_cassettes/local_numbers.yml +0 -26
- data/spec/vcr_cassettes/recordings.yml +0 -27
- data/spec/vcr_cassettes/send_fax.yml +0 -27
- data/spec/vcr_cassettes/toll_free_numbers.yml +0 -34
- data/spec/vcr_cassettes/transcriptions.yml +0 -28
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
|
4
|
+
%w[
|
|
5
|
+
bundler/setup
|
|
6
|
+
signalwire
|
|
7
|
+
].each { |f| require f }
|
|
8
|
+
|
|
9
|
+
# Set logging to debug for testing
|
|
10
|
+
Signalwire::Logger.logger.level = ::Logger::DEBUG
|
|
11
|
+
|
|
12
|
+
class OutboundConsumer < Signalwire::Relay::Consumer
|
|
13
|
+
def ready
|
|
14
|
+
logger.info 'Dialing out'
|
|
15
|
+
call = client.calling.new_call(from: ENV['FROM_NUMBER'], to: ENV['TO_NUMBER'])
|
|
16
|
+
call.dial
|
|
17
|
+
call.play_tts 'please leave your message after the beep. Press pound when done.'
|
|
18
|
+
result = call.record({"audio": { "beep": "true", "terminators": "#"}})
|
|
19
|
+
call.play_tts 'you said:'
|
|
20
|
+
call.play_audio result.url
|
|
21
|
+
call.hangup
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
OutboundConsumer.new.run
|
data/lib/signalwire.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Signalwire::Blade
|
|
4
|
+
RECONNECT_PERIOD = 5
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'signalwire/blade/event_handler'
|
|
8
|
+
require 'signalwire/blade/connection'
|
|
9
|
+
require 'signalwire/blade/message'
|
|
10
|
+
require 'signalwire/blade/message/connect'
|
|
11
|
+
require 'signalwire/blade/message/execute'
|
|
12
|
+
require 'signalwire/blade/message/subscribe'
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'has_guarded_handlers'
|
|
4
|
+
require 'eventmachine'
|
|
5
|
+
require 'faye/websocket'
|
|
6
|
+
require 'json'
|
|
7
|
+
|
|
8
|
+
module Signalwire::Blade
|
|
9
|
+
class Connection
|
|
10
|
+
include Signalwire::Logger
|
|
11
|
+
include Signalwire::Blade::EventHandler
|
|
12
|
+
include Signalwire::Common
|
|
13
|
+
|
|
14
|
+
attr_reader :session_id, :connected, :node_id, :connection
|
|
15
|
+
|
|
16
|
+
def initialize(**options)
|
|
17
|
+
@options = options
|
|
18
|
+
@session_id = nil
|
|
19
|
+
@node_id = nil
|
|
20
|
+
@connected = false
|
|
21
|
+
@url = @options.fetch(:url, 'wss://relay.signalwire.com')
|
|
22
|
+
@log_traffic = options.fetch(:log_traffic, true)
|
|
23
|
+
@authentication = options.fetch(:authentication, nil)
|
|
24
|
+
|
|
25
|
+
@inbound_queue = EM::Queue.new
|
|
26
|
+
@outbound_queue = EM::Queue.new
|
|
27
|
+
|
|
28
|
+
@counter = 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def connect!
|
|
32
|
+
setup_started_event
|
|
33
|
+
enable_epoll
|
|
34
|
+
handle_signals
|
|
35
|
+
|
|
36
|
+
main_loop!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def reconnect!
|
|
40
|
+
return if @shutdown
|
|
41
|
+
sleep Signalwire::Blade::RECONNECT_PERIOD
|
|
42
|
+
@connected = false
|
|
43
|
+
logger.info "Attempting reconnection"
|
|
44
|
+
main_loop!
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def main_loop!
|
|
48
|
+
EM.run do
|
|
49
|
+
@ws = Faye::WebSocket::Client.new(@url)
|
|
50
|
+
|
|
51
|
+
@ws.on(:open) { |event| broadcast :started, event }
|
|
52
|
+
@ws.on(:message) { |event| enqueue_inbound event }
|
|
53
|
+
@ws.on(:close) { handle_close }
|
|
54
|
+
|
|
55
|
+
@ws.on :error do |error|
|
|
56
|
+
logger.error "Error occurred: #{error.message}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
EM.next_tick { flush_queues }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def setup_started_event
|
|
64
|
+
on :started do |_event|
|
|
65
|
+
@connected = true
|
|
66
|
+
myreq = connect_request
|
|
67
|
+
start_periodic_timer
|
|
68
|
+
|
|
69
|
+
write_command(myreq) do |event|
|
|
70
|
+
@session_id = event.dig(:result, :sessionid) unless @session_id
|
|
71
|
+
@node_id = event.dig(:result, :nodeid) unless @node_d
|
|
72
|
+
logger.info "Blade Session connected with id: #{@session_id}"
|
|
73
|
+
broadcast :connected, event
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
rescue StandardError => e
|
|
77
|
+
logger.error e.inspect
|
|
78
|
+
logger.error e.backtrace
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def enable_epoll
|
|
83
|
+
# This is only enabled on Linux
|
|
84
|
+
EM.epoll
|
|
85
|
+
logger.debug "Running with epoll #{EM.epoll?}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def transmit(message)
|
|
89
|
+
enqueue_outbound message
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def write(message)
|
|
93
|
+
log_traffic :send, message
|
|
94
|
+
@ws.send(message)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def receive(message)
|
|
98
|
+
event = Message.from_json(message.data)
|
|
99
|
+
log_traffic :recv, event.payload
|
|
100
|
+
EM.defer do
|
|
101
|
+
broadcast :message, event
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def write_command(command, &block)
|
|
106
|
+
once(:message, id: command.id, &block) if block_given?
|
|
107
|
+
transmit(command.build_request.to_json)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def execute(params, &block)
|
|
111
|
+
block_given? ? write_command(Execute.new(params), &block) : write_command(Execute.new(params))
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def subscribe(params, &block)
|
|
115
|
+
block_given? ? write_command(Subscribe.new(params), &block) : write_command(Subscribe.new(params))
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def handle_close
|
|
119
|
+
reconnect!
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def disconnect!
|
|
123
|
+
# logger.info 'Stopping Blade event loop'
|
|
124
|
+
@ws = nil
|
|
125
|
+
@connected = false
|
|
126
|
+
EM.stop
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def flush_queues
|
|
130
|
+
@inbound_queue.pop { |inbound| receive(inbound) } until @inbound_queue.empty?
|
|
131
|
+
if connected?
|
|
132
|
+
@outbound_queue.pop { |outbound| write(outbound) } until @outbound_queue.empty?
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
EM.next_tick { flush_queues }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def enqueue_inbound(message)
|
|
139
|
+
@inbound_queue.push message
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def enqueue_outbound(message)
|
|
143
|
+
@outbound_queue.push message
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def connect_request
|
|
147
|
+
req = Connect.new
|
|
148
|
+
req[:params][:authentication] = @authentication if @authentication
|
|
149
|
+
req
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def connected?
|
|
153
|
+
@connected == true
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def start_periodic_timer
|
|
157
|
+
pinger = EventMachine::PeriodicTimer.new(Signalwire::Relay::PING_TIMEOUT) do
|
|
158
|
+
timeouter = EventMachine::Timer.new(2) do
|
|
159
|
+
# reconnect logic goes here
|
|
160
|
+
logger.error "We got disconnected!"
|
|
161
|
+
pinger.cancel
|
|
162
|
+
reconnect!
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
@ws.ping 'detecting presence' do
|
|
166
|
+
timeouter.cancel
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def log_traffic(direction, message)
|
|
172
|
+
if @log_traffic
|
|
173
|
+
pretty = case direction
|
|
174
|
+
when :send
|
|
175
|
+
JSON.pretty_generate(JSON.parse(message))
|
|
176
|
+
when :recv
|
|
177
|
+
JSON.pretty_generate(message)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
logger.debug "#{direction.to_s.upcase}: #{pretty}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def handle_signals
|
|
184
|
+
Signal.trap('INT') do
|
|
185
|
+
shutdown_from_signal
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
Signal.trap('TERM') do
|
|
189
|
+
shutdown_from_signal
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def shutdown_from_signal
|
|
195
|
+
@shutdown = true
|
|
196
|
+
disconnect!
|
|
197
|
+
exit
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'has_guarded_handlers'
|
|
4
|
+
|
|
5
|
+
module Signalwire::Blade
|
|
6
|
+
module EventHandler
|
|
7
|
+
include HasGuardedHandlers
|
|
8
|
+
alias on register_handler
|
|
9
|
+
alias once register_tmp_handler
|
|
10
|
+
|
|
11
|
+
def broadcast(event_type, event)
|
|
12
|
+
trigger_handler event_type, event, broadcast: true
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Signalwire::Blade
|
|
6
|
+
class Message
|
|
7
|
+
extend Forwardable
|
|
8
|
+
def_delegators :@payload, :[], :[]=, :dig
|
|
9
|
+
|
|
10
|
+
def initialize(params = {})
|
|
11
|
+
@payload = params
|
|
12
|
+
@id = params[:id]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def id
|
|
16
|
+
@id ||= SecureRandom.uuid
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def payload
|
|
20
|
+
@payload ||= {}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def build_request
|
|
24
|
+
payload.merge(
|
|
25
|
+
jsonrpc: '2.0',
|
|
26
|
+
id: id
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.from_json(json_hash)
|
|
31
|
+
new JSON.parse(json_hash, symbolize_names: true)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_s
|
|
35
|
+
inspect
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Signalwire::Blade
|
|
4
|
+
class Connect < Message
|
|
5
|
+
def initialize
|
|
6
|
+
@payload = {
|
|
7
|
+
method: 'blade.connect',
|
|
8
|
+
params: {
|
|
9
|
+
version: {
|
|
10
|
+
major: 2,
|
|
11
|
+
minor: 1,
|
|
12
|
+
revision: 0
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Signalwire::Blade
|
|
4
|
+
class Execute < Message
|
|
5
|
+
# Creates an Execute message
|
|
6
|
+
#
|
|
7
|
+
# @param params [Hash] The "params" portion of the execute
|
|
8
|
+
def initialize(params = {})
|
|
9
|
+
@payload =
|
|
10
|
+
{
|
|
11
|
+
method: 'blade.execute',
|
|
12
|
+
params: params
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Signalwire::Blade
|
|
4
|
+
class Subscribe < Message
|
|
5
|
+
# Creates a Subscribe message
|
|
6
|
+
#
|
|
7
|
+
# @param params [Hash] The "params" portion of the message
|
|
8
|
+
def initialize(params = {})
|
|
9
|
+
@payload = {
|
|
10
|
+
method: 'blade.subscription',
|
|
11
|
+
params: params
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'logger'
|
|
4
|
+
|
|
5
|
+
module Signalwire
|
|
6
|
+
module Logger
|
|
7
|
+
class << self
|
|
8
|
+
# A global logger object
|
|
9
|
+
# @return [Logger] a Logger instance
|
|
10
|
+
def logger
|
|
11
|
+
@logger ||= begin
|
|
12
|
+
logger = ::Logger.new(STDERR, progname: 'SignalWire', level: ::Logger::DEBUG)
|
|
13
|
+
logger.level = ENV.fetch('SIGNALWIRE_LOG_LEVEL', ::Logger::WARN)
|
|
14
|
+
logger
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def logger
|
|
20
|
+
Signalwire::Logger.logger
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def level=(level)
|
|
24
|
+
Signalwire::Logger.logger.level = level
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Signalwire::Relay
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
require 'signalwire/relay/constants'
|
|
7
|
+
require 'signalwire/relay/client'
|
|
8
|
+
require 'signalwire/relay/request'
|
|
9
|
+
require 'signalwire/relay/event'
|
|
10
|
+
require 'signalwire/relay/consumer'
|
|
11
|
+
|
|
12
|
+
require 'signalwire/relay/calling'
|
|
13
|
+
require 'signalwire/relay/calling/call_convenience_methods'
|
|
14
|
+
require 'signalwire/relay/calling/call'
|
|
15
|
+
|
|
16
|
+
require 'signalwire/relay/calling/action'
|
|
17
|
+
require 'signalwire/relay/calling/action/connect_action'
|
|
18
|
+
require 'signalwire/relay/calling/action/play_action'
|
|
19
|
+
require 'signalwire/relay/calling/action/prompt_action'
|
|
20
|
+
require 'signalwire/relay/calling/action/record_action'
|
|
21
|
+
|
|
22
|
+
require 'signalwire/relay/calling/result'
|
|
23
|
+
require 'signalwire/relay/calling/result/answer_result'
|
|
24
|
+
require 'signalwire/relay/calling/result/connect_result'
|
|
25
|
+
require 'signalwire/relay/calling/result/dial_result'
|
|
26
|
+
require 'signalwire/relay/calling/result/hangup_result'
|
|
27
|
+
require 'signalwire/relay/calling/result/play_result'
|
|
28
|
+
require 'signalwire/relay/calling/result/prompt_result'
|
|
29
|
+
require 'signalwire/relay/calling/result/record_result'
|
|
30
|
+
|
|
31
|
+
require 'signalwire/relay/calling/component'
|
|
32
|
+
require 'signalwire/relay/calling/control_component'
|
|
33
|
+
require 'signalwire/relay/calling/component/answer'
|
|
34
|
+
require 'signalwire/relay/calling/component/connect'
|
|
35
|
+
require 'signalwire/relay/calling/component/dial'
|
|
36
|
+
require 'signalwire/relay/calling/component/hangup'
|
|
37
|
+
require 'signalwire/relay/calling/component/play'
|
|
38
|
+
require 'signalwire/relay/calling/component/prompt'
|
|
39
|
+
require 'signalwire/relay/calling/component/record'
|
|
40
|
+
require 'signalwire/relay/calling/component/await'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
require 'concurrent-ruby'
|
|
5
|
+
|
|
6
|
+
module Signalwire::Relay
|
|
7
|
+
module Calling
|
|
8
|
+
class Instance
|
|
9
|
+
extend Forwardable
|
|
10
|
+
include Signalwire::Logger
|
|
11
|
+
include Signalwire::Common
|
|
12
|
+
|
|
13
|
+
def_delegators :@client, :relay_execute, :protocol, :on, :once, :broadcast
|
|
14
|
+
|
|
15
|
+
def initialize(client)
|
|
16
|
+
@client = client
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def calls
|
|
20
|
+
@calls ||= Concurrent::Array.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def contexts
|
|
24
|
+
@contexts ||= Concurrent::Array.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def receive(context:, &block)
|
|
28
|
+
@client.on :event, event_type: 'calling.call.receive' do |event|
|
|
29
|
+
logger.info "Starting up call for #{event.call_params}"
|
|
30
|
+
call_obj = Signalwire::Relay::Calling::Call.from_event(self, event)
|
|
31
|
+
calls << call_obj
|
|
32
|
+
block.call(call_obj) if block_given?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
receive_command = {
|
|
36
|
+
protocol: protocol,
|
|
37
|
+
method: 'call.receive',
|
|
38
|
+
params: {
|
|
39
|
+
context: context
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
relay_execute receive_command do
|
|
44
|
+
contexts << context
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def find_call_by_id(call_id)
|
|
49
|
+
calls.find { |call| call.id == call_id }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def find_call_by_tag(tag)
|
|
53
|
+
calls.find { |call| call.tag == tag }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def end_call(call_id)
|
|
57
|
+
calls.delete find_call_by_id(call_id)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def new_call(from:, to:, device_type: 'phone', timeout: 30)
|
|
61
|
+
params = {
|
|
62
|
+
device: {
|
|
63
|
+
type: device_type,
|
|
64
|
+
params: {
|
|
65
|
+
from_number: from,
|
|
66
|
+
to_number: to,
|
|
67
|
+
timeout: timeout
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
call = Call.new(self, params)
|
|
72
|
+
calls << call
|
|
73
|
+
call
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def dial(from:, to:, device_type: 'phone', timeout: 30)
|
|
77
|
+
handle = new_call(from: from, to: to, device_type: device_type, timeout: timeout)
|
|
78
|
+
handle.dial
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|