blather 0.4.7 → 0.4.8
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.md +162 -0
- data/examples/{print_heirarchy.rb → print_hierarchy.rb} +5 -5
- data/examples/stream_only.rb +27 -0
- data/lib/blather.rb +4 -0
- data/lib/blather/client/client.rb +91 -73
- data/lib/blather/client/dsl.rb +156 -32
- data/lib/blather/client/dsl/pubsub.rb +86 -54
- data/lib/blather/core_ext/active_support.rb +9 -9
- data/lib/blather/core_ext/active_support/inheritable_attributes.rb +2 -2
- data/lib/blather/core_ext/nokogiri.rb +12 -7
- data/lib/blather/errors.rb +25 -14
- data/lib/blather/errors/sasl_error.rb +21 -3
- data/lib/blather/errors/stanza_error.rb +37 -21
- data/lib/blather/errors/stream_error.rb +27 -17
- data/lib/blather/jid.rb +79 -24
- data/lib/blather/roster.rb +39 -21
- data/lib/blather/roster_item.rb +43 -21
- data/lib/blather/stanza.rb +88 -40
- data/lib/blather/stanza/disco.rb +12 -2
- data/lib/blather/stanza/disco/disco_info.rb +112 -20
- data/lib/blather/stanza/disco/disco_items.rb +81 -12
- data/lib/blather/stanza/iq.rb +94 -38
- data/lib/blather/stanza/iq/query.rb +16 -22
- data/lib/blather/stanza/iq/roster.rb +98 -20
- data/lib/blather/stanza/message.rb +266 -111
- data/lib/blather/stanza/presence.rb +118 -42
- data/lib/blather/stanza/presence/status.rb +140 -60
- data/lib/blather/stanza/presence/subscription.rb +44 -10
- data/lib/blather/stanza/pubsub.rb +70 -15
- data/lib/blather/stanza/pubsub/affiliations.rb +36 -7
- data/lib/blather/stanza/pubsub/create.rb +26 -4
- data/lib/blather/stanza/pubsub/errors.rb +13 -4
- data/lib/blather/stanza/pubsub/event.rb +56 -10
- data/lib/blather/stanza/pubsub/items.rb +46 -6
- data/lib/blather/stanza/pubsub/publish.rb +52 -7
- data/lib/blather/stanza/pubsub/retract.rb +45 -6
- data/lib/blather/stanza/pubsub/subscribe.rb +30 -4
- data/lib/blather/stanza/pubsub/subscription.rb +74 -6
- data/lib/blather/stanza/pubsub/subscriptions.rb +35 -9
- data/lib/blather/stanza/pubsub/unsubscribe.rb +30 -4
- data/lib/blather/stanza/pubsub_owner.rb +17 -7
- data/lib/blather/stanza/pubsub_owner/delete.rb +23 -5
- data/lib/blather/stanza/pubsub_owner/purge.rb +23 -5
- data/lib/blather/stream.rb +96 -29
- data/lib/blather/stream/parser.rb +6 -9
- data/lib/blather/xmpp_node.rb +101 -153
- data/spec/blather/client/client_spec.rb +1 -1
- data/spec/blather/errors_spec.rb +5 -5
- data/spec/blather/stanza/message_spec.rb +56 -0
- data/spec/blather/stanza/presence/status_spec.rb +1 -1
- data/spec/blather/stanza_spec.rb +3 -3
- data/spec/blather/xmpp_node_spec.rb +19 -74
- metadata +6 -10
- data/README.rdoc +0 -185
- data/examples/drb_client.rb +0 -5
- data/examples/ping.rb +0 -11
- data/examples/pong.rb +0 -6
- data/examples/pubsub/cli.rb +0 -64
- data/examples/pubsub/ping_pong.rb +0 -18
data/lib/blather/roster.rb
CHANGED
@@ -1,20 +1,27 @@
|
|
1
1
|
module Blather
|
2
2
|
|
3
|
-
|
4
|
-
# Local Roster
|
3
|
+
# Local Roster
|
5
4
|
# Takes care of adding/removing JIDs through the stream
|
6
5
|
class Roster
|
7
6
|
include Enumerable
|
8
7
|
|
8
|
+
# Create a new roster
|
9
|
+
#
|
10
|
+
# @param [Blather::Stream] stream the stream the roster should use to
|
11
|
+
# update roster entries
|
12
|
+
# @param [Blather::Stanza::Roster] stanza a roster stanza used to preload
|
13
|
+
# the roster
|
14
|
+
# @return [Blather::Roster]
|
9
15
|
def initialize(stream, stanza = nil)
|
10
16
|
@stream = stream
|
11
17
|
@items = {}
|
12
18
|
stanza.items.each { |i| push i, false } if stanza
|
13
19
|
end
|
14
20
|
|
15
|
-
|
16
|
-
# Process any incoming stanzas adn either add or remove the
|
21
|
+
# Process any incoming stanzas and either adds or removes the
|
17
22
|
# corresponding RosterItem
|
23
|
+
#
|
24
|
+
# @param [Blather::Stanza::Roster] stanza a roster stanza
|
18
25
|
def process(stanza)
|
19
26
|
stanza.items.each do |i|
|
20
27
|
case i.subscription
|
@@ -24,18 +31,21 @@ module Blather
|
|
24
31
|
end
|
25
32
|
end
|
26
33
|
|
27
|
-
##
|
28
34
|
# Pushes a JID into the roster
|
29
|
-
#
|
35
|
+
#
|
36
|
+
# @param [String, Blather::JID, #jid] elem a JID to add to the roster
|
37
|
+
# @return [self]
|
38
|
+
# @see #push
|
30
39
|
def <<(elem)
|
31
40
|
push elem
|
32
41
|
self
|
33
42
|
end
|
34
43
|
|
35
|
-
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
44
|
+
# Push a JID into the roster and update the server
|
45
|
+
#
|
46
|
+
# @param [String, Blather::JID, #jid] elem a jid to add to the roster
|
47
|
+
# @param [true, false] send send the update over the wire
|
48
|
+
# @see Blather::JID
|
39
49
|
def push(elem, send = true)
|
40
50
|
jid = elem.respond_to?(:jid) ? elem.jid : JID.new(elem)
|
41
51
|
@items[key(jid)] = node = RosterItem.new(elem)
|
@@ -44,35 +54,41 @@ module Blather
|
|
44
54
|
end
|
45
55
|
alias_method :add, :push
|
46
56
|
|
47
|
-
|
48
|
-
#
|
49
|
-
#
|
57
|
+
# Remove a JID from the roster and update the server
|
58
|
+
#
|
59
|
+
# @param [String, Blather::JID] jid the JID to remove from the roster
|
50
60
|
def delete(jid)
|
51
61
|
@items.delete key(jid)
|
52
|
-
|
62
|
+
item = Stanza::Iq::Roster::RosterItem.new(jid, nil, :remove)
|
63
|
+
@stream.write Stanza::Iq::Roster.new(:set, item)
|
53
64
|
end
|
54
65
|
alias_method :remove, :delete
|
55
66
|
|
56
|
-
##
|
57
67
|
# Get a RosterItem by JID
|
68
|
+
#
|
69
|
+
# @param [String, Blather::JID] jid the jid of the item to return
|
70
|
+
# @return [Blather::RosterItem, nil] the associated RosterItem
|
58
71
|
def [](jid)
|
59
72
|
items[key(jid)]
|
60
73
|
end
|
61
74
|
|
62
|
-
##
|
63
75
|
# Iterate over all RosterItems
|
76
|
+
#
|
77
|
+
# @yield [Blather::RosterItem] yields each RosterItem
|
64
78
|
def each(&block)
|
65
79
|
items.each &block
|
66
80
|
end
|
67
81
|
|
68
|
-
|
69
|
-
#
|
82
|
+
# Get a duplicate of all RosterItems
|
83
|
+
#
|
84
|
+
# @return [Array<Blather::RosterItem>] a duplicate of all RosterItems
|
70
85
|
def items
|
71
86
|
@items.dup
|
72
87
|
end
|
73
88
|
|
74
|
-
##
|
75
89
|
# A hash of items keyed by group
|
90
|
+
#
|
91
|
+
# @return [Hash<group => Array<RosterItem>>]
|
76
92
|
def grouped
|
77
93
|
self.inject(Hash.new{|h,k|h[k]=[]}) do |hash, item|
|
78
94
|
item[1].groups.each { |group| hash[group] << item[1] }
|
@@ -81,13 +97,15 @@ module Blather
|
|
81
97
|
end
|
82
98
|
|
83
99
|
private
|
100
|
+
# Creates a stripped jid
|
84
101
|
def self.key(jid)
|
85
102
|
JID.new(jid).stripped.to_s
|
86
103
|
end
|
87
104
|
|
105
|
+
# Instance method to wrap around the class method
|
88
106
|
def key(jid)
|
89
107
|
self.class.key(jid)
|
90
108
|
end
|
91
|
-
end
|
109
|
+
end # Roster
|
92
110
|
|
93
|
-
end
|
111
|
+
end # Blather
|
data/lib/blather/roster_item.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
module Blather
|
2
2
|
|
3
|
-
##
|
4
3
|
# RosterItems hold internal representations of the user's roster
|
5
4
|
# including each JID's status.
|
6
5
|
class RosterItem
|
7
|
-
VALID_SUBSCRIPTION_TYPES = [:both, :from, :none, :remove, :to]
|
6
|
+
VALID_SUBSCRIPTION_TYPES = [:both, :from, :none, :remove, :to].freeze
|
8
7
|
|
9
8
|
attr_reader :jid,
|
10
9
|
:ask,
|
@@ -18,8 +17,19 @@ module Blather
|
|
18
17
|
super
|
19
18
|
end
|
20
19
|
|
21
|
-
|
22
|
-
#
|
20
|
+
# Create a new RosterItem
|
21
|
+
#
|
22
|
+
# @overload initialize(jid)
|
23
|
+
# Create a new RosterItem based on a JID
|
24
|
+
# @param [Blather::JID] jid the JID object
|
25
|
+
# @overload initialize(jid)
|
26
|
+
# Create a new RosterItem based on a JID string
|
27
|
+
# @param [String] jid a JID string
|
28
|
+
# @overload initialize(node)
|
29
|
+
# Create a new RosterItem based on a stanza
|
30
|
+
# @param [Blather::Stanza::Iq::Roster::RosterItem] node a RosterItem
|
31
|
+
# stanza
|
32
|
+
# @return [Blather::RosterItem] the new RosterItem
|
23
33
|
def initialize(item)
|
24
34
|
@statuses = []
|
25
35
|
@groups = []
|
@@ -40,54 +50,66 @@ module Blather
|
|
40
50
|
@groups = [nil] if @groups.empty?
|
41
51
|
end
|
42
52
|
|
43
|
-
##
|
44
53
|
# Set the jid
|
54
|
+
#
|
55
|
+
# @param [String, Blather::JID] jid the new jid
|
56
|
+
# @see Blather::JID
|
45
57
|
def jid=(jid)
|
46
58
|
@jid = JID.new(jid).stripped
|
47
59
|
end
|
48
60
|
|
49
|
-
##
|
50
61
|
# Set the subscription
|
51
62
|
# Ensures it is one of VALID_SUBSCRIPTION_TYPES
|
63
|
+
#
|
64
|
+
# @param [#to_sym] sub the new subscription
|
52
65
|
def subscription=(sub)
|
53
|
-
|
54
|
-
|
66
|
+
if sub && !VALID_SUBSCRIPTION_TYPES.include?(sub = sub.to_sym)
|
67
|
+
raise ArgumentError, "Invalid Type (#{sub}), use: #{VALID_SUBSCRIPTION_TYPES*' '}"
|
68
|
+
end
|
55
69
|
@subscription = sub ? sub : :none
|
56
70
|
end
|
57
71
|
|
58
|
-
##
|
59
72
|
# Get the current subscription
|
60
|
-
#
|
73
|
+
#
|
74
|
+
# @return [:both, :from, :none, :remove, :to]
|
61
75
|
def subscription
|
62
76
|
@subscription || :none
|
63
77
|
end
|
64
78
|
|
65
|
-
##
|
66
79
|
# Set the ask value
|
67
|
-
#
|
80
|
+
#
|
81
|
+
# @param [nil, :subscribe] ask the new ask
|
68
82
|
def ask=(ask)
|
69
|
-
|
83
|
+
if ask && (ask = ask.to_sym) != :subscribe
|
84
|
+
raise ArgumentError, "Invalid Type (#{ask}), can only be :subscribe"
|
85
|
+
end
|
70
86
|
@ask = ask ? ask : nil
|
71
87
|
end
|
72
88
|
|
73
|
-
##
|
74
89
|
# Set the status then sorts them according to priority
|
75
|
-
#
|
90
|
+
#
|
91
|
+
# @param [Blather::Stanza::Status] the new status
|
76
92
|
def status=(presence)
|
77
93
|
@statuses.delete_if { |s| s.from == presence.from }
|
78
94
|
@statuses << presence
|
79
95
|
@statuses.sort!
|
80
96
|
end
|
81
97
|
|
82
|
-
|
83
|
-
#
|
84
|
-
#
|
98
|
+
# The status with the highest priority
|
99
|
+
#
|
100
|
+
# @param [String, nil] resource the resource to get the status of
|
85
101
|
def status(resource = nil)
|
86
|
-
top =
|
102
|
+
top = if resource
|
103
|
+
@statuses.detect { |s| s.from.resource == resource }
|
104
|
+
else
|
105
|
+
@statuses.first
|
106
|
+
end
|
87
107
|
end
|
88
108
|
|
89
|
-
|
90
|
-
#
|
109
|
+
# Translate the RosterItem into a proper stanza that can be sent over the
|
110
|
+
# stream
|
111
|
+
#
|
112
|
+
# @return [Blather::Stanza::Iq::Roster]
|
91
113
|
def to_stanza(type = nil)
|
92
114
|
r = Stanza::Iq::Roster.new type
|
93
115
|
n = Stanza::Iq::Roster::RosterItem.new jid, name, subscription, ask
|
data/lib/blather/stanza.rb
CHANGED
@@ -1,95 +1,143 @@
|
|
1
1
|
module Blather
|
2
|
-
|
3
|
-
# Base XMPP Stanza
|
2
|
+
|
3
|
+
# # Base XMPP Stanza
|
4
|
+
#
|
5
|
+
# All stanzas inherit this class. It provides a set of methods and helpers
|
6
|
+
# common to all XMPP Stanzas
|
7
|
+
#
|
8
|
+
# @handler :stanza
|
4
9
|
class Stanza < XMPPNode
|
10
|
+
# @private
|
5
11
|
@@last_id = 0
|
12
|
+
# @private
|
6
13
|
@@handler_list = []
|
7
14
|
|
8
|
-
class_inheritable_array :
|
15
|
+
class_inheritable_array :handler_hierarchy
|
9
16
|
|
10
|
-
|
11
|
-
# Registers a callback onto the callback heirarchy stack
|
17
|
+
# Registers a callback onto the callback stack
|
12
18
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
19
|
+
# @param [Symbol] handler the name of the handler
|
20
|
+
# @param [Symbol, String, nil] name the name of the first element in the
|
21
|
+
# stanza. If nil the inherited name will be used. If that's nil the
|
22
|
+
# handler name will be used.
|
23
|
+
# @param [String, nil] ns the namespace of the stanza
|
17
24
|
def self.register(handler, name = nil, ns = nil)
|
18
25
|
@@handler_list << handler
|
19
|
-
self.
|
20
|
-
self.
|
26
|
+
self.handler_hierarchy ||= [:stanza]
|
27
|
+
self.handler_hierarchy.unshift handler
|
21
28
|
|
22
29
|
name = name || self.registered_name || handler
|
23
30
|
super name, ns
|
24
31
|
end
|
25
32
|
|
33
|
+
# The handler stack for the current stanza class
|
34
|
+
#
|
35
|
+
# @return [Array<Symbol>]
|
26
36
|
def self.handler_list
|
27
37
|
@@handler_list
|
28
38
|
end
|
29
39
|
|
30
|
-
##
|
31
40
|
# Helper method that creates a unique ID for stanzas
|
41
|
+
#
|
42
|
+
# @return [String] a new unique ID
|
32
43
|
def self.next_id
|
33
44
|
@@last_id += 1
|
34
45
|
'blather%04x' % @@last_id
|
35
46
|
end
|
36
47
|
|
37
|
-
|
38
|
-
# Helper method to generate stanza guard methods
|
39
|
-
#
|
40
|
-
# attribute_helpers_for(:type, [:subscribe, :unsubscribe])
|
48
|
+
# Check if the stanza is an error stanza
|
41
49
|
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
[values].flatten.each do |v|
|
46
|
-
define_method("#{v}?") { __send__(attr) == v }
|
47
|
-
end
|
50
|
+
# @return [true, false]
|
51
|
+
def error?
|
52
|
+
self.type == :error
|
48
53
|
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
# Copies itself then swaps from and to
|
54
|
-
# then returns the new stanza
|
55
|
+
# Creates a copy with to and from swapped
|
56
|
+
#
|
57
|
+
# @return [Blather::Stanza]
|
55
58
|
def reply
|
56
59
|
self.dup.reply!
|
57
60
|
end
|
58
61
|
|
59
|
-
##
|
60
62
|
# Swaps from and to
|
63
|
+
#
|
64
|
+
# @return [self]
|
61
65
|
def reply!
|
62
66
|
self.to, self.from = self.from, self.to
|
63
67
|
self
|
64
68
|
end
|
65
69
|
|
66
|
-
|
70
|
+
# Get the stanza's ID
|
71
|
+
#
|
72
|
+
# @return [String, nil]
|
73
|
+
def id
|
74
|
+
read_attr :id
|
75
|
+
end
|
67
76
|
|
68
|
-
|
77
|
+
# Set the stanza's ID
|
78
|
+
#
|
79
|
+
# @param [#to_s] id the new stanza ID
|
80
|
+
def id=(id)
|
81
|
+
write_attr :id, id
|
82
|
+
end
|
69
83
|
|
70
|
-
|
71
|
-
#
|
84
|
+
# Get the stanza's to
|
85
|
+
#
|
86
|
+
# @return [Blather::JID, nil]
|
72
87
|
def to
|
73
88
|
JID.new(self[:to]) if self[:to]
|
74
89
|
end
|
75
90
|
|
76
|
-
|
77
|
-
#
|
91
|
+
# Set the stanza's to field
|
92
|
+
#
|
93
|
+
# @param [#to_s] to the new JID for the to field
|
94
|
+
def to=(to)
|
95
|
+
write_attr :to, to
|
96
|
+
end
|
97
|
+
|
98
|
+
# Get the stanza's from
|
99
|
+
#
|
100
|
+
# @return [Blather::JID, nil]
|
78
101
|
def from
|
79
102
|
JID.new(self[:from]) if self[:from]
|
80
103
|
end
|
81
104
|
|
82
|
-
|
105
|
+
# Set the stanza's from field
|
106
|
+
#
|
107
|
+
# @param [#to_s] from the new JID for the from field
|
108
|
+
def from=(from)
|
109
|
+
write_attr :from, from
|
110
|
+
end
|
83
111
|
|
84
|
-
|
85
|
-
#
|
86
|
-
#
|
87
|
-
|
112
|
+
# Get the stanza's type
|
113
|
+
#
|
114
|
+
# @return [Symbol, nil]
|
115
|
+
def type
|
116
|
+
read_attr :type, :to_sym
|
117
|
+
end
|
118
|
+
|
119
|
+
# Set the stanza's type
|
120
|
+
#
|
121
|
+
# @param [#to_s] type the new stanza type
|
122
|
+
def type=(type)
|
123
|
+
write_attr :type, type
|
124
|
+
end
|
125
|
+
|
126
|
+
# Create an error stanza from the current stanza
|
127
|
+
#
|
128
|
+
# @param [String] name the error name
|
129
|
+
# @param [<Blather::StanzaError::VALID_TYPES>] type the error type
|
130
|
+
# @param [String, nil] text the error text
|
131
|
+
# @param [Array<XML::Node>] extras an array of extra nodes to attach to
|
132
|
+
# the error
|
133
|
+
#
|
134
|
+
# @return [Blather::StanzaError]
|
88
135
|
def as_error(name, type, text = nil, extras = [])
|
89
136
|
StanzaError.new self, name, type, text, extras
|
90
137
|
end
|
91
138
|
|
92
|
-
|
139
|
+
protected
|
140
|
+
# @private
|
93
141
|
def reply_if_needed!
|
94
142
|
unless @reversed_endpoints
|
95
143
|
reply!
|
data/lib/blather/stanza/disco.rb
CHANGED
@@ -1,15 +1,25 @@
|
|
1
1
|
module Blather
|
2
2
|
class Stanza
|
3
3
|
|
4
|
+
# # Disco Base class
|
5
|
+
#
|
6
|
+
# Use Blather::Stanza::DiscoInfo or Blather::Stanza::DiscoItems
|
4
7
|
class Disco < Iq::Query
|
8
|
+
|
9
|
+
# Get the name of the node
|
10
|
+
#
|
11
|
+
# @return [String] the node name
|
5
12
|
def node
|
6
13
|
query[:node]
|
7
14
|
end
|
8
15
|
|
16
|
+
# Set the name of the node
|
17
|
+
#
|
18
|
+
# @param [#to_s] node the new node name
|
9
19
|
def node=(node)
|
10
20
|
query[:node] = node
|
11
21
|
end
|
12
22
|
end
|
13
23
|
|
14
|
-
end #Stanza
|
15
|
-
end #Blather
|
24
|
+
end # Stanza
|
25
|
+
end # Blather
|