blather 0.2.2 → 0.2.3

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.
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