Class: Jabber::MUC::MUCClient
- Inherits:
-
Object
- Object
- Jabber::MUC::MUCClient
- Defined in:
- lib/xmpp4r/muc/helper/mucclient.rb
Overview
The MUCClient Helper handles low-level stuff of the Multi-User Chat (JEP 0045).
Use one instance per room.
Note that one client cannot join a single room multiple times. At least the clients’ resources must be different. This is a protocol design issue. But don’t consider it as a bug, it is just a clone-preventing feature.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#jid ⇒ Object
readonly
- MUC JID jid
- JID
-
room@component/nick.
-
#my_jid ⇒ Object
- Sender JID, set this to use MUCClient from Components my_jid
- JID
-
Defaults to nil.
-
#roster ⇒ Object
readonly
- MUC room roster roster
- Hash
-
of [String] Nick => [Presence].
Instance Method Summary collapse
-
#active? ⇒ Boolean
Is the MUC client active?.
-
#add_join_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for <presence/> stanzas indicating availability of a MUC participant.
-
#add_leave_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for <presence/> stanzas indicating unavailability of a MUC participant.
-
#add_message_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for <message/> stanza directed to the whole room.
-
#add_presence_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for a <presence/> stanza which is neither a join nor a leave.
-
#add_private_message_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for <message/> stanza with type=‘chat’.
-
#configure(options = {}) ⇒ Object
Use this method to configure a MUC room of which you are the owner.
-
#exit(reason = nil) ⇒ Object
Exit the room.
-
#from_room?(jid) ⇒ Boolean
- Does this JID belong to that room? jid
- JID
- result
- true
-
or [false].
- #get_room_configuration ⇒ Object
-
#initialize(stream) ⇒ MUCClient
constructor
Initialize a MUCClient.
-
#join(jid, password = nil, opts = {}) ⇒ Object
Join a room.
-
#nick ⇒ Object
- The MUCClient’s own nick (= resource) result
- String
-
Nickname.
-
#nick=(new_nick) ⇒ Object
Change nick.
- #owner? ⇒ Boolean
-
#room ⇒ Object
- The room name (= node) result
- String
-
Room name.
-
#send(stanza, to = nil) ⇒ Object
Send a stanza to the room.
-
#send_affiliations(items) ⇒ Object
- Push a list of new affiliations to the room items
- Array
-
of, or single [IqQueryMUCAdminItem].
- #submit_room_configuration(options) ⇒ Object
Constructor Details
#initialize(stream) ⇒ MUCClient
Initialize a MUCClient
Call MUCClient#join after you have registered your callbacks to avoid reception of stanzas after joining and before registration of callbacks.
- stream
- Stream
-
to operate on
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 45 def initialize(stream) # Attributes initialization @stream = stream @my_jid = nil @jid = nil @roster = {} @roster_lock = Mutex.new @active = false @join_cbs = CallbackList.new @leave_cbs = CallbackList.new @presence_cbs = CallbackList.new @message_cbs = CallbackList.new @private_message_cbs = CallbackList.new end |
Instance Attribute Details
#jid ⇒ Object (readonly)
MUC JID
- jid
- JID
-
room@component/nick
36 37 38 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 36 def jid @jid end |
#my_jid ⇒ Object
Sender JID, set this to use MUCClient from Components
- my_jid
- JID
-
Defaults to nil
26 27 28 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 26 def my_jid @my_jid end |
#roster ⇒ Object (readonly)
MUC room roster
- roster
- Hash
-
of [String] Nick => [Presence]
31 32 33 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 31 def roster @roster end |
Instance Method Details
#active? ⇒ Boolean
Is the MUC client active?
This is false after initialization, true after joining and false after exit/kick
168 169 170 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 168 def active? @active end |
#add_join_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for <presence/> stanzas indicating availability of a MUC participant
This callback will not be called for initial presences when a client joins a room, but only for the presences afterwards.
The callback will be called from MUCClient#handle_presence with one argument: the <presence/> stanza. Note that this stanza will have been already inserted into MUCClient#roster.
275 276 277 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 275 def add_join_callback(prio = 0, ref = nil, &block) @join_cbs.add(prio, ref, block) end |
#add_leave_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for <presence/> stanzas indicating unavailability of a MUC participant
The callback will be called with one argument: the <presence/> stanza.
Note that this is called just before the stanza is removed from MUCClient#roster, so it is still possible to see the last presence in the given block.
If the presence’s origin is your MUC JID, the MUCClient will be deactivated afterwards.
291 292 293 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 291 def add_leave_callback(prio = 0, ref = nil, &block) @leave_cbs.add(prio, ref, block) end |
#add_message_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for <message/> stanza directed to the whole room.
See MUCClient#add_private_message_callback for private messages between MUC participants.
308 309 310 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 308 def (prio = 0, ref = nil, &block) @message_cbs.add(prio, ref, block) end |
#add_presence_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for a <presence/> stanza which is neither a join nor a leave. This will be called when a room participant simply changes his status.
299 300 301 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 299 def add_presence_callback(prio = 0, ref = nil, &block) @presence_cbs.add(prio, ref, block) end |
#add_private_message_callback(prio = 0, ref = nil, &block) ⇒ Object
Add a callback for <message/> stanza with type=‘chat’.
These stanza are normally not broadcasted to all room occupants but are some sort of private messaging.
317 318 319 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 317 def (prio = 0, ref = nil, &block) @private_message_cbs.add(prio, ref, block) end |
#configure(options = {}) ⇒ Object
Use this method to configure a MUC room of which you are the owner.
- options
- Hash
-
where keys are the features of the room you wish
to configure. See www.xmpp.org/extensions/xep-0045.html#registrar-formtype-owner
406 407 408 409 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 406 def configure(={}) get_room_configuration submit_room_configuration() end |
#exit(reason = nil) ⇒ Object
Exit the room
-
Sends presence with type=‘unavailable’ with an optional reason in
<status/>
, -
then waits for a reply from the MUC component (will be processed by leave-callbacks),
-
then deletes callbacks from the stream.
- reason
- String
-
Optional custom exit message
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 137 def exit(reason=nil) unless active? raise "MUCClient hasn't yet joined" end pres = Presence.new pres.type = :unavailable pres.to = jid pres.from = @my_jid pres.status = reason if reason @stream.send(pres) { |r| Jabber::debuglog "exit: #{r.to_s.inspect}" if r.kind_of?(Presence) and r.type == :unavailable and r.from == jid @leave_cbs.process(r) true else false end } deactivate self end |
#from_room?(jid) ⇒ Boolean
Does this JID belong to that room?
- jid
- JID
- result
- true
-
or [false]
325 326 327 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 325 def from_room?(jid) @jid.strip == jid.strip end |
#get_room_configuration ⇒ Object
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 411 def get_room_configuration raise 'You are not the owner' unless owner? iq = Iq.new(:get, jid.strip) iq.from = my_jid iq.add(IqQueryMUCOwner.new) fields = [] @stream.send_with_id(iq) do |answer| raise "Configuration not possible for this room" unless answer.query && answer.query.x(Dataforms::XData) answer.query.x(Dataforms::XData).fields.each do |field| if (var = field.attributes['var']) fields << var end end end fields end |
#join(jid, password = nil, opts = {}) ⇒ Object
Join a room
This registers its own callbacks on the stream provided to initialize and sends initial presence to the room. May throw ServerError if joining fails.
- jid
- JID
-
room@component/nick
- password
- String
-
Optional password
- opts
- Hash
-
If the parameter :history => false is passed then you will receive no history messages after initial presence
- return
- MUCClient
-
self (chain-able)
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 73 def join(jid, password=nil, opts={}) if active? raise "MUCClient already active" end @jid = (jid.kind_of?(JID) ? jid : JID.new(jid)) activate # Joining pres = Presence.new pres.to = @jid pres.from = @my_jid xmuc = XMUC.new xmuc.password = password # Add history/maxstanzas as requested. false=0 xmuc.add_element REXML::Element.new('history').tap { |hist| hist.add_attribute 'maxstanzas', (opts[:history]||0).to_i.to_s } unless opts[:history].nil? pres.add(xmuc) # We don't use Stream#send_with_id here as it's unknown # if the MUC component *always* uses our stanza id. error = nil @stream.send(pres) { |r| if from_room?(r.from) and r.kind_of?(Presence) and r.type == :error # Error from room error = r.error true # type='unavailable' may occur when the MUC kills our previous instance, # but all join-failures should be type='error' elsif r.from == jid and r.kind_of?(Presence) and r.type != :unavailable # Our own presence reflected back - success if r.x(XMUCUser) and (i = r.x(XMUCUser).items.first) @affiliation = i.affiliation # we're interested in if it's :owner @role = i.role # :moderator ? end handle_presence(r, false) true else # Everything else false end } if error deactivate raise ServerError.new(error) end self end |
#nick ⇒ Object
The MUCClient’s own nick (= resource)
- result
- String
-
Nickname
176 177 178 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 176 def nick @jid ? @jid.resource : nil end |
#nick=(new_nick) ⇒ Object
Change nick
Threading is, again, suggested. This method waits for two <presence/> stanzas, one indicating unavailabilty of the old transient JID, one indicating availability of the new transient JID.
If the service denies nick-change, ServerError will be raised.
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 189 def nick=(new_nick) unless active? raise "MUCClient not active" end new_jid = JID.new(@jid.node, @jid.domain, new_nick) # Joining pres = Presence.new pres.to = new_jid pres.from = @my_jid error = nil # Keeping track of the two stanzas enables us to process stanzas # which don't arrive in the order specified by JEP-0045 presence_unavailable = false presence_available = false # We don't use Stream#send_with_id here as it's unknown # if the MUC component *always* uses our stanza id. @stream.send(pres) { |r| if from_room?(r.from) and r.kind_of?(Presence) and r.type == :error # Error from room error = r.error elsif r.from == @jid and r.kind_of?(Presence) and r.type == :unavailable and r.x and r.x.kind_of?(XMUCUser) and r.x.status_code == 303 # Old JID is offline, but wait for the new JID and let stanza be handled # by the standard callback presence_unavailable = true handle_presence(r) elsif r.from == new_jid and r.kind_of?(Presence) and r.type != :unavailable # Our own presence reflected back - success presence_available = true handle_presence(r) end if error or (presence_available and presence_unavailable) true else false end } if error raise ServerError.new(error) end # Apply new JID @jid = new_jid end |
#owner? ⇒ Boolean
397 398 399 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 397 def owner? @affiliation == :owner end |
#room ⇒ Object
The room name (= node)
- result
- String
-
Room name
243 244 245 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 243 def room @jid ? @jid.node : nil end |
#send(stanza, to = nil) ⇒ Object
Send a stanza to the room
If stanza is a Jabber::Message, stanza.type
will be automatically set to :groupchat if directed to room or :chat if directed to participant.
- stanza
- XMPPStanza
-
to send
- to
- String
-
Stanza destination recipient, or room if
nil
255 256 257 258 259 260 261 262 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 255 def send(stanza, to=nil) if stanza.kind_of? Message stanza.type = to ? :chat : :groupchat end stanza.from = @my_jid stanza.to = JID.new(jid.node, jid.domain, to) @stream.send(stanza) end |
#send_affiliations(items) ⇒ Object
Push a list of new affiliations to the room
- items
- Array
-
of, or single [IqQueryMUCAdminItem]
455 456 457 458 459 460 461 462 463 464 465 466 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 455 def send_affiliations(items) iq = Iq.new(:set, jid.strip) iq.from = my_jid iq.add(IqQueryMUCAdmin.new) items = [items] unless items.kind_of? Array items.each { |item| iq.query.add(item) } @stream.send_with_id(iq) end |
#submit_room_configuration(options) ⇒ Object
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
# File 'lib/xmpp4r/muc/helper/mucclient.rb', line 433 def submit_room_configuration() # fill out the reply form iq = Iq.new(:set, jid.strip) iq.from = my_jid query = IqQueryMUCOwner.new form = Dataforms::XData.new form.type = :submit .each do |var, values| field = Dataforms::XDataField.new values = [values] unless values.is_a?(Array) field.var, field.values = var, values form.add(field) end query.add(form) iq.add(query) @stream.send_with_id(iq) end |