Class: Freeswitch::ESL::Connection

Inherits:
Object
  • Object
show all
Includes:
Logger
Defined in:
lib/freeswitch/esl/connection.rb,
lib/freeswitch/esl/connection/command_request.rb,
lib/freeswitch/esl/connection/event_dispatcher.rb,
lib/freeswitch/esl/connection/command_dispatcher.rb

Overview

Base ESL connection that handles the wire protocol.

Subclasses are responsible for providing an open socket and calling #initialize_socket to start the reader and event-dispatcher threads.

Threading model:

* A reader thread owned by {CommandDispatcher} reads messages from the
  socket and routes them to pending command executions (FIFO) or to the
  event dispatcher.
* A *dispatcher thread* processes @event_queue and calls registered handlers.
* Command enqueue + write is atomic under a mutex in CommandDispatcher,
  guaranteeing queue order == socket write order.

Direct Known Subclasses

Client

Defined Under Namespace

Classes: CommandDispatcher, CommandRequest, EventDispatcher

Instance Method Summary collapse

Methods included from Logger

default_logger, #logger

Constructor Details

#initialize(socket) ⇒ Connection

Returns a new instance of Connection.



28
29
30
# File 'lib/freeswitch/esl/connection.rb', line 28

def initialize(socket)
  initialize_socket(socket)
end

Instance Method Details

#bgapi(command, *args, timeout: nil, &block) ⇒ Object

Execute a background bgapi command. Returns the Job-UUID string. The optional block is called with the BACKGROUND_JOB Event when the result arrives.

Raises:



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/freeswitch/esl/connection.rb', line 42

def bgapi(command, *args, timeout: nil, &block)
  raise DisconnectedError, "Connection is closed" if closed?

  parts = ["bgapi", command, *args].compact
  logger.debug("[BGAPI] #{parts.join(' ')}")
  cmd = @command_dispatcher.execute_command(parts.join(" "), timeout:).wait
  job_uuid = cmd.response["Job-UUID"]
  raise CommandError, "FreeSWITCH bgapi did not return a Job-UUID" unless job_uuid

  @event_dispatcher.register_bgapi_handler(job_uuid, block) if block
  job_uuid
end

#closeObject

Stop dispatchers and mark the connection closed. Event handlers are removed together with the dispatcher instances, so a reconnect path must rebuild them through #initialize_socket.



101
102
103
104
105
106
107
108
109
110
# File 'lib/freeswitch/esl/connection.rb', line 101

def close
  return if @closed

  @closed = true
  @command_dispatcher&.stop
  @event_dispatcher&.stop

  send(:remove_instance_variable, :@command_dispatcher)
  send(:remove_instance_variable, :@event_dispatcher)
end

#closed?Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/freeswitch/esl/connection.rb', line 94

def closed?
  @closed
end

#filter(header, value) ⇒ Object

Add an event-header filter so FreeSWITCH only sends matching events.



82
83
84
# File 'lib/freeswitch/esl/connection.rb', line 82

def filter(header, value)
  send_command("filter #{header} #{value}").wait
end

#on(event_name) ⇒ Object

Register a handler block for an event name. Use “ALL” to handle every event. Multiple handlers per event name are supported. Returns self for chaining.



89
90
91
92
# File 'lib/freeswitch/esl/connection.rb', line 89

def on(event_name, &)
  @event_dispatcher.on(event_name, &)
  self
end

#pending_bgapi_command_uuidsObject

Return an array of Job-UUID strings for all pending bgapi commands.



61
62
63
# File 'lib/freeswitch/esl/connection.rb', line 61

def pending_bgapi_command_uuids
  @event_dispatcher.pending_bgapi_command_uuids
end

#pending_commands_countObject

Return the number of commands currently waiting for a response.



56
57
58
# File 'lib/freeswitch/esl/connection.rb', line 56

def pending_commands_count
  @command_dispatcher.pending_commands_count
end

#send_command(command, timeout: nil) ⇒ Object

Send a raw ESL command and return a CommandRequest object that can be used to wait for the response.

Raises:



33
34
35
36
37
# File 'lib/freeswitch/esl/connection.rb', line 33

def send_command(command, timeout: nil)
  raise DisconnectedError, "Connection is closed" if closed?

  @command_dispatcher.execute_command(command, timeout:)
end

#subscribe(*event_names) ⇒ Object

Subscribe to one or more event names (JSON format). Pass no arguments or “ALL” to receive every event.



67
68
69
70
# File 'lib/freeswitch/esl/connection.rb', line 67

def subscribe(*event_names)
  events = event_names.empty? ? "ALL" : event_names.join(" ")
  send_command("event json #{events}").wait
end

#unsubscribe(*event_names) ⇒ Object

Cancel subscriptions. Without arguments cancels all events.



73
74
75
76
77
78
79
# File 'lib/freeswitch/esl/connection.rb', line 73

def unsubscribe(*event_names)
  if event_names.empty?
    send_command("noevents").wait
  else
    event_names.each { |e| send_command("nixevent #{e}").wait }
  end
end