Class: RubyAsterisk::AMI::Client
- Inherits:
-
Object
- Object
- RubyAsterisk::AMI::Client
- Includes:
- RubyAsterisk::AMI::Commands::Channel, RubyAsterisk::AMI::Commands::Conference, RubyAsterisk::AMI::Commands::Extension, RubyAsterisk::AMI::Commands::Mailbox, RubyAsterisk::AMI::Commands::Monitor, RubyAsterisk::AMI::Commands::Queue, RubyAsterisk::AMI::Commands::Sip, RubyAsterisk::AMI::Commands::System
- Defined in:
- lib/ruby-asterisk/ami/client.rb
Overview
Asynchronous AMI client.
#execute registers a Promise for the outgoing command and writes it to the socket via the internal Reactor, returning the Promise immediately without blocking. Callers obtain the response by calling Promise#value on the returned Promise, which blocks only until the matching reply arrives (or a per-command timeout fires).
Data pipeline:
Client (external thread)
→ Reactor#send_command (Thread::Queue + IO.pipe doorbell)
→ intake Fiber → socket write
→ socket read → reader Fiber → Parser
→ dispatcher → Promise#resolve (Mutex+CV)
→ Client#execute caller (blocks on Promise#value)
Instance Attribute Summary collapse
-
#connected ⇒ Object
Returns the value of attribute connected.
-
#host ⇒ Object
Returns the value of attribute host.
-
#port ⇒ Object
Returns the value of attribute port.
-
#timeout ⇒ Object
Returns the value of attribute timeout.
Instance Method Summary collapse
-
#connect ⇒ true, false
Connect to the Asterisk AMI server and start the async reactor.
-
#disconnect ⇒ true, false
Disconnect from Asterisk, stop the reactor, and reject pending promises.
-
#execute(command, options = {}, timeout: @timeout) ⇒ Promise
Send an AMI command asynchronously.
-
#initialize(host:, port:) ⇒ Client
constructor
A new instance of Client.
- #login(username:, secret:) ⇒ Object
- #logoff ⇒ Object
Methods included from RubyAsterisk::AMI::Commands::Monitor
#change_monitor, #monitor, #pause_monitor, #stop_monitor, #unpause_monitor
Methods included from RubyAsterisk::AMI::Commands::Sip
#sip_peers, #sip_show_peer, #sip_show_registry
Methods included from RubyAsterisk::AMI::Commands::Mailbox
#mailbox_count, #mailbox_status
Methods included from RubyAsterisk::AMI::Commands::Queue
#queue_add, #queue_pause, #queue_remove, #queue_status, #queue_summary, #queues
Methods included from RubyAsterisk::AMI::Commands::Extension
Methods included from RubyAsterisk::AMI::Commands::Conference
#confbridge, #confbridge_kick, #confbridge_mute, #confbridge_unmute, #confbridges, #meet_me_list
Methods included from RubyAsterisk::AMI::Commands::Channel
#atxfer, #channels, #core_show_channels, #hangup, #originate, #originate_app, #redirect, #status
Methods included from RubyAsterisk::AMI::Commands::System
#command, #device_state_list, #event_mask, #parked_calls, #ping, #skinny_devices, #skinny_lines, #wait_event
Constructor Details
#initialize(host:, port:) ⇒ Client
Returns a new instance of Client.
45 46 47 48 49 50 51 |
# File 'lib/ruby-asterisk/ami/client.rb', line 45 def initialize(host:, port:) self.host = host.to_s self.port = port.to_i self.connected = false @timeout = 5 @reactor = nil end |
Instance Attribute Details
#connected ⇒ Object
Returns the value of attribute connected.
43 44 45 |
# File 'lib/ruby-asterisk/ami/client.rb', line 43 def connected @connected end |
#host ⇒ Object
Returns the value of attribute host.
43 44 45 |
# File 'lib/ruby-asterisk/ami/client.rb', line 43 def host @host end |
#port ⇒ Object
Returns the value of attribute port.
43 44 45 |
# File 'lib/ruby-asterisk/ami/client.rb', line 43 def port @port end |
#timeout ⇒ Object
Returns the value of attribute timeout.
43 44 45 |
# File 'lib/ruby-asterisk/ami/client.rb', line 43 def timeout @timeout end |
Instance Method Details
#connect ⇒ true, false
Connect to the Asterisk AMI server and start the async reactor.
56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/ruby-asterisk/ami/client.rb', line 56 def connect @reactor = Reactor.new(host, port, on_event: method(:handle_event), on_disconnect: method(:handle_disconnect)) @reactor.start self.connected = true true rescue StandardError => e puts "Connection error: #{e.}" @reactor = nil self.connected = false false end |
#disconnect ⇒ true, false
Disconnect from Asterisk, stop the reactor, and reject pending promises.
73 74 75 76 77 78 79 80 81 82 |
# File 'lib/ruby-asterisk/ami/client.rb', line 73 def disconnect @reactor&.stop @reactor&.reject_all_promises(RuntimeError.new('Client disconnected')) @reactor = nil self.connected = false true rescue StandardError => e puts e false end |
#execute(command, options = {}, timeout: @timeout) ⇒ Promise
Send an AMI command asynchronously.
A caller-supplied 'ActionID' option becomes the request's own ActionID instead of an extra header: two ActionID lines in one frame would leave the response uncorrelated with its Promise.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/ruby-asterisk/ami/client.rb', line 109 def execute(command, = {}, timeout: @timeout) raise Error, 'Not connected to AMI' unless @reactor = .dup action_id = .delete('ActionID') request = Request.new(command, , action_id: action_id) promise = Promise.new(action_id: request.action_id, command_type: command, timeout: timeout) promise.on_timeout = -> { @reactor&.unregister_promise(request.action_id) } @reactor.register_promise(request.action_id, promise) # Push the whole frame in one operation so commands issued from concurrent # threads cannot interleave their header lines on the wire. @reactor.send_command(request.commands.join) promise end |
#login(username:, secret:) ⇒ Object
84 85 86 87 88 89 |
# File 'lib/ruby-asterisk/ami/client.rb', line 84 def login(username:, secret:) connect unless connected raise Error, "Unable to connect to AMI at #{host}:#{port}" unless connected execute 'Login', { 'Username' => username, 'Secret' => secret, 'Event' => 'On' } end |
#logoff ⇒ Object
91 92 93 |
# File 'lib/ruby-asterisk/ami/client.rb', line 91 def logoff execute 'Logoff' end |