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

Returns a new instance of Promise.

Parameters:

  • action_id (String)

    the AMI ActionID this promise tracks

  • command_type (String)

    the AMI action name (e.g. 'Ping')

  • timeout (Numeric, nil) (defaults to: 5)

    default seconds to wait in #value; nil waits indefinitely (used by WaitEvent with a negative Timeout)



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.

Parameters:

  • error (Exception)


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.

Parameters:

  • raw (String)

    the raw AMI response string



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

Returns true if the promise has been resolved or rejected.

Returns:

  • (Boolean)

    true if the promise has been resolved or rejected



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.

Parameters:

  • timeout (Numeric, nil) (defaults to: @timeout)

    seconds to wait (defaults to the value set at construction); nil blocks until the response arrives

Returns:

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