blather 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/README.rdoc +2 -2
  2. data/Rakefile +30 -18
  3. data/ext/Makefile +149 -0
  4. data/ext/mkmf.log +30 -0
  5. data/ext/push_parser.bundle +0 -0
  6. data/ext/push_parser.c +231 -0
  7. data/ext/push_parser.o +0 -0
  8. data/lib/blather.rb +3 -7
  9. data/lib/blather/client.rb +247 -4
  10. data/lib/blather/roster.rb +0 -9
  11. data/lib/blather/stanza/{disco.rb → iq/disco.rb} +3 -1
  12. data/lib/blather/stanza/{disco → iq/discos}/disco_info.rb +5 -3
  13. data/lib/blather/stanza/{disco → iq/discos}/disco_items.rb +2 -0
  14. data/lib/blather/stanza/iq/query.rb +1 -1
  15. data/lib/blather/stanza/iq/roster.rb +2 -2
  16. data/lib/blather/xmpp_node.rb +1 -1
  17. data/spec/blather/stanza/{discos → iq/discos}/disco_info_spec.rb +12 -12
  18. data/spec/blather/stanza/{discos → iq/discos}/disco_items_spec.rb +1 -1
  19. data/spec/blather/stanza/iq/query_spec.rb +0 -7
  20. data/spec/blather/stanza/iq/roster_spec.rb +21 -21
  21. data/spec/blather/stanza/pubsub/event_spec.rb +13 -0
  22. data/spec/build_safe.rb +20 -0
  23. metadata +19 -68
  24. data/VERSION.yml +0 -4
  25. data/examples/pubsub/cli.rb +0 -64
  26. data/examples/pubsub/ping_pong.rb +0 -18
  27. data/examples/pubsub/pubsub_dsl.rb +0 -52
  28. data/examples/pubsub_client.rb +0 -39
  29. data/examples/rosterprint.rb +0 -14
  30. data/examples/xmpp4r/echo.rb +0 -35
  31. data/lib/blather/client/client.rb +0 -165
  32. data/lib/blather/client/dsl.rb +0 -99
  33. data/lib/blather/client/pubsub.rb +0 -53
  34. data/lib/blather/client/pubsub/node.rb +0 -27
  35. data/lib/blather/stanza/pubsub.rb +0 -33
  36. data/lib/blather/stanza/pubsub/affiliations.rb +0 -52
  37. data/lib/blather/stanza/pubsub/errors.rb +0 -9
  38. data/lib/blather/stanza/pubsub/event.rb +0 -21
  39. data/lib/blather/stanza/pubsub/items.rb +0 -59
  40. data/lib/blather/stanza/pubsub/owner.rb +0 -9
  41. data/lib/blather/stanza/pubsub/subscriptions.rb +0 -57
  42. data/spec/blather/stanza/pubsub/affiliations_spec.rb +0 -46
  43. data/spec/blather/stanza/pubsub/items_spec.rb +0 -59
  44. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +0 -63
  45. data/spec/blather/stanza/pubsub_spec.rb +0 -26
  46. 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/disco/disco_info
31
- blather/stanza/disco/disco_items
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
@@ -1,13 +1,256 @@
1
- require File.join(File.dirname(__FILE__), *%w[client dsl])
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
@@ -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,9 +1,11 @@
1
1
  module Blather
2
2
  class Stanza
3
+ class Iq
3
4
 
4
- class Disco < Iq::Query
5
+ class Disco < Query
5
6
  attribute_accessor :node, :to_sym => false
6
7
  end
7
8
 
9
+ end #Iq
8
10
  end #Stanza
9
11
  end #Blather
@@ -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, node = nil, identities = [], features = [])
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
@@ -1,5 +1,6 @@
1
1
  module Blather
2
2
  class Stanza
3
+ class Iq
3
4
 
4
5
  class DiscoItems < Disco
5
6
  register :disco_items, nil, 'http://jabber.org/protocol/disco#items'
@@ -55,5 +56,6 @@ class Stanza
55
56
  end
56
57
  end
57
58
 
59
+ end #Iq
58
60
  end #Stanza
59
61
  end #Blather
@@ -8,7 +8,7 @@ class Iq
8
8
  ##
9
9
  # Ensure the namespace is set to the query node
10
10
  def initialize(type = nil)
11
- super
11
+ super()
12
12
  query.namespace = self.class.ns
13
13
  end
14
14
 
@@ -27,8 +27,8 @@ class Iq
27
27
  ##
28
28
  # Roster items
29
29
  def items
30
- items = query.find('//item', self.class.ns)
31
- items = query.find('//query_ns:item', :query_ns => self.class.ns) if items.empty?
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
 
@@ -129,7 +129,7 @@ module Blather
129
129
  def namespace=(ns)
130
130
  if ns
131
131
  ns = {nil => ns} unless ns.is_a?(Hash)
132
- ns.each { |n| XML::Namespace.new self, *n }
132
+ ns.each { |p,n| XML::Namespace.new self, p, n }
133
133
  end
134
134
  end
135
135
 
@@ -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, 'music', [], []
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, nil, ids
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, nil, control
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, nil, {:name => 'name', :type => 'type', :category => 'category'}
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, nil, control.first
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, nil, ids
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, nil, [], features
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, nil, [], control
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, nil, [], 'feature1'
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, nil, [], control.first
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, nil, [], features
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