Class: Jabber::Observable::PubSub

Inherits:
Object
  • Object
show all
Defined in:
lib/xmpp4r-observable.rb

Overview

Jabber::Observable::PubSub - Convenience subclass to deal with PubSub

Defined Under Namespace

Classes: AlreadySet, NoService

Instance Method Summary collapse

Constructor Details

#initialize(observable) ⇒ PubSub

Creates a new PubSub object

observable

points a Jabber::Observable object



100
101
102
103
104
105
106
# File 'lib/xmpp4r-observable.rb', line 100

def initialize(observable)
	@observable = observable

	@helper = @service_jid = nil
	@disco = Jabber::Discovery::Helper.new(@observable.client)
	attach!
end

Instance Method Details

#attach!Object



108
109
110
111
112
113
114
115
116
117
# File 'lib/xmpp4r-observable.rb', line 108

def attach!
	begin
		domain = Jabber::JID.new(@observable.jid).domain
		@service_jid = "pubsub." + domain
		set_service(@service_jid)
	rescue
		@helper = @service_jid = nil
	end
	return has_service?
end

#create_node(node) ⇒ Object

Create a PubSub node (Lots of options still have to be encoded!)



191
192
193
194
195
196
197
198
199
200
201
# File 'lib/xmpp4r-observable.rb', line 191

def create_node(node)
	raise_noservice if ! has_service?
	begin
		@helper.create_node(node)
	rescue => e
		raise e
		return nil
	end
	@my_nodes << node if defined? @my_nodes
	node
end

#delete_node(node) ⇒ Object

Delete a PubSub node (Lots of options still have to be encoded!)



249
250
251
252
253
254
255
256
257
258
259
# File 'lib/xmpp4r-observable.rb', line 249

def delete_node(node)
	raise_noservice if ! has_service?
	begin
		@helper.delete_node(node)
	rescue => e
		raise e
		return nil
	end
	@my_nodes.delete(node) if defined? @my_nodes
	node
end

#get_items_from(node, count = nil) ⇒ Object

Get items from a node



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/xmpp4r-observable.rb', line 299

def get_items_from(node, count = nil)
	raise_noservice if ! has_service?

	if is_subscribed_to?(node)
		# FIXME
		# @helper.get_items_from(node, count)
		# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
		# The above should just work, but I had to reimplement it since OpenFire (the Jabber Server
		# I am testing against) seems to require subids for nodes we're subscribed to.
		subids = find_subids_for(node)
		iq = Jabber::Iq.new(:get, @service_jid)
		iq.add(Jabber::PubSub::IqPubSub.new)
		iq.from = @observable.jid
		items = Jabber::PubSub::Items.new
		items.node = node
		items.max_items = count
		items.subid = subids[0]
		iq.pubsub.add(items)
		res = nil
		@observable.client.send_with_id(iq) { |reply|
			if reply.kind_of?(Jabber::Iq) and reply.pubsub and reply.pubsub.first_element('items')
				res = {}
				reply.pubsub.first_element('items').each_element('item') do |item|
					res[item.attributes['id']] = item.children.first if item.children.first
				end
			end
			true
		}
		res
	else
		@helper.get_items_from(node, count)
	end
end

#has_service?Boolean

Checks if the PubSub service is set

Returns:

  • (Boolean)


128
129
130
# File 'lib/xmpp4r-observable.rb', line 128

def has_service?
	! @helper.nil?
end

#inspectObject

:nodoc:



119
120
121
122
123
124
125
# File 'lib/xmpp4r-observable.rb', line 119

def inspect	#:nodoc:
	if has_service?
		sprintf("#<%s:0x%x @service_jid=%s>", self.class.name, __id__, @service_jid)
	else
		sprintf("#<%s:0x%x @has_service?=false>", self.class.name, __id__)
	end
end

#is_subscribed_to?(node) ⇒ Boolean

Return true if we’re subscribed to that node

Returns:

  • (Boolean)


240
241
242
243
244
245
246
# File 'lib/xmpp4r-observable.rb', line 240

def is_subscribed_to?(node)
	ret = false
	subscriptions.each do |sub|
		ret = true if sub.node == node and sub.attributes['subscription'] == 'subscribed'
	end
	return ret
end

#my_nodesObject

Return an array of nodes I own



204
205
206
207
208
209
210
211
212
213
# File 'lib/xmpp4r-observable.rb', line 204

def my_nodes
	if ! defined? @my_nodes
		ret = []
		subscriptions.each do |sub|
			 ret << sub.node if sub.attributes['affiliation'] == 'owner'
		end
		@my_nodes = ret
	end
	return @my_nodes
end

#node_exists?(node) ⇒ Boolean

Return true if a given node exists

Returns:

  • (Boolean)


216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/xmpp4r-observable.rb', line 216

def node_exists?(node)
	ret = []
	if ! defined? @existing_nodes or ! @existing_nodes.include?(node)
		# We'll renew @existing_nodes if we haven't got it the first time
		reply = @disco.get_items_for(@service_jid)
		reply.items.each do |item|
			ret << item.node
		end
		@existing_nodes = ret
	end
	return @existing_nodes.include?(node)
end

#publish_atom_item(node, title, body, time = Time.now) ⇒ Object

Publish atom Item. This is an item with one atom entry with title, body and time.



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/xmpp4r-observable.rb', line 279

def publish_atom_item(node, title, body, time = Time.now)
	raise_noservice if ! has_service?
	
	item = Jabber::PubSub::Item.new
	entry = REXML::Element.new('entry')
	entry.add_namespace("http://www.w3.org/2005/Atom")
	mytitle = REXML::Element.new('title')
	mytitle.text = title
	entry.add(mytitle)
	mybody = REXML::Element.new('body')
	mybody.text = body
	entry.add(mybody)
	published = REXML::Element.new("published")
	published.text = time.utc.iso8601
	entry.add(published)
	item.add(entry)
	publish_item(node, item)
end

#publish_item(node, item) ⇒ Object

Publish an Item. This infers an item of Jabber::PubSub::Item kind is passed



262
263
264
265
# File 'lib/xmpp4r-observable.rb', line 262

def publish_item(node, item)
	raise_noservice if ! has_service?
	@helper.publish_item_to(node, item)
end

#publish_simple_item(node, text) ⇒ Object

Publish Simple Item. This is an item with one element and some text to it.



268
269
270
271
272
273
274
275
276
# File 'lib/xmpp4r-observable.rb', line 268

def publish_simple_item(node, text)
	raise_noservice if ! has_service?
	
	item = Jabber::PubSub::Item.new
	xml = REXML::Element.new('value')
	xml.text = text
	item.add(xml)
	publish_item(node, item)
end

#set_service(service) ⇒ Object

Sets the PubSub service. Just one service is allowed. If nil, reset.



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/xmpp4r-observable.rb', line 133

def set_service(service)
	if service.nil?
		@helper = @service_jid = nil
	else
		raise NotConnected, "You are not connected" if ! @observable.connected?
		raise AlreadySet, "You already have a PubSub service (#{@service_jid})." if has_service?
		@helper = Jabber::PubSub::ServiceHelper.new(@observable.client, service)
		@service_jid = service

		@helper.add_event_callback do |event|
			@observable.changed(:event)
			@observable.notify_observers(:event, event)
		end
	end
end

#subscribe_to(node) ⇒ Object

Subscribe to a node.



150
151
152
153
# File 'lib/xmpp4r-observable.rb', line 150

def subscribe_to(node)
	raise_noservice if ! has_service?
	@helper.subscribe_to(node) unless is_subscribed_to?(node)
end

#subscribed_nodesObject

Returns an array of nodes I am subscribed to



230
231
232
233
234
235
236
237
# File 'lib/xmpp4r-observable.rb', line 230

def subscribed_nodes
	ret = []
	subscriptions.each do |sub|
		next if sub.node.nil?
		ret << sub.node if sub.attributes['subscription'] == 'subscribed' and ! my_nodes.include?(sub.node)
	end
	return ret
end

#subscriptionsObject

Return the subscriptions we have in the configured PubSub service.



185
186
187
188
# File 'lib/xmpp4r-observable.rb', line 185

def subscriptions
	raise_noservice if ! has_service?
	@helper.get_subscriptions_from_all_nodes()
end

#unsubscribe_from(node) ⇒ Object

Unsubscribe from a node.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/xmpp4r-observable.rb', line 156

def unsubscribe_from(node)
	raise_noservice if ! has_service?
	
	# FIXME
	# @helper.unsubscribe_from(node)
	# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	# The above should just work, but I had to reimplement it since XMPP4R doesn't support subids
	# and OpenFire (the Jabber Server I am testing against) seems to require it.
	
	subids = find_subids_for(node)
	return if subids.empty?
	
	subids.each do |subid|
		iq = Jabber::Iq.new(:set, @service_jid)
		iq.add(Jabber::PubSub::IqPubSub.new)
		iq.from = @jid
		unsub = REXML::Element.new('unsubscribe')
		unsub.attributes['node'] = node
		unsub.attributes['jid'] = @jid
		unsub.attributes['subid'] = subid
		iq.pubsub.add(unsub)
		res = nil
		@observable.client.send_with_id(iq) do |reply|
			res = reply.kind_of?(Jabber::Iq) and reply.type == :result
		end # @stream.send_with_id(iq)
	end
end