Class: Switest::Call
- Inherits:
-
Object
- Object
- Switest::Call
- Defined in:
- lib/switest/call.rb
Constant Summary collapse
- CALLSTATE_MAP =
{ "RINGING" => :ringing, "ACTIVE" => :answered }.freeze
Instance Attribute Summary collapse
-
#answer_time ⇒ Object
readonly
Returns the value of attribute answer_time.
-
#direction ⇒ Object
readonly
Returns the value of attribute direction.
-
#end_reason ⇒ Object
readonly
Returns the value of attribute end_reason.
-
#end_time ⇒ Object
readonly
Returns the value of attribute end_time.
-
#from ⇒ Object
readonly
Returns the value of attribute from.
-
#headers ⇒ Object
readonly
Returns the value of attribute headers.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#start_time ⇒ Object
readonly
Returns the value of attribute start_time.
-
#state ⇒ Object
readonly
Returns the value of attribute state.
-
#to ⇒ Object
readonly
Returns the value of attribute to.
Instance Method Summary collapse
- #active? ⇒ Boolean
-
#alive? ⇒ Boolean
State queries.
-
#answer(wait: 5) ⇒ Object
Actions.
- #answered? ⇒ Boolean
- #ended? ⇒ Boolean
- #flush_dtmf ⇒ Object
-
#handle_callstate(call_state) ⇒ Object
Internal state updates.
- #handle_dtmf(digit) ⇒ Object
-
#handle_event(response) ⇒ Object
Internal: dispatch a librevox Response event to the appropriate handler.
- #handle_hangup(cause, event_content = {}) ⇒ Object
- #hangup(cause = "NORMAL_CLEARING", wait: 5) ⇒ Object
- #inbound? ⇒ Boolean
-
#initialize(id:, direction:, to: nil, from: nil, headers: {}, session: nil) ⇒ Call
constructor
A new instance of Call.
- #outbound? ⇒ Boolean
- #play_audio(url, wait: true) ⇒ Object
- #receive_dtmf(count: 1, timeout: 5) ⇒ Object
- #reject(reason = :decline, wait: 5) ⇒ Object
- #send_dtmf(digits, wait: true) ⇒ Object
-
#wait_for_answer(timeout: 5) ⇒ Object
Blocking waits.
- #wait_for_end(timeout: 5) ⇒ Object
Constructor Details
#initialize(id:, direction:, to: nil, from: nil, headers: {}, session: nil) ⇒ Call
Returns a new instance of Call.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/switest/call.rb', line 15 def initialize(id:, direction:, to: nil, from: nil, headers: {}, session: nil) @id = id @session = session @direction = direction # :inbound or :outbound @to = to @from = from @headers = headers.is_a?(Hash) ? headers.dup : {} @state = :new @start_time = Time.now @answer_time = nil @end_time = nil @end_reason = nil @dtmf_queue = Async::Queue.new @answered_promise = Async::Promise.new @ended_promise = Async::Promise.new end |
Instance Attribute Details
#answer_time ⇒ Object (readonly)
Returns the value of attribute answer_time.
12 13 14 |
# File 'lib/switest/call.rb', line 12 def answer_time @answer_time end |
#direction ⇒ Object (readonly)
Returns the value of attribute direction.
11 12 13 |
# File 'lib/switest/call.rb', line 11 def direction @direction end |
#end_reason ⇒ Object (readonly)
Returns the value of attribute end_reason.
12 13 14 |
# File 'lib/switest/call.rb', line 12 def end_reason @end_reason end |
#end_time ⇒ Object (readonly)
Returns the value of attribute end_time.
12 13 14 |
# File 'lib/switest/call.rb', line 12 def end_time @end_time end |
#from ⇒ Object (readonly)
Returns the value of attribute from.
11 12 13 |
# File 'lib/switest/call.rb', line 11 def from @from end |
#headers ⇒ Object (readonly)
Returns the value of attribute headers.
11 12 13 |
# File 'lib/switest/call.rb', line 11 def headers @headers end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
11 12 13 |
# File 'lib/switest/call.rb', line 11 def id @id end |
#start_time ⇒ Object (readonly)
Returns the value of attribute start_time.
12 13 14 |
# File 'lib/switest/call.rb', line 12 def start_time @start_time end |
#state ⇒ Object (readonly)
Returns the value of attribute state.
13 14 15 |
# File 'lib/switest/call.rb', line 13 def state @state end |
#to ⇒ Object (readonly)
Returns the value of attribute to.
11 12 13 |
# File 'lib/switest/call.rb', line 11 def to @to end |
Instance Method Details
#active? ⇒ Boolean
40 41 42 |
# File 'lib/switest/call.rb', line 40 def active? @state == :answered end |
#alive? ⇒ Boolean
State queries
36 37 38 |
# File 'lib/switest/call.rb', line 36 def alive? @state != :ended end |
#answer(wait: 5) ⇒ Object
Actions
61 62 63 64 65 66 |
# File 'lib/switest/call.rb', line 61 def answer(wait: 5) return unless @state == :ringing && inbound? sendmsg("execute", "answer") return unless wait wait_for_answer(timeout: wait) end |
#answered? ⇒ Boolean
44 45 46 |
# File 'lib/switest/call.rb', line 44 def answered? @state == :answered end |
#ended? ⇒ Boolean
48 49 50 |
# File 'lib/switest/call.rb', line 48 def ended? @state == :ended end |
#flush_dtmf ⇒ Object
93 94 95 |
# File 'lib/switest/call.rb', line 93 def flush_dtmf @dtmf_queue.dequeue until @dtmf_queue.empty? end |
#handle_callstate(call_state) ⇒ Object
Internal state updates
149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/switest/call.rb', line 149 def handle_callstate(call_state) return if @state == :ended new_state = CALLSTATE_MAP[call_state] return if new_state.nil? || @state == new_state @state = new_state if new_state == :answered @answer_time = Time.now @answered_promise.resolve(true) end end |
#handle_dtmf(digit) ⇒ Object
179 180 181 |
# File 'lib/switest/call.rb', line 179 def handle_dtmf(digit) @dtmf_queue.enqueue(digit) end |
#handle_event(response) ⇒ Object
Internal: dispatch a librevox Response event to the appropriate handler.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/switest/call.rb', line 133 def handle_event(response) return unless response.event? case response.event when "CHANNEL_CALLSTATE" handle_callstate(response.content[:channel_call_state]) when "CHANNEL_HANGUP_COMPLETE" cause = response.content[:hangup_cause] handle_hangup(cause, response.content) when "DTMF" digit = response.content[:dtmf_digit] handle_dtmf(digit) if digit end end |
#handle_hangup(cause, event_content = {}) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/switest/call.rb', line 161 def handle_hangup(cause, event_content = {}) return if @state == :ended @state = :ended @end_time = Time.now @end_reason = cause # Merge event data into headers if event_content.is_a?(Hash) event_content.each do |k, v| next if k == :body @headers[k] = v.to_s end end @answered_promise.resolve(true) @ended_promise.resolve(true) end |
#hangup(cause = "NORMAL_CLEARING", wait: 5) ⇒ Object
68 69 70 71 72 73 |
# File 'lib/switest/call.rb', line 68 def hangup(cause = "NORMAL_CLEARING", wait: 5) return if ended? sendmsg("hangup", hangup_cause: cause) return unless wait wait_for_end(timeout: wait) end |
#inbound? ⇒ Boolean
52 53 54 |
# File 'lib/switest/call.rb', line 52 def inbound? @direction == :inbound end |
#outbound? ⇒ Boolean
56 57 58 |
# File 'lib/switest/call.rb', line 56 def outbound? @direction == :outbound end |
#play_audio(url, wait: true) ⇒ Object
85 86 87 |
# File 'lib/switest/call.rb', line 85 def play_audio(url, wait: true) sendmsg("execute", "playback", url, event_lock: wait) end |
#receive_dtmf(count: 1, timeout: 5) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/switest/call.rb', line 97 def receive_dtmf(count: 1, timeout: 5) digits = String.new deadline = Time.now + timeout count.times do remaining = deadline - Time.now break if remaining <= 0 Async::Task.current.with_timeout(remaining) do digits << @dtmf_queue.dequeue end rescue Async::TimeoutError break end digits end |
#reject(reason = :decline, wait: 5) ⇒ Object
75 76 77 78 79 80 81 82 83 |
# File 'lib/switest/call.rb', line 75 def reject(reason = :decline, wait: 5) return unless @state == :ringing && inbound? cause = case reason when :busy then "USER_BUSY" when :decline then "CALL_REJECTED" else "CALL_REJECTED" end hangup(cause, wait: wait) end |
#send_dtmf(digits, wait: true) ⇒ Object
89 90 91 |
# File 'lib/switest/call.rb', line 89 def send_dtmf(digits, wait: true) play_audio("tone_stream://d=200;w=250;#{digits}", wait: wait) end |
#wait_for_answer(timeout: 5) ⇒ Object
Blocking waits
116 117 118 119 120 121 122 |
# File 'lib/switest/call.rb', line 116 def wait_for_answer(timeout: 5) return true if answered? Async::Task.current.with_timeout(timeout) { @answered_promise.wait } answered? rescue Async::TimeoutError answered? end |
#wait_for_end(timeout: 5) ⇒ Object
124 125 126 127 128 129 130 |
# File 'lib/switest/call.rb', line 124 def wait_for_end(timeout: 5) return true if ended? Async::Task.current.with_timeout(timeout) { @ended_promise.wait } ended? rescue Async::TimeoutError ended? end |