jubjub 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,6 +72,47 @@ Examples
72
72
  c['muc#roomconfig_persistentroom'] = true
73
73
  }.exit
74
74
 
75
+ # List pubsub nodes
76
+ u.pubsub
77
+ => [
78
+ #<Jubjub::Pubsub:0x101f23c88 @service="pubsub.jabber.org" @node="facts">,
79
+ #<Jubjub::Pubsub:0x101f23a30 @service="pubsub.jabber.org" @node="news">
80
+ ]
81
+
82
+ # List from a different service?
83
+ u.pubsub('pubsub.jabber.ru')
84
+ => [
85
+ ...
86
+ ]
87
+
88
+ # Create a pubsub node
89
+ node = u.pubsub.create('node_1')
90
+ => #<Jubjub::Pubsub:0x101f3bae0 @service="pubsub.jabber.org" @node="node_1">
91
+
92
+ # Subscribe to node
93
+ subscription = node.subscribe
94
+ => #<Jubjub::PubsubSubscription:0x101effd60 @service="pubsub.jabber.org" @node="node_1" @subscriber="theozaurus@jabber.org" @subid="5129CD7935528" @subscription="subscribed">
95
+
96
+ # Subscribe to something else
97
+ u.pubsub.subscribe('new_thing')
98
+ => #<Jubjub::PubsubSubscription:0x101effd60 @service="pubsub.jabber.org" @node="new_thing" @subscriber="theozaurus@jabber.org" @subid="5129CD7935528" @subscription="subscribed">
99
+
100
+ # Unsubscribe
101
+ subscription.unsubscribe
102
+ => true
103
+
104
+ # Destroy a node directly
105
+ node.destroy
106
+ => true
107
+
108
+ # Destroy another node
109
+ u.pubsub.destroy('spare_node')
110
+ => true
111
+
112
+ # Destroy another node with redirect
113
+ u.pubsub.destroy('old_node', 'pubsub.jabber.ru', 'new_new')
114
+ => true
115
+
75
116
  TODO
76
117
  ====
77
118
 
@@ -1,6 +1,7 @@
1
1
  require "net/http"
2
2
  require "nokogiri"
3
3
  require "jubjub/connection/xmpp_gateway/muc"
4
+ require "jubjub/connection/xmpp_gateway/pubsub"
4
5
 
5
6
  module Jubjub
6
7
  module Connection
@@ -18,6 +19,10 @@ module Jubjub
18
19
  @muc ||= Muc.new(self)
19
20
  end
20
21
 
22
+ def pubsub
23
+ @pubsub ||= Pubsub.new(self)
24
+ end
25
+
21
26
  def write(stanza)
22
27
  req = Net::HTTP::Post.new( url.path )
23
28
  req.basic_auth( @jid.to_s, @password )
@@ -0,0 +1,242 @@
1
+ require 'jubjub/connection/xmpp_gateway/helper'
2
+ require 'jubjub/pubsub'
3
+
4
+ module Jubjub
5
+ module Connection
6
+ class XmppGateway
7
+ class Pubsub
8
+
9
+ include Helper
10
+
11
+ def initialize(connection)
12
+ @connection = connection
13
+ end
14
+
15
+ # http://xmpp.org/extensions/xep-0060.html#entity-nodes
16
+ # <iq type='get'
17
+ # from='francisco@denmark.lit/barracks'
18
+ # to='pubsub.shakespeare.lit'
19
+ # id='nodes1'>
20
+ # <query xmlns='http://jabber.org/protocol/disco#items'/>
21
+ # </iq>
22
+ #
23
+ # Expected
24
+ # <iq type='result'
25
+ # from='pubsub.shakespeare.lit'
26
+ # to='francisco@denmark.lit/barracks'
27
+ # id='nodes1'>
28
+ # <query xmlns='http://jabber.org/protocol/disco#items'>
29
+ # <item jid='pubsub.shakespeare.lit'
30
+ # node='blogs'
31
+ # name='Weblog updates'/>
32
+ # <item jid='pubsub.shakespeare.lit'
33
+ # node='news'
34
+ # name='News and announcements'/>
35
+ # </query>
36
+ # </iq>
37
+ def list(jid)
38
+ request = Nokogiri::XML::Builder.new do |xml|
39
+ xml.iq_(:to => jid, :type => 'get') {
40
+ xml.query_('xmlns' => namespaces['disco_items'])
41
+ }
42
+ end
43
+
44
+ write(
45
+ # Generate stanza
46
+ request.to_xml
47
+ ).xpath(
48
+ # Pull out required parts
49
+ '//iq[@type="result"]/disco_items:query/disco_items:item',
50
+ namespaces
51
+ ).map{|item|
52
+ jid = item.attr('jid')
53
+ node = item.attr('node')
54
+ Jubjub::Pubsub.new jid, node, @connection
55
+ }
56
+ end
57
+
58
+ # http://xmpp.org/extensions/xep-0060.html#owner-create
59
+ # <iq type='set'
60
+ # from='hamlet@denmark.lit/elsinore'
61
+ # to='pubsub.shakespeare.lit'
62
+ # id='create1'>
63
+ # <pubsub xmlns='http://jabber.org/protocol/pubsub'>
64
+ # <create node='princely_musings'/>
65
+ # </pubsub>
66
+ # </iq>
67
+ #
68
+ # Expected
69
+ # <iq type='result'
70
+ # from='pubsub.shakespeare.lit'
71
+ # to='hamlet@denmark.lit/elsinore'
72
+ # id='create2'>
73
+ # <pubsub xmlns='http://jabber.org/protocol/pubsub'>
74
+ # <create node='25e3d37dabbab9541f7523321421edc5bfeb2dae'/>
75
+ # </pubsub>
76
+ # </iq>
77
+ def create(jid, node)
78
+ request = Nokogiri::XML::Builder.new do |xml|
79
+ xml.iq_(:to => jid, :type => 'set') {
80
+ xml.pubsub_('xmlns' => namespaces['pubsub']) {
81
+ xml.create_('node' => node)
82
+ }
83
+ }
84
+ end
85
+
86
+ success = write(
87
+ # Generate stanza
88
+ request.to_xml
89
+ ).xpath(
90
+ # Pull out required parts
91
+ '//iq[@type="result"]/pubsub:pubsub/pubsub:create',
92
+ namespaces
93
+ ).any?
94
+ Jubjub::Pubsub.new jid, node, @connection if success
95
+ end
96
+
97
+ # http://xmpp.org/extensions/xep-0060.html#owner-delete
98
+ # <iq type='set'
99
+ # from='hamlet@denmark.lit/elsinore'
100
+ # to='pubsub.shakespeare.lit'
101
+ # id='delete1'>
102
+ # <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
103
+ # <delete node='princely_musings'>
104
+ # <redirect uri='xmpp:hamlet@denmark.lit?;node=blog'/>
105
+ # </delete>
106
+ # </pubsub>
107
+ # </iq>
108
+ #
109
+ # Expected
110
+ # <iq type='result'
111
+ # from='pubsub.shakespeare.lit'
112
+ # id='delete1'/>
113
+ def destroy(jid, node, redirect_jid = nil, redirect_node = nil)
114
+ request = Nokogiri::XML::Builder.new do |xml|
115
+ xml.iq_(:to => jid, :type => 'set') {
116
+ xml.pubsub_('xmlns' => namespaces['pubsub_owner']) {
117
+ xml.delete_('node' => node){
118
+ xml.redirect( 'uri' => pubsub_uri(redirect_jid, redirect_node) ) if redirect_jid && redirect_node
119
+ }
120
+ }
121
+ }
122
+ end
123
+
124
+ success = write(
125
+ # Generate stanza
126
+ request.to_xml
127
+ ).xpath(
128
+ # Pull out required parts
129
+ '//iq[@type="result"]'
130
+ ).any?
131
+ end
132
+
133
+ # http://xmpp.org/extensions/xep-0060.html#subscriber-subscribe
134
+ # <iq type='set'
135
+ # from='francisco@denmark.lit/barracks'
136
+ # to='pubsub.shakespeare.lit'
137
+ # id='sub1'>
138
+ # <pubsub xmlns='http://jabber.org/protocol/pubsub'>
139
+ # <subscribe
140
+ # node='princely_musings'
141
+ # jid='francisco@denmark.lit'/>
142
+ # </pubsub>
143
+ # </iq>
144
+ #
145
+ # Expected
146
+ # <iq type='result'
147
+ # from='pubsub.shakespeare.lit'
148
+ # to='francisco@denmark.lit/barracks'
149
+ # id='sub1'>
150
+ # <pubsub xmlns='http://jabber.org/protocol/pubsub'>
151
+ # <subscription
152
+ # node='princely_musings'
153
+ # jid='francisco@denmark.lit'
154
+ # subid='ba49252aaa4f5d320c24d3766f0bdcade78c78d3'
155
+ # subscription='subscribed'/>
156
+ # </pubsub>
157
+ # </iq>
158
+ def subscribe(jid, node)
159
+ request = Nokogiri::XML::Builder.new do |xml|
160
+ xml.iq_(:to => jid, :type => 'set') {
161
+ xml.pubsub_('xmlns' => namespaces['pubsub']) {
162
+ xml.subscribe_('node' => node, 'jid' => subscriber)
163
+ }
164
+ }
165
+ end
166
+
167
+ result = write(
168
+ # Generate stanza
169
+ request.to_xml
170
+ ).xpath(
171
+ # Pull out required parts
172
+ '//iq[@type="result"]/pubsub:pubsub/pubsub:subscription',
173
+ namespaces
174
+ )
175
+ if result.any?
176
+ subscriber = Jubjub::Jid.new(result.first.attr('jid'))
177
+ subid = result.first.attr('subid')
178
+ subscription = result.first.attr('subscription')
179
+ Jubjub::PubsubSubscription.new jid, node, subscriber, subid, subscription, @connection
180
+ end
181
+ end
182
+
183
+ # http://xmpp.org/extensions/xep-0060.html#subscriber-unsubscribe
184
+ # <iq type='set'
185
+ # from='francisco@denmark.lit/barracks'
186
+ # to='pubsub.shakespeare.lit'
187
+ # id='unsub1'>
188
+ # <pubsub xmlns='http://jabber.org/protocol/pubsub'>
189
+ # <unsubscribe
190
+ # node='princely_musings'
191
+ # jid='francisco@denmark.lit'/>
192
+ # </pubsub>
193
+ # </iq>
194
+ #
195
+ # Expected
196
+ # <iq type='result'
197
+ # from='pubsub.shakespeare.lit'
198
+ # to='francisco@denmark.lit/barracks'
199
+ # id='unsub1'/>
200
+ def unsubscribe(jid, node, subid=nil)
201
+ unsubscribe_options = {'node' => node, 'jid' => subscriber}
202
+ unsubscribe_options['subid'] = subid if subid
203
+
204
+ request = Nokogiri::XML::Builder.new do |xml|
205
+ xml.iq_(:to => jid, :type => 'set') {
206
+ xml.pubsub_('xmlns' => namespaces['pubsub']) {
207
+ xml.unsubscribe_(unsubscribe_options)
208
+ }
209
+ }
210
+ end
211
+
212
+ write(
213
+ # Generate stanza
214
+ request.to_xml
215
+ ).xpath(
216
+ # Pull out required parts
217
+ '//iq[@type="result"]'
218
+ ).any?
219
+ end
220
+
221
+ private
222
+
223
+ def subscriber
224
+ Jubjub::Jid.new @connection.jid.node, @connection.jid.domain
225
+ end
226
+
227
+ def pubsub_uri(jid, node)
228
+ "xmpp:#{jid}?;node=#{node}"
229
+ end
230
+
231
+ def namespaces
232
+ {
233
+ 'disco_items' => 'http://jabber.org/protocol/disco#items',
234
+ 'pubsub' => 'http://jabber.org/protocol/pubsub',
235
+ 'pubsub_owner' => 'http://jabber.org/protocol/pubsub#owner'
236
+ }
237
+ end
238
+
239
+ end
240
+ end
241
+ end
242
+ end
@@ -60,14 +60,12 @@ module Jubjub
60
60
  list.inspect
61
61
  end
62
62
 
63
- protected
63
+ private
64
64
 
65
65
  def method_missing(name, *args, &block)
66
66
  list.send(name, *args, &block)
67
67
  end
68
-
69
- private
70
-
68
+
71
69
  def list
72
70
  @list ||= @connection.muc.list @jid
73
71
  end
@@ -0,0 +1,107 @@
1
+ require "jubjub/connection/xmpp_gateway/pubsub"
2
+
3
+ module Jubjub
4
+
5
+ class Pubsub
6
+
7
+ attr_reader :jid, :node
8
+
9
+ def initialize(jid, node, connection)
10
+ @jid = Jubjub::Jid.new jid
11
+ @node = node
12
+ @connection = connection
13
+ end
14
+
15
+ def destroy(redirect_jid = nil, redirect_node = nil)
16
+ redirect_jid = Jubjub::Jid.new(redirect_jid) if redirect_jid
17
+ @connection.pubsub.destroy jid, node, redirect_jid, redirect_node
18
+ end
19
+
20
+ def subscribe
21
+ @connection.pubsub.subscribe jid, node
22
+ end
23
+
24
+ def unsubscribe(subid = nil)
25
+ @connection.pubsub.unsubscribe jid, node, subid
26
+ end
27
+
28
+ # Hide the connection details and show jid as string for compactness
29
+ def inspect
30
+ obj_id = "%x" % (object_id << 1)
31
+ "#<#{self.class}:0x#{obj_id} @jid=\"#{jid}\" @node=#{node.inspect}>"
32
+ end
33
+
34
+ end
35
+
36
+ class PubsubSubscription
37
+
38
+ attr_reader :jid, :node, :subscriber, :subid, :subscription
39
+
40
+ def initialize(jid, node, subscriber, subid, subscription, connection)
41
+ @jid = Jubjub::Jid.new jid
42
+ @node = node
43
+ @subscriber = Jubjub::Jid.new subscriber
44
+ @subid = subid
45
+ @subscription = subscription
46
+ @connection = connection
47
+ end
48
+
49
+ def unsubscribe
50
+ @connection.pubsub.unsubscribe jid, node, subid
51
+ end
52
+
53
+ # Hide the connection details and show jid as string for compactness
54
+ def inspect
55
+ obj_id = "%x" % (object_id << 1)
56
+ "#<#{self.class}:0x#{obj_id} @jid=\"#{jid}\" @node=#{node.inspect} @subscriber=\"#{subscriber}\" @subid=#{subid.inspect} @subscription=#{subscription.inspect}>"
57
+ end
58
+
59
+ end
60
+
61
+ # Uses proxy pattern for syntax sugar
62
+ # and delaying expensive operations until
63
+ # required
64
+ class PubsubCollection
65
+
66
+ attr_reader :jid
67
+
68
+ def initialize(jid, connection)
69
+ @jid = Jubjub::Jid.new jid
70
+ @connection = connection
71
+ end
72
+
73
+ def create(node)
74
+ @connection.pubsub.create jid, node
75
+ end
76
+
77
+ def destroy(node, redirect_jid = nil, redirect_node = nil)
78
+ redirect_jid = Jubjub::Jid.new(redirect_jid) if redirect_jid
79
+ @connection.pubsub.destroy jid, node, redirect_jid, redirect_node
80
+ end
81
+
82
+ def subscribe(node)
83
+ @connection.pubsub.subscribe jid, node
84
+ end
85
+
86
+ def unsubscribe(node, subid=nil)
87
+ @connection.pubsub.unsubscribe jid, node, subid
88
+ end
89
+
90
+ # Hint that methods are actually applied to list using method_missing
91
+ def inspect
92
+ list.inspect
93
+ end
94
+
95
+ private
96
+
97
+ def method_missing(name, *args, &block)
98
+ list.send(name, *args, &block)
99
+ end
100
+
101
+ def list
102
+ @list ||= @connection.pubsub.list jid
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -51,7 +51,12 @@ module Jubjub
51
51
  # if no jid is specified will default to 'connection.JID_DOMAIN'
52
52
  def mucs(jid = nil)
53
53
  jid ||= "conference.#{jubjub_jid.domain}"
54
- Jubjub::MucCollection.new(jid, jubjub_connection)
54
+ Jubjub::MucCollection.new jid, jubjub_connection
55
+ end
56
+
57
+ def pubsub(jid = nil)
58
+ jid ||= "pubsub.#{jubjub_jid.domain}"
59
+ Jubjub::PubsubCollection.new jid, jubjub_connection
55
60
  end
56
61
  end
57
62