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.
- data/README.mdown +41 -0
- data/lib/jubjub/connection/xmpp_gateway.rb +5 -0
- data/lib/jubjub/connection/xmpp_gateway/pubsub.rb +242 -0
- data/lib/jubjub/muc.rb +2 -4
- data/lib/jubjub/pubsub.rb +107 -0
- data/lib/jubjub/user.rb +6 -1
- data/spec/connection/{xmpp_gateway_spec.rb → xmpp_gateway_muc_spec.rb} +0 -0
- data/spec/connection/xmpp_gateway_pubsub_spec.rb +153 -0
- data/spec/fixtures/vcr_cassettes/pubsub_create.yml +47 -0
- data/spec/fixtures/vcr_cassettes/pubsub_destroy.yml +47 -0
- data/spec/fixtures/vcr_cassettes/pubsub_destroy_with_redirect.yml +93 -0
- data/spec/fixtures/vcr_cassettes/pubsub_list.yml +119 -0
- data/spec/fixtures/vcr_cassettes/pubsub_subscribe.yml +72 -0
- data/spec/fixtures/vcr_cassettes/pubsub_unsubscribe.yml +93 -0
- data/spec/fixtures/vcr_cassettes/pubsub_unsubscribe_with_subid.yml +93 -0
- data/spec/mixins/user_spec.rb +16 -0
- data/spec/models/pubsub_collection_spec.rb +122 -0
- data/spec/models/pubsub_spec.rb +108 -0
- data/spec/models/pubsub_subscription_spec.rb +115 -0
- metadata +30 -6
data/README.mdown
CHANGED
@@ -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
|
data/lib/jubjub/muc.rb
CHANGED
@@ -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
|
data/lib/jubjub/user.rb
CHANGED
@@ -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
|
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
|
|