Class: RubyAsterisk::AMI::Promise

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-asterisk/ami/promise.rb

Overview

Thread-safe promise representing a pending AMI command response.

Created by Client#execute and resolved by the event-loop thread when the matching ActionID response arrives from Asterisk.

Usage (blocking):

promise = client.ping
response = promise.value(5)   # blocks up to 5 s, returns a Response

Usage (async):

promise = client.ping         # returns immediately
# ... do other work ...
response = promise.value      # blocks until resolved or timeout

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(action_id:, command_type:, timeout: 5) ⇒ Promise



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/ruby-asterisk/ami/promise.rb', line 34

def initialize(action_id:, command_type:, timeout: 5)
  @action_id    = action_id
  @command_type = command_type
  @timeout      = timeout
  @mutex        = Mutex.new
  @cv           = ConditionVariable.new
  @raw          = nil
  @error        = nil
  @resolved     = false
  @on_timeout   = nil
end

Instance Attribute Details

#action_idObject (readonly)

Returns the value of attribute action_id.



24
25
26
# File 'lib/ruby-asterisk/ami/promise.rb', line 24

def action_id
  @action_id
end

#on_timeoutObject

Optional callback invoked when #value gives up on a timeout, used by the Reactor to drop the abandoned entry from its pending map.



28
29
30
# File 'lib/ruby-asterisk/ami/promise.rb', line 28

def on_timeout
  @on_timeout
end

Instance Method Details

#reject(error) ⇒ Object

Reject the promise with an error. Called when the connection drops or the client disconnects.



62
63
64
65
66
67
68
# File 'lib/ruby-asterisk/ami/promise.rb', line 62

def reject(error)
  @mutex.synchronize do
    @error    = error
    @resolved = true
    @cv.broadcast
  end
end

#resolve(raw) ⇒ Object

Resolve the promise with raw AMI response data. Called by the Client event-loop thread — safe to call from any thread.



50
51
52
53
54
55
56
# File 'lib/ruby-asterisk/ami/promise.rb', line 50

def resolve(raw)
  @mutex.synchronize do
    @raw      = raw
    @resolved = true
    @cv.broadcast
  end
end

#resolved?Boolean



94
95
96
# File 'lib/ruby-asterisk/ami/promise.rb', line 94

def resolved?
  @mutex.synchronize { @resolved }
end

#value(timeout = @timeout) ⇒ RubyAsterisk::Response

Block until the response arrives and return it as a Response.

Raises:

  • (Timeout::Error)

    if no response arrives within timeout seconds

  • (RuntimeError)

    if the promise was rejected (e.g. disconnect)



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/ruby-asterisk/ami/promise.rb', line 77

def value(timeout = @timeout)
  @mutex.synchronize do
    unless @resolved
      @cv.wait(@mutex, timeout)
      unless @resolved
        @on_timeout&.call
        raise Timeout::Error,
              "Timeout waiting for AMI response (ActionID: #{@action_id})"
      end
    end
    raise @error if @error

    build_response
  end
end