Class: Jabber::MUC::MUCClient
- Defined in:
- lib/gems/xmpp4r-0.4/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) ⇒ 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/gems/xmpp4r-0.4/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/gems/xmpp4r-0.4/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/gems/xmpp4r-0.4/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/gems/xmpp4r-0.4/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
161 162 163 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 161 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.
268 269 270 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 268 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.
284 285 286 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 284 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.
301 302 303 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 301 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.
292 293 294 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 292 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.
310 311 312 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 310 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
399 400 401 402 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 399 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
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 130 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]
318 319 320 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 318 def from_room?(jid) @jid.strip == jid.strip end |
#get_room_configuration ⇒ Object
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 404 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) ⇒ 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
- return
- MUCClient
-
self (chain-able)
72 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 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 72 def join(jid, password=nil) 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 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
169 170 171 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 169 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.
182 183 184 185 186 187 188 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 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 182 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
390 391 392 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 390 def owner? @affiliation == :owner end |
#room ⇒ Object
The room name (= node)
- result
- String
-
Room name
236 237 238 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 236 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
248 249 250 251 252 253 254 255 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 248 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]
448 449 450 451 452 453 454 455 456 457 458 459 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 448 def send_affiliations(items) iq = Iq.new(:set, jid.strip) iq.from = my_jid iq.add(IqQueryMUCAdmin.new) items = [item] unless items.kind_of? Array items.each { |item| iq.query.add(item) } @stream.send_with_id(iq) end |
#submit_room_configuration(options) ⇒ Object
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
# File 'lib/gems/xmpp4r-0.4/lib/xmpp4r/muc/helper/mucclient.rb', line 426 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 |