Class: Blather::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/blather/client/client.rb

Overview

# Blather Client

Blather’s Client class provides a set of helpers for working with common XMPP tasks such as setting up and starting the connection, settings status, registering and dispatching filters and handlers and roster management.

Client can be used separately from the DSL if you’d like to implement your own DSL Here’s the echo example using the client without the DSL:

require 'blather/client/client'
client = Client.setup '[email protected]', 'echo'

client.register_handler(:ready) do
  puts "Connected ! send messages to #{client.jid.stripped}."
end

client.register_handler :subscription, :request? do |s|
  client.write s.approve!
end

client.register_handler :message, :chat?, :body => 'exit' do |m|
  client.write Blather::Stanza::Message.new(m.from, 'Exiting...')
  client.close
end

client.register_handler :message, :chat?, :body do |m|
  client.write Blather::Stanza::Message.new(m.from, "You sent: #{m.body}")
end

Defined Under Namespace

Classes: Job

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeClient

Returns a new instance of Client.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/blather/client/client.rb', line 74

def initialize  # @private
  @state = :initializing

  @status = Stanza::Presence::Status.new
  @handlers = {}
  @tmp_handlers = {}
  @tmp_handlers_mutex = Mutex.new
  @filters = {:before => [], :after => []}
  @roster = Roster.new self
  @caps = Stanza::Capabilities.new
  @queue_size = 5

  setup_initial_handlers
end

Instance Attribute Details

#capsObject (readonly)

Returns the value of attribute caps.



50
51
52
# File 'lib/blather/client/client.rb', line 50

def caps
  @caps
end

#jidObject (readonly)

Returns the value of attribute jid.



50
51
52
# File 'lib/blather/client/client.rb', line 50

def jid
  @jid
end

#queue_sizeObject (readonly)

Returns the value of attribute queue_size.



50
51
52
# File 'lib/blather/client/client.rb', line 50

def queue_size
  @queue_size
end

#rosterObject (readonly)

Returns the value of attribute roster.



50
51
52
# File 'lib/blather/client/client.rb', line 50

def roster
  @roster
end

Class Method Details

.setup(jid, password, host = nil, port = nil, certs = nil, connect_timeout = nil, options = {}) ⇒ Blather::Client

Create a new client and set it up

domain

Parameters:

  • jid (Blather::JID, #to_s)

    the JID to authorize with

  • password (String)

    the password to authorize with

  • host (String) (defaults to: nil)

    if this isn’t set it’ll be resolved off the JID’s

  • port (Fixnum, String) (defaults to: nil)

    the port to connect to.

  • options (Hash) (defaults to: {})

    a list of options to create the client with

Options Hash (options):

  • :authcid (String)

    A custom authcid for advanced authentication scenarios

  • :workqueue_count (Number) — default: 5

    the number of threads used to process incoming XMPP messages. If this parameter is specified with 0, no background threads are used; instead stanzas are handled in the same process that the Client is running in.

Returns:



69
70
71
# File 'lib/blather/client/client.rb', line 69

def self.setup(jid, password, host = nil, port = nil, certs = nil, connect_timeout = nil, options = {})
  self.new.setup(jid, password, host, port, certs, connect_timeout, options)
end

Instance Method Details

#clear_handlers(type, *guards) ⇒ Object

Clear handlers with given guards

Parameters:

  • type (Symbol, nil)

    remove filters for a specific handler

  • guards (guards)

    take a look at the guards documentation



152
153
154
# File 'lib/blather/client/client.rb', line 152

def clear_handlers(type, *guards)
  @handlers[type].delete_if { |g, _| g == guards }
end

#closeObject

Close the connection



192
193
194
195
196
197
198
# File 'lib/blather/client/client.rb', line 192

def close
  EM.next_tick {
    handler_queue.shutdown if handler_queue
    @handler_queue = nil
    self.stream.close_connection_after_writing if connected?
  }
end

#connected?Boolean

Check whether the client is currently connected.

Returns:

  • (Boolean)


90
91
92
# File 'lib/blather/client/client.rb', line 90

def connected?
  setup? && !@stream.nil? && !@stream.stopped?
end

#handle_data(stanza) ⇒ Object



221
222
223
224
225
226
227
# File 'lib/blather/client/client.rb', line 221

def handle_data(stanza)
  catch(:halt) do
    run_filters :before, stanza
    handle_stanza stanza
    run_filters :after, stanza
  end
end

#handler_queueObject



248
249
250
251
252
253
254
255
# File 'lib/blather/client/client.rb', line 248

def handler_queue
  return if queue_size == 0
  return @handler_queue if @handler_queue
  @handler_queue = Class.new(Job)
  @handler_queue.client = self
  @handler_queue.workers queue_size
  return @handler_queue
end

#post_init(stream, jid = nil) ⇒ Object



201
202
203
204
205
# File 'lib/blather/client/client.rb', line 201

def post_init(stream, jid = nil)
  @stream = stream
  @jid = JID.new(jid) if jid
  self.jid.node ? client_post_init : ready!
end

#receive_data(stanza) ⇒ Object



213
214
215
216
217
218
219
# File 'lib/blather/client/client.rb', line 213

def receive_data(stanza)
  if handler_queue
    handler_queue.perform_async stanza
  else
    handle_data stanza
  end
end

#register_filter(type, handler = nil, *guards) {|Blather::Stanza| ... } ⇒ Object

Register a filter to be run before or after the handler chain is run.

Parameters:

  • type (<:before, :after>)

    the filter type

  • handler (Symbol, nil) (defaults to: nil)

    set the filter on a specific handler

  • guards (guards)

    take a look at the guards documentation

Yields:



130
131
132
133
134
135
# File 'lib/blather/client/client.rb', line 130

def register_filter(type, handler = nil, *guards, &filter)
  unless [:before, :after].include?(type)
    raise "Invalid filter: #{type}. Must be :before or :after"
  end
  @filters[type] << [guards, handler, filter]
end

#register_handler(type, *guards) {|Blather::Stanza| ... } ⇒ Object

Register a handler

Parameters:

  • type (Symbol, nil)

    set the filter on a specific handler

  • guards (guards)

    take a look at the guards documentation

Yields:



161
162
163
164
165
# File 'lib/blather/client/client.rb', line 161

def register_handler(type, *guards, &handler)
  check_handler type, guards
  @handlers[type] ||= []
  @handlers[type] << [guards, handler]
end

#register_tmp_handler(id) {|Blather::Stanza| ... } ⇒ Object

Register a temporary handler. Temporary handlers are based on the ID of the JID and live only until a stanza with said ID is received.

Parameters:

  • id (#to_s)

    the ID of the stanza that should be handled

Yields:



142
143
144
145
146
# File 'lib/blather/client/client.rb', line 142

def register_tmp_handler(id, &handler)
  @tmp_handlers_mutex.synchronize do
    @tmp_handlers[id.to_s] = handler
  end
end

#runObject Also known as: connect

Start the connection.

The stream type used is based on the JID. If a node exists it uses Blather::Stream::Client otherwise Blather::Stream::Component



117
118
119
120
121
# File 'lib/blather/client/client.rb', line 117

def run
  raise 'not setup!' unless setup?
  klass = @setup[0].node ? Blather::Stream::Client : Blather::Stream::Component
  klass.start self, *@setup
end

#setup(jid, password, host = nil, port = nil, certs = nil, connect_timeout = nil, options = {}) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
# File 'lib/blather/client/client.rb', line 235

def setup(jid, password, host = nil, port = nil, certs = nil, connect_timeout = nil, options = {})
  @jid = JID.new(jid)
  @setup = [@jid, password]
  @setup << host
  @setup << port
  @setup << certs
  @setup << connect_timeout
  @setup << options
  @queue_size = options[:workqueue_count] || 5
  self
end

#setup?Boolean

Returns:

  • (Boolean)


230
231
232
# File 'lib/blather/client/client.rb', line 230

def setup?
  @setup.is_a? Array
end

#statusObject

Get the current status. Taken from the ‘state` attribute of Status



95
96
97
# File 'lib/blather/client/client.rb', line 95

def status
  @status.state
end

#status=(state) ⇒ Object

Set the status. Status can be set with either a single value or an array containing

[state, message, to].



103
104
105
106
107
108
109
110
111
# File 'lib/blather/client/client.rb', line 103

def status=(state)
  state, msg, to = state

  status = Stanza::Presence::Status.new state, msg
  status.to = to
  @status = status unless to

  write status
end

#unbindObject



208
209
210
# File 'lib/blather/client/client.rb', line 208

def unbind
  call_handler_for(:disconnected, nil) || (EM.reactor_running? && EM.stop)
end

#write(stanza) ⇒ Object

Write data to the stream

Parameters:

  • stanza (#to_xml, #to_s)

    the content to send down the wire



170
171
172
# File 'lib/blather/client/client.rb', line 170

def write(stanza)
  self.stream.send(stanza)
end

#write_with_handler(stanza) {|Blather::Stanza| ... } ⇒ Object

Helper that will create a temporary handler for the stanza being sent before writing it to the stream.

client.write_with_handler(stanza) { |s| "handle stanza here" }

is equivalent to:

client.register_tmp_handler(stanza.id) { |s| "handle stanza here" }
client.write stanza

Parameters:

Yields:



186
187
188
189
# File 'lib/blather/client/client.rb', line 186

def write_with_handler(stanza, &handler)
  register_tmp_handler stanza.id, &handler
  write stanza
end