File: pubsub.rb

package info (click to toggle)
ruby-xmpp4r 0.5.6-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 1,384 kB
  • sloc: ruby: 17,382; xml: 74; sh: 12; makefile: 4
file content (211 lines) | stat: -rw-r--r-- 6,107 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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
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
# =XMPP4R - XMPP Library for Ruby
#
# This file's copyright (c) 2009 by Pablo Lorenzzoni <pablo@propus.com.br>
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
# Website::http://xmpp4r.github.io

require 'xmpp4r/pubsub'
require 'xmpp4r/pubsub/helper/servicehelper'
require 'xmpp4r/pubsub/helper/nodebrowser'
require 'xmpp4r/pubsub/helper/nodehelper'

module Jabber
class Observable
  # Jabber::Observable::PubSub - Convenience subclass to deal with PubSub
  class PubSub
    class NoService < StandardError; end #:nodoc:

    class AlreadySet < StandardError; end #:nodoc:

    # Creates a new PubSub object
    #
    # observable:: points a Jabber::Observable object
    def initialize(observable)
      @observable = observable

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

    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

    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

    # Checks if the PubSub service is set
    def has_service?
      ! @helper.nil?
    end

    # Sets the PubSub service. Just one service is allowed. If nil, reset.
    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 a node.
    def subscribe_to(node)
      raise_noservice if ! has_service?
      @helper.subscribe_to(node) unless is_subscribed_to?(node)
    end

    # Unsubscribe from a node.
    def unsubscribe_from(node)
      raise_noservice if ! has_service?
      @helper.unsubscribe_from(node)
    end

    # Return the subscriptions we have in the configured PubSub service.
    def subscriptions
      raise_noservice if ! has_service?
      @helper.get_subscriptions_from_all_nodes()
    end

    # Create a PubSub node (Lots of options still have to be encoded!)
    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

    # Return an array of nodes I own
    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

    # Return true if a given node exists
    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

    # Returns an array of nodes I am subscribed to
    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

    # Return true if we're subscribed to that node
    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

    # Delete a PubSub node (Lots of options still have to be encoded!)
    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

    # Publish an Item. This infers an item of Jabber::PubSub::Item kind is passed
    def publish_item(node, item)
      raise_noservice if ! has_service?
      @helper.publish_item_to(node, item)
    end

    # Publish Simple Item. This is an item with one element and some text to it.
    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

    # Publish atom Item. This is an item with one atom entry with title, body and time.
    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

    # Get items from a node
    def get_items_from(node, count = nil)
      raise_noservice if ! has_service?
      @helper.get_items_from(node, count)
    end

    private

    def raise_noservice #:nodoc:
      raise NoService, "Have you forgot to call #set_service ?"
    end
  end # of class PubSub
end # of class Observable
end # of module Jabber