blather 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +2 -2
- data/Rakefile +30 -18
- data/ext/Makefile +149 -0
- data/ext/mkmf.log +30 -0
- data/ext/push_parser.bundle +0 -0
- data/ext/push_parser.c +231 -0
- data/ext/push_parser.o +0 -0
- data/lib/blather.rb +3 -7
- data/lib/blather/client.rb +247 -4
- data/lib/blather/roster.rb +0 -9
- data/lib/blather/stanza/{disco.rb → iq/disco.rb} +3 -1
- data/lib/blather/stanza/{disco → iq/discos}/disco_info.rb +5 -3
- data/lib/blather/stanza/{disco → iq/discos}/disco_items.rb +2 -0
- data/lib/blather/stanza/iq/query.rb +1 -1
- data/lib/blather/stanza/iq/roster.rb +2 -2
- data/lib/blather/xmpp_node.rb +1 -1
- data/spec/blather/stanza/{discos → iq/discos}/disco_info_spec.rb +12 -12
- data/spec/blather/stanza/{discos → iq/discos}/disco_items_spec.rb +1 -1
- data/spec/blather/stanza/iq/query_spec.rb +0 -7
- data/spec/blather/stanza/iq/roster_spec.rb +21 -21
- data/spec/blather/stanza/pubsub/event_spec.rb +13 -0
- data/spec/build_safe.rb +20 -0
- metadata +19 -68
- data/VERSION.yml +0 -4
- data/examples/pubsub/cli.rb +0 -64
- data/examples/pubsub/ping_pong.rb +0 -18
- data/examples/pubsub/pubsub_dsl.rb +0 -52
- data/examples/pubsub_client.rb +0 -39
- data/examples/rosterprint.rb +0 -14
- data/examples/xmpp4r/echo.rb +0 -35
- data/lib/blather/client/client.rb +0 -165
- data/lib/blather/client/dsl.rb +0 -99
- data/lib/blather/client/pubsub.rb +0 -53
- data/lib/blather/client/pubsub/node.rb +0 -27
- data/lib/blather/stanza/pubsub.rb +0 -33
- data/lib/blather/stanza/pubsub/affiliations.rb +0 -52
- data/lib/blather/stanza/pubsub/errors.rb +0 -9
- data/lib/blather/stanza/pubsub/event.rb +0 -21
- data/lib/blather/stanza/pubsub/items.rb +0 -59
- data/lib/blather/stanza/pubsub/owner.rb +0 -9
- data/lib/blather/stanza/pubsub/subscriptions.rb +0 -57
- data/spec/blather/stanza/pubsub/affiliations_spec.rb +0 -46
- data/spec/blather/stanza/pubsub/items_spec.rb +0 -59
- data/spec/blather/stanza/pubsub/subscriptions_spec.rb +0 -63
- data/spec/blather/stanza/pubsub_spec.rb +0 -26
- data/spec/fixtures/pubsub.rb +0 -157
data/ext/push_parser.o
ADDED
Binary file
|
data/lib/blather.rb
CHANGED
@@ -26,17 +26,13 @@ $:.unshift File.join(File.dirname(__FILE__), '..')
|
|
26
26
|
blather/stanza/iq
|
27
27
|
blather/stanza/iq/query
|
28
28
|
blather/stanza/iq/roster
|
29
|
-
blather/stanza/disco
|
30
|
-
blather/stanza/
|
31
|
-
blather/stanza/
|
29
|
+
blather/stanza/iq/disco
|
30
|
+
blather/stanza/iq/discos/disco_info
|
31
|
+
blather/stanza/iq/discos/disco_items
|
32
32
|
blather/stanza/message
|
33
33
|
blather/stanza/presence
|
34
34
|
blather/stanza/presence/status
|
35
35
|
blather/stanza/presence/subscription
|
36
|
-
blather/stanza/pubsub
|
37
|
-
blather/stanza/pubsub/affiliations
|
38
|
-
blather/stanza/pubsub/subscriptions
|
39
|
-
blather/stanza/pubsub/items
|
40
36
|
|
41
37
|
blather/stream
|
42
38
|
blather/stream/client
|
data/lib/blather/client.rb
CHANGED
@@ -1,13 +1,256 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), *%w[
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. blather])
|
2
|
+
|
3
|
+
module Blather #:nodoc:
|
4
|
+
|
5
|
+
class Client #:nodoc:
|
6
|
+
attr_accessor :jid,
|
7
|
+
:roster
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@state = :initializing
|
11
|
+
|
12
|
+
@status = Stanza::Presence::Status.new
|
13
|
+
@handlers = {}
|
14
|
+
@tmp_handlers = {}
|
15
|
+
@roster = Roster.new self
|
16
|
+
|
17
|
+
setup_initial_handlers
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup(jid, password, host = nil, port = 5222)
|
21
|
+
@setup = [JID.new(jid), password, host, port]
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup?
|
26
|
+
@setup.is_a?(Array) && !@setup.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
raise 'Not setup!' unless @setup.is_a?(Array)
|
31
|
+
trap(:INT) { EM.stop }
|
32
|
+
EM.run {
|
33
|
+
klass = @setup[2].node ? Blather::Stream::Client : Blather::Stream::Component
|
34
|
+
klass.start Blather.client, *@setup
|
35
|
+
}
|
36
|
+
|
37
|
+
def temporary_handler(id, &handler)
|
38
|
+
@tmp_handlers[id] = handler
|
39
|
+
end
|
40
|
+
|
41
|
+
def register_handler(type, *guards, &handler)
|
42
|
+
@handlers[type] ||= []
|
43
|
+
@handlers[type] << [guards, handler]
|
44
|
+
end
|
45
|
+
|
46
|
+
def status
|
47
|
+
@status.state
|
48
|
+
end
|
49
|
+
|
50
|
+
def status=(state)
|
51
|
+
state, msg, to = state
|
52
|
+
|
53
|
+
status = Stanza::Presence::Status.new state, msg
|
54
|
+
status.to = to
|
55
|
+
@statustatus unless to
|
56
|
+
|
57
|
+
write status
|
58
|
+
end
|
59
|
+
|
60
|
+
def write(stanza)
|
61
|
+
stanza.from ||= jid if stanza.respond_to?(:from)
|
62
|
+
@stream.send(stanza) if @stream
|
63
|
+
end
|
64
|
+
|
65
|
+
def stream_started(stream)
|
66
|
+
@stream = stream
|
67
|
+
|
68
|
+
#retreive roster
|
69
|
+
if @stream.is_a?(Stream::Component)
|
70
|
+
@state = :ready
|
71
|
+
call_handler_for :ready, nil
|
72
|
+
else
|
73
|
+
write Stanza::Iq::Roster.new
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def stop
|
78
|
+
@stream.close_connection_after_writing
|
79
|
+
end
|
80
|
+
|
81
|
+
def stopped
|
82
|
+
EM.stop
|
83
|
+
end
|
84
|
+
|
85
|
+
def call(stanza)
|
86
|
+
if handler = @tmp_handlers.delete(stanza.id)
|
87
|
+
handler.call stanza
|
88
|
+
else
|
89
|
+
stanza.handler_heirarchy.each do |type|
|
90
|
+
break if call_handler_for(type, stanza) && (stanza.is_a?(BlatherError) || stanza.type == :iq)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def call_handler_for(type, stanza)
|
96
|
+
if @handlers[type]
|
97
|
+
@handlers[type].find { |guards, handler| handler.call(stanza) unless guarded?(guards, stanza) }
|
98
|
+
true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
def setup_initial_handlers
|
104
|
+
register_handler :error do |err|
|
105
|
+
raise err
|
106
|
+
end
|
107
|
+
|
108
|
+
register_handler :iq do |iq|
|
109
|
+
write(StanzaError::ServiceUnavailable.new(iq, :cancel).to_node) if [:set, :get].include?(iq.type)
|
110
|
+
end
|
111
|
+
|
112
|
+
register_handler :status do |status|
|
113
|
+
roster[status.from].status = status if roster[status.from]
|
114
|
+
end
|
115
|
+
|
116
|
+
register_handler :roster do |node|
|
117
|
+
roster.process node
|
118
|
+
if @state == :initializing
|
119
|
+
@state = :ready
|
120
|
+
write @status
|
121
|
+
call_handler_for :ready, nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# If any of the guards returns FALSE this returns true
|
128
|
+
def guarded?(guards, stanza)
|
129
|
+
guards.find do |guard|
|
130
|
+
case guard
|
131
|
+
when Symbol
|
132
|
+
!stanza.__send__(guard)
|
133
|
+
when Array
|
134
|
+
# return FALSE if any item is TRUE
|
135
|
+
!guard.detect { |condition| !guarded?([condition], stanza) }
|
136
|
+
when Hash
|
137
|
+
# return FALSE unless any inequality is found
|
138
|
+
guard.find do |method, value|
|
139
|
+
if value.is_a?(Regexp)
|
140
|
+
!stanza.__send__(method).to_s.match(value)
|
141
|
+
else
|
142
|
+
stanza.__send__(method) != value
|
143
|
+
end
|
144
|
+
end
|
145
|
+
when Proc
|
146
|
+
!guard.call(stanza)
|
147
|
+
else
|
148
|
+
raise "Bad guard: #{guard.inspect}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end #Client
|
154
|
+
|
155
|
+
def client
|
156
|
+
@client ||= Client.new
|
157
|
+
end
|
158
|
+
module_function :client
|
159
|
+
end #Blather
|
160
|
+
|
161
|
+
##
|
162
|
+
# Prepare server settings
|
163
|
+
# setup_client [node@domain/resource], [password], [host], [port]
|
164
|
+
# host and port are optional defaulting to the domain in the JID and 5222 respectively
|
165
|
+
def setup_client(jid, password, host = nil, port = 5222)
|
166
|
+
at_exit { Blather.client.setup_client(jid, password, host, port).run }
|
167
|
+
end
|
168
|
+
|
169
|
+
def setup_component(jid, secret, host, port)
|
170
|
+
at_exit { Blather.client.setup_component(jid, secret, host, port).run }
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Shutdown the connection.
|
175
|
+
# Flushes the write buffer then stops EventMachine
|
176
|
+
def shutdown
|
177
|
+
Blather.client.stop
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Set handler for a stanza type
|
182
|
+
def handle(stanza_type, *guards, &block)
|
183
|
+
Blather.client.register_handler stanza_type, *guards, &block
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Wrapper for "handle :ready" (just a bit of syntactic sugar)
|
188
|
+
def when_ready(&block)
|
189
|
+
handle :ready, &block
|
190
|
+
end
|
191
|
+
|
192
|
+
##
|
193
|
+
# Set current status
|
194
|
+
def status(state = nil, msg = nil)
|
195
|
+
Blather.client.status = state, msg
|
196
|
+
end
|
197
|
+
|
198
|
+
##
|
199
|
+
# Direct access to the roster
|
200
|
+
def roster
|
201
|
+
Blather.client.roster
|
202
|
+
end
|
203
|
+
|
204
|
+
##
|
205
|
+
# Write data to the stream
|
206
|
+
# Anything that resonds to #to_s can be paseed to the stream
|
207
|
+
def write(stanza)
|
208
|
+
Blather.client.write(stanza)
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
# Helper method to make sending basic messages easier
|
213
|
+
# say [jid], [msg]
|
214
|
+
def say(to, msg)
|
215
|
+
Blather.client.write Blather::Stanza::Message.new(to, msg)
|
216
|
+
end
|
217
|
+
|
218
|
+
##
|
219
|
+
# Wrapper to grab the current JID
|
220
|
+
def jid
|
221
|
+
Blather.client.jid
|
222
|
+
end
|
223
|
+
|
224
|
+
##
|
225
|
+
#
|
226
|
+
def discover(what, who, where, &callback)
|
227
|
+
stanza = Blather::Stanza.class_from_registration(:query, "http://jabber.org/protocol/disco##{what}").new
|
228
|
+
stanza.to = who
|
229
|
+
stanza.node = where
|
230
|
+
|
231
|
+
Blather.client.temporary_handler stanza.id, &callback
|
232
|
+
write stanza
|
233
|
+
end
|
234
|
+
|
235
|
+
##
|
236
|
+
# Checks to see if the method is part of the handlers list.
|
237
|
+
# If so it creates a handler, otherwise it'll pass it back
|
238
|
+
# to Ruby's method_missing handler
|
239
|
+
def method_missing(method, *args, &block)
|
240
|
+
if Blather::Stanza.handler_list.include?(method)
|
241
|
+
handle method, *args, &block
|
242
|
+
else
|
243
|
+
super
|
244
|
+
end
|
245
|
+
end
|
2
246
|
|
3
|
-
include Blather::DSL
|
4
247
|
|
5
248
|
at_exit do
|
6
|
-
unless client.setup?
|
249
|
+
unless Blather.client.setup?
|
7
250
|
if ARGV.length < 2
|
8
251
|
puts "Run with #{$0} user@server/resource password [host] [port]"
|
9
252
|
else
|
10
|
-
client.setup(*ARGV).run
|
253
|
+
Blather.client.setup(*ARGV).run
|
11
254
|
end
|
12
255
|
end
|
13
256
|
end
|
data/lib/blather/roster.rb
CHANGED
@@ -71,15 +71,6 @@ module Blather
|
|
71
71
|
@items.dup
|
72
72
|
end
|
73
73
|
|
74
|
-
##
|
75
|
-
# A hash of items keyed by group
|
76
|
-
def grouped
|
77
|
-
self.inject(Hash.new{|h,k|h[k]=[]}) do |hash, item|
|
78
|
-
item[1].groups.each { |group| hash[group] << item[1] }
|
79
|
-
hash
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
74
|
private
|
84
75
|
def self.key(jid)
|
85
76
|
JID.new(jid).stripped.to_s
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Blather
|
2
2
|
class Stanza
|
3
|
+
class Iq
|
3
4
|
|
4
5
|
##
|
5
6
|
# DiscoInfo object ()
|
@@ -7,11 +8,9 @@ class Stanza
|
|
7
8
|
class DiscoInfo < Disco
|
8
9
|
register :disco_info, nil, 'http://jabber.org/protocol/disco#info'
|
9
10
|
|
10
|
-
def initialize(type = nil,
|
11
|
+
def initialize(type = nil, identities = [], features = [], node = nil)
|
11
12
|
super type
|
12
13
|
|
13
|
-
self.node = node
|
14
|
-
|
15
14
|
[identities].flatten.each do |id|
|
16
15
|
query << (id.is_a?(Identity) ? id : Identity.new(id[:name], id[:type], id[:category]))
|
17
16
|
end
|
@@ -19,6 +18,8 @@ class Stanza
|
|
19
18
|
[features].flatten.each do |feature|
|
20
19
|
query << (feature.is_a?(Feature) ? feature : Feature.new(feature))
|
21
20
|
end
|
21
|
+
|
22
|
+
self.node = node
|
22
23
|
end
|
23
24
|
|
24
25
|
##
|
@@ -80,5 +81,6 @@ class Stanza
|
|
80
81
|
end
|
81
82
|
end
|
82
83
|
|
84
|
+
end #Iq
|
83
85
|
end #Stanza
|
84
86
|
end #Blather
|
@@ -27,8 +27,8 @@ class Iq
|
|
27
27
|
##
|
28
28
|
# Roster items
|
29
29
|
def items
|
30
|
-
items = query.find('
|
31
|
-
items = query.find('
|
30
|
+
items = query.find('item')
|
31
|
+
items = query.find('query_ns:item', :query_ns => self.class.ns) if items.empty?
|
32
32
|
items.map { |i| RosterItem.new(i) }
|
33
33
|
end
|
34
34
|
|
data/lib/blather/xmpp_node.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), *%w[.. .. .. spec_helper])
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. .. .. spec_helper])
|
2
2
|
|
3
3
|
def disco_info_xml
|
4
4
|
<<-XML
|
@@ -24,7 +24,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo' do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'has a node attribute' do
|
27
|
-
n = Blather::Stanza::Iq::DiscoInfo.new nil,
|
27
|
+
n = Blather::Stanza::Iq::DiscoInfo.new nil, [], [], 'music'
|
28
28
|
n.node.must_equal 'music'
|
29
29
|
n.node = :foo
|
30
30
|
n.node.must_equal 'foo'
|
@@ -55,7 +55,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo identities' do
|
|
55
55
|
control = [ Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
|
56
56
|
Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
|
57
57
|
|
58
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
58
|
+
di = Stanza::Iq::DiscoInfo.new nil, ids
|
59
59
|
di.identities.size.must_equal 2
|
60
60
|
di.identities.each { |i| control.include?(i).must_equal true }
|
61
61
|
end
|
@@ -64,7 +64,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo identities' do
|
|
64
64
|
control = [ Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
|
65
65
|
Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
|
66
66
|
|
67
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
67
|
+
di = Stanza::Iq::DiscoInfo.new nil, control
|
68
68
|
di.identities.size.must_equal 2
|
69
69
|
di.identities.each { |i| control.include?(i).must_equal true }
|
70
70
|
end
|
@@ -72,7 +72,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo identities' do
|
|
72
72
|
it 'takes a single hash as identity' do
|
73
73
|
control = [Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category])]
|
74
74
|
|
75
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
75
|
+
di = Stanza::Iq::DiscoInfo.new nil, {:name => 'name', :type => 'type', :category => 'category'}
|
76
76
|
di.identities.size.must_equal 1
|
77
77
|
di.identities.each { |i| control.include?(i).must_equal true }
|
78
78
|
end
|
@@ -80,7 +80,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo identities' do
|
|
80
80
|
it 'takes a single identity object as identity' do
|
81
81
|
control = [Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category])]
|
82
82
|
|
83
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
83
|
+
di = Stanza::Iq::DiscoInfo.new nil, control.first
|
84
84
|
di.identities.size.must_equal 1
|
85
85
|
di.identities.each { |i| control.include?(i).must_equal true }
|
86
86
|
end
|
@@ -94,7 +94,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo identities' do
|
|
94
94
|
control = [ Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
|
95
95
|
Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
|
96
96
|
|
97
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
97
|
+
di = Stanza::Iq::DiscoInfo.new nil, ids
|
98
98
|
di.identities.size.must_equal 2
|
99
99
|
di.identities.each { |i| control.include?(i).must_equal true }
|
100
100
|
end
|
@@ -105,7 +105,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo features' do
|
|
105
105
|
features = %w[feature1 feature2 feature3]
|
106
106
|
control = features.map { |f| Stanza::Iq::DiscoInfo::Feature.new f }
|
107
107
|
|
108
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
108
|
+
di = Stanza::Iq::DiscoInfo.new nil, [], features
|
109
109
|
di.features.size.must_equal 3
|
110
110
|
di.features.each { |f| control.include?(f).must_equal true }
|
111
111
|
end
|
@@ -114,7 +114,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo features' do
|
|
114
114
|
features = %w[feature1 feature2 feature3]
|
115
115
|
control = features.map { |f| Stanza::Iq::DiscoInfo::Feature.new f }
|
116
116
|
|
117
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
117
|
+
di = Stanza::Iq::DiscoInfo.new nil, [], control
|
118
118
|
di.features.size.must_equal 3
|
119
119
|
di.features.each { |f| control.include?(f).must_equal true }
|
120
120
|
end
|
@@ -122,7 +122,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo features' do
|
|
122
122
|
it 'takes a single string' do
|
123
123
|
control = [Stanza::Iq::DiscoInfo::Feature.new('feature1')]
|
124
124
|
|
125
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
125
|
+
di = Stanza::Iq::DiscoInfo.new nil, [], 'feature1'
|
126
126
|
di.features.size.must_equal 1
|
127
127
|
di.features.each { |f| control.include?(f).must_equal true }
|
128
128
|
end
|
@@ -130,7 +130,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo features' do
|
|
130
130
|
it 'takes a single Feature object' do
|
131
131
|
control = [Stanza::Iq::DiscoInfo::Feature.new('feature1')]
|
132
132
|
|
133
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
133
|
+
di = Stanza::Iq::DiscoInfo.new nil, [], control.first
|
134
134
|
di.features.size.must_equal 1
|
135
135
|
di.features.each { |f| control.include?(f).must_equal true }
|
136
136
|
end
|
@@ -140,7 +140,7 @@ describe 'Blather::Stanza::Iq::DiscoInfo features' do
|
|
140
140
|
control = features.map { |f| Stanza::Iq::DiscoInfo::Feature.new f }
|
141
141
|
features[1] = control[1]
|
142
142
|
|
143
|
-
di = Stanza::Iq::DiscoInfo.new nil,
|
143
|
+
di = Stanza::Iq::DiscoInfo.new nil, [], features
|
144
144
|
di.features.size.must_equal 3
|
145
145
|
di.features.each { |f| control.include?(f).must_equal true }
|
146
146
|
end
|