Class: Freeswitch::ESL::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/freeswitch/esl/command.rb

Overview

Represents the asynchronous execution of a bgapi command.

A Command is created by Freeswitch::ESL::Client#exec and tracks the full lifecycle of the request: pending → completed (success or failure).

Async usage (non-blocking)

cmd = client.exec("originate", "sofia/default/[email protected]")
cmd.on_complete { |c| puts c.response.body }
# ... do other work ...
cmd.response  # blocks until completed (or timeout)

Sync usage (blocking)

cmd = client.exec("originate", "sofia/default/[email protected]")
cmd.wait
puts cmd.response.body

Timeout

The default timeout is DEFAULT_TIMEOUT seconds across client readiness, the bgapi acknowledgement and the result event. A timeout after submission does not establish whether FreeSWITCH executed the command. Late replies remain in the connection FIFO until consumed; late results are ignored.

Constant Summary collapse

DEFAULT_TIMEOUT =
60

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client, command, *args, timeout: DEFAULT_TIMEOUT, raise_error: true, &block) ⇒ Command

Returns a new instance of Command.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/freeswitch/esl/command.rb', line 43

def initialize(client, command, *args, timeout: DEFAULT_TIMEOUT, raise_error: true, &block)
  @client = client
  @command = command
  @args = args
  @timeout = timeout
  @raise_error = raise_error
  @status = :pending
  @job_uuid = nil
  @response = nil
  @error = nil
  @callbacks = block ? [block] : []
  @mutex = Mutex.new
  @cond = ConditionVariable.new
  @sent_at = nil
  @finished_at = nil

  validate_command!
end

Instance Attribute Details

#args ⇒ Object (readonly)

Returns the value of attribute args.



41
42
43
# File 'lib/freeswitch/esl/command.rb', line 41

def args
  @args
end

#command ⇒ Object (readonly)

Returns the value of attribute command.



41
42
43
# File 'lib/freeswitch/esl/command.rb', line 41

def command
  @command
end

#error ⇒ CommandError, ... (readonly)

Returns the error that caused the command to fail (nil if successful).

Returns:



39
40
41
# File 'lib/freeswitch/esl/command.rb', line 39

def error
  @error
end

#finished_at ⇒ Object (readonly)

Returns the value of attribute finished_at.



41
42
43
# File 'lib/freeswitch/esl/command.rb', line 41

def finished_at
  @finished_at
end

#job_uuid ⇒ String? (readonly)

Returns Job-UUID assigned by FreeSWITCH (nil if invalid).

Returns:

  • (String, nil) —

    Job-UUID assigned by FreeSWITCH (nil if invalid)



36
37
38
# File 'lib/freeswitch/esl/command.rb', line 36

def job_uuid
  @job_uuid
end

#sent_at ⇒ Object (readonly)

Returns the value of attribute sent_at.



41
42
43
# File 'lib/freeswitch/esl/command.rb', line 41

def sent_at
  @sent_at
end

#status ⇒ :pending, ... (readonly)

Returns current status of the command.

Returns:

  • (:pending, :ok, :failed, :timeout) —

    current status of the command



33
34
35
# File 'lib/freeswitch/esl/command.rb', line 33

def status
  @status
end

Instance Method Details

#completed? ⇒ Boolean

Returns true when the command has finished (success or failure).

Returns:

  • (Boolean) —

    true when the command has finished (success or failure)



118
119
120
# File 'lib/freeswitch/esl/command.rb', line 118

def completed?
  !pending?
end

#execute! ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/freeswitch/esl/command.rb', line 62

def execute!
  configure_timeout!
  return unless wait_until_client_ready
  return unless begin_submission?

  @job_uuid = @client.bgapi(@command, *@args, timeout: remaining_timeout) do |event|
    event.error? ? fail!(event) : complete!(event)
  end
rescue StandardError => e
  handle_submission_error(e)
end

#execution_time ⇒ Object



142
143
144
145
146
# File 'lib/freeswitch/esl/command.rb', line 142

def execution_time
  return nil unless @sent_at

  (@finished_at || now) - @sent_at
end

#failed? ⇒ Boolean

Returns true when the command failed or timed out.

Returns:

  • (Boolean) —

    true when the command failed or timed out



138
139
140
# File 'lib/freeswitch/esl/command.rb', line 138

def failed?
  %i[failed timeout].include?(@status)
end

#ok? ⇒ Boolean

Returns true when the command completed successfully.

Returns:

  • (Boolean) —

    true when the command completed successfully



128
129
130
# File 'lib/freeswitch/esl/command.rb', line 128

def ok?
  @status == :ok
end

#on_complete {|_self| ... } ⇒ Object

Register a callback to be called when the command completes (success or failure). Multiple callbacks are supported and are called in order. If the command is already completed the block is called immediately. Returns self for chaining.

Yields:

  • (_self)

Yield Parameters:

Raises:

  • (ArgumentError)


78
79
80
81
82
83
84
85
# File 'lib/freeswitch/esl/command.rb', line 78

def on_complete(&block)
  raise ArgumentError, "Block is required" unless block_given?

  @callbacks << block
  yield(self) if completed?

  self
end

#pending? ⇒ Boolean

Returns true when the command is still waiting for a result.

Returns:

  • (Boolean) —

    true when the command is still waiting for a result



123
124
125
# File 'lib/freeswitch/esl/command.rb', line 123

def pending?
  %i[pending sent].include?(@status)
end

#response ⇒ Protocol::Event?

Block the calling thread until the command completes or the timeout expires.

Returns:

  • (Protocol::Event) —

    the event returned by FreeSWITCH when the command completed successfully

  • (nil) —

    if the command failed or timed out but did not raise an exception (raise_error: false)

Raises:



92
93
94
95
96
# File 'lib/freeswitch/esl/command.rb', line 92

def response
  wait unless completed?

  @response
end

#timeout? ⇒ Boolean

Returns true when the command terminated with a timeout (a special kind of failure).

Returns:

  • (Boolean) —

    true when the command terminated with a timeout (a special kind of failure)



133
134
135
# File 'lib/freeswitch/esl/command.rb', line 133

def timeout?
  @status == :timeout
end

#wait ⇒ Command

Wait for the command to complete, fail or timeout.

Returns:

  • (Command) —

    self after completion

Raises:



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/freeswitch/esl/command.rb', line 100

def wait
  @mutex.synchronize do
    return self if completed?

    while pending?
      break if deadline_expired?

      @cond.wait(@mutex, remaining_timeout)
    end
  end

  timeout!("Command timed out after #{@timeout}s waiting for completion") if pending?
  raise @error if @error && @raise_error

  self
end