jubjub 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|