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
@@ -1,58 +1,85 @@
|
|
1
1
|
module Blather
|
2
2
|
class Stanza
|
3
3
|
|
4
|
-
#
|
4
|
+
# # Presence Stanza
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# [RFC 3921 Section 2.2 - Presence Syntax](http://xmpp.org/rfcs/rfc3921.html#stanzas-presence)
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# that availability. Presence stanzas are also used to negotiate and manage subscriptions to the presence of other entities.
|
8
|
+
# Within Blather most of the interaction with Presence stanzas will be
|
9
|
+
# through one of its child classes: Status or Subscription.
|
11
10
|
#
|
12
|
-
#
|
11
|
+
# Presence stanzas are used to express an entity's current network
|
12
|
+
# availability (offline or online, along with various sub-states of the
|
13
|
+
# latter and optional user-defined descriptive text), and to notify other
|
14
|
+
# entities of that availability. Presence stanzas are also used to negotiate
|
15
|
+
# and manage subscriptions to the presence of other entities.
|
13
16
|
#
|
14
|
-
#
|
15
|
-
# is used to signal to the server that the sender is online and available for communication. If included, the +type+
|
16
|
-
# attribute specifies a lack of availability, a request to manage a subscription to another entity's presence, a
|
17
|
-
# request for another entity's current presence, or an error related to a previously-sent presence stanza. If included,
|
18
|
-
# the +type+ attribute must have one of the following values:
|
17
|
+
# ## "Type" Attribute
|
19
18
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
19
|
+
# The `type` attribute of a presence stanza is optional. A presence stanza
|
20
|
+
# that does not possess a `type` attribute is used to signal to the server
|
21
|
+
# that the sender is online and available for communication. If included,
|
22
|
+
# the `type` attribute specifies a lack of availability, a request to manage
|
23
|
+
# a subscription to another entity's presence, a request for another
|
24
|
+
# entity's current presence, or an error related to a previously-sent
|
25
|
+
# presence stanza. If included, the `type` attribute must have one of the
|
26
|
+
# following values:
|
27
|
+
#
|
28
|
+
# * `:unavailable` -- Signals that the entity is no longer available for
|
29
|
+
# communication
|
30
|
+
#
|
31
|
+
# * `:subscribe` -- The sender wishes to subscribe to the recipient's
|
32
|
+
# presence.
|
33
|
+
#
|
34
|
+
# * `:subscribed` -- The sender has allowed the recipient to receive their
|
35
|
+
# presence.
|
36
|
+
#
|
37
|
+
# * `:unsubscribe` -- The sender is unsubscribing from another entity's
|
38
|
+
# presence.
|
39
|
+
#
|
40
|
+
# * `:unsubscribed` -- The subscription request has been denied or a
|
41
|
+
# previously-granted subscription has been cancelled.
|
42
|
+
#
|
43
|
+
# * `:probe` -- A request for an entity's current presence; should be
|
44
|
+
# generated only by a server on behalf of a user.
|
45
|
+
#
|
46
|
+
# * `:error` -- An error has occurred regarding processing or delivery of a
|
47
|
+
# previously-sent presence stanza.
|
27
48
|
#
|
28
49
|
# Blather provides a helper for each possible type:
|
29
50
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
51
|
+
# Presence#unavailabe?
|
52
|
+
# Presence#unavailable?
|
53
|
+
# Presence#subscribe?
|
54
|
+
# Presence#subscribed?
|
55
|
+
# Presence#unsubscribe?
|
56
|
+
# Presence#unsubscribed?
|
57
|
+
# Presence#probe?
|
58
|
+
# Presence#error?
|
38
59
|
#
|
39
|
-
# Blather treats the
|
40
|
-
# The default
|
60
|
+
# Blather treats the `type` attribute like a normal ruby object attribute
|
61
|
+
# providing a getter and setter. The default `type` is nil.
|
41
62
|
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
63
|
+
# presence = Presence.new
|
64
|
+
# presence.type # => nil
|
65
|
+
# presence.type = :unavailable
|
66
|
+
# presence.unavailable? # => true
|
67
|
+
# presence.error? # => false
|
47
68
|
#
|
48
|
-
#
|
69
|
+
# presence.type = :invalid # => RuntimeError
|
49
70
|
#
|
71
|
+
# @handler :presence
|
50
72
|
class Presence < Stanza
|
51
|
-
VALID_TYPES = [:unavailable,
|
73
|
+
VALID_TYPES = [ :unavailable,
|
74
|
+
:subscribe,
|
75
|
+
:subscribed,
|
76
|
+
:unsubscribe,
|
77
|
+
:unsubscribed,
|
78
|
+
:probe,
|
79
|
+
:error].freeze
|
52
80
|
|
53
81
|
register :presence
|
54
82
|
|
55
|
-
##
|
56
83
|
# Creates a class based on the presence type
|
57
84
|
# either a Status or Subscription object is created based
|
58
85
|
# on the type attribute.
|
@@ -66,18 +93,67 @@ class Stanza
|
|
66
93
|
klass.new.inherit(node)
|
67
94
|
end
|
68
95
|
|
69
|
-
##
|
70
96
|
# Ensure element_name is "presence" for all subclasses
|
71
97
|
def self.new
|
72
98
|
super :presence
|
73
99
|
end
|
74
100
|
|
75
|
-
|
101
|
+
# Check if the IQ is of type :unavailable
|
102
|
+
#
|
103
|
+
# @return [true, false]
|
104
|
+
def unavailable?
|
105
|
+
self.type == :unavailable
|
106
|
+
end
|
76
107
|
|
77
|
-
|
78
|
-
#
|
79
|
-
|
80
|
-
|
108
|
+
# Check if the IQ is of type :subscribe
|
109
|
+
#
|
110
|
+
# @return [true, false]
|
111
|
+
def subscribe?
|
112
|
+
self.type == :subscribe
|
113
|
+
end
|
114
|
+
|
115
|
+
# Check if the IQ is of type :subscribed
|
116
|
+
#
|
117
|
+
# @return [true, false]
|
118
|
+
def subscribed?
|
119
|
+
self.type == :subscribed
|
120
|
+
end
|
121
|
+
|
122
|
+
# Check if the IQ is of type :unsubscribe
|
123
|
+
#
|
124
|
+
# @return [true, false]
|
125
|
+
def unsubscribe?
|
126
|
+
self.type == :unsubscribe
|
127
|
+
end
|
128
|
+
|
129
|
+
# Check if the IQ is of type :unsubscribed
|
130
|
+
#
|
131
|
+
# @return [true, false]
|
132
|
+
def unsubscribed?
|
133
|
+
self.type == :unsubscribed
|
134
|
+
end
|
135
|
+
|
136
|
+
# Check if the IQ is of type :probe
|
137
|
+
#
|
138
|
+
# @return [true, false]
|
139
|
+
def probe?
|
140
|
+
self.type == :probe
|
141
|
+
end
|
142
|
+
|
143
|
+
# Check if the IQ is of type :error
|
144
|
+
#
|
145
|
+
# @return [true, false]
|
146
|
+
def error?
|
147
|
+
self.type == :error
|
148
|
+
end
|
149
|
+
|
150
|
+
# Ensures type is one of Blather::Stanza::Presence::VALID_TYPES
|
151
|
+
#
|
152
|
+
# @param [#to_sym] type the Presence type. Must be one of VALID_TYPES
|
153
|
+
def type=(type)
|
154
|
+
if type && !VALID_TYPES.include?(type.to_sym)
|
155
|
+
raise ArgumentError, "Invalid Type (#{type}), use: #{VALID_TYPES*' '}"
|
156
|
+
end
|
81
157
|
super
|
82
158
|
end
|
83
159
|
|
@@ -2,73 +2,89 @@ module Blather
|
|
2
2
|
class Stanza
|
3
3
|
class Presence
|
4
4
|
|
5
|
-
#
|
5
|
+
# # Status Stanza
|
6
6
|
#
|
7
|
-
#
|
8
|
-
# various sub-states of the latter and optional user-defined descriptive text), and to notify other entities of
|
9
|
-
# that availability.
|
7
|
+
# [RFC 3921 Section 2.2.2 - Presence Child Elements](http://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2)
|
10
8
|
#
|
11
|
-
#
|
9
|
+
# Presence stanzas are used to express an entity's current network
|
10
|
+
# availability (offline or online, along with various sub-states of the
|
11
|
+
# latter and optional user-defined descriptive text), and to notify other
|
12
|
+
# entities of that availability.
|
12
13
|
#
|
13
|
-
#
|
14
|
+
# ## "State" Attribute
|
14
15
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# *
|
19
|
-
#
|
16
|
+
# The `state` attribute determains the availability of the entity and can be
|
17
|
+
# one of the following:
|
18
|
+
#
|
19
|
+
# * `:available` -- The entity or resource is available
|
20
|
+
#
|
21
|
+
# * `:away` -- The entity or resource is temporarily away.
|
22
|
+
#
|
23
|
+
# * `:chat` -- The entity or resource is actively interested in chatting.
|
24
|
+
#
|
25
|
+
# * `:dnd` -- The entity or resource is busy (dnd = "Do Not Disturb").
|
26
|
+
#
|
27
|
+
# * `:xa` -- The entity or resource is away for an extended period (xa =
|
28
|
+
# "eXtended Away").
|
20
29
|
#
|
21
30
|
# Blather provides a helper for each possible state:
|
22
31
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
32
|
+
# Status#available?
|
33
|
+
# Status#away?
|
34
|
+
# Status#chat?
|
35
|
+
# Status#dnd?
|
36
|
+
# Status#xa?
|
37
|
+
#
|
38
|
+
# Blather treats the `type` attribute like a normal ruby object attribute
|
39
|
+
# providing a getter and setter. The default `type` is `available`.
|
28
40
|
#
|
29
|
-
#
|
30
|
-
#
|
41
|
+
# status = Status.new
|
42
|
+
# status.state # => :available
|
43
|
+
# status.available? # => true
|
44
|
+
# status.state = :away
|
45
|
+
# status.away? # => true
|
46
|
+
# status.available? # => false
|
47
|
+
# status
|
48
|
+
# status.state = :invalid # => RuntimeError
|
31
49
|
#
|
32
|
-
#
|
33
|
-
# status.state # => :available
|
34
|
-
# status.available? # => true
|
35
|
-
# status.state = :away
|
36
|
-
# status.away? # => true
|
37
|
-
# status.available? # => false
|
38
|
-
# status
|
39
|
-
# status.state = :invalid # => RuntimeError
|
50
|
+
# ## "Type" Attribute
|
40
51
|
#
|
41
|
-
#
|
52
|
+
# The `type` attribute is inherited from Presence, but limits the value to
|
53
|
+
# either `nil` or `:unavailable` as these are the only types that relate to
|
54
|
+
# Status.
|
42
55
|
#
|
43
|
-
#
|
44
|
-
# as these are the only types that relate to Status.
|
56
|
+
# ## "Priority" Attribute
|
45
57
|
#
|
46
|
-
#
|
58
|
+
# The `priority` attribute sets the priority of the status for the entity
|
59
|
+
# and must be an integer between -128 and 127.
|
47
60
|
#
|
48
|
-
#
|
49
|
-
# -128 and 127.
|
61
|
+
# ## "Message" Attribute
|
50
62
|
#
|
51
|
-
#
|
63
|
+
# The optional `message` element contains XML character data specifying a
|
64
|
+
# natural-language description of availability status. It is normally used
|
65
|
+
# in conjunction with the show element to provide a detailed description of
|
66
|
+
# an availability state (e.g., "In a meeting").
|
52
67
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# description of an availability state (e.g., "In a meeting").
|
56
|
-
#
|
57
|
-
# Blather treats the +message+ attribute like a normal ruby object attribute providing a getter and setter.
|
58
|
-
# The default +message+ is nil.
|
68
|
+
# Blather treats the `message` attribute like a normal ruby object attribute
|
69
|
+
# providing a getter and setter. The default `message` is nil.
|
59
70
|
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
71
|
+
# status = Status.new
|
72
|
+
# status.message # => nil
|
73
|
+
# status.message = "gone!"
|
74
|
+
# status.message # => "gone!"
|
64
75
|
#
|
76
|
+
# @handler :status
|
65
77
|
class Status < Presence
|
66
|
-
VALID_STATES = [:away, :chat, :dnd, :xa]
|
78
|
+
VALID_STATES = [:away, :chat, :dnd, :xa].freeze
|
67
79
|
|
68
80
|
include Comparable
|
69
81
|
|
70
82
|
register :status, :status
|
71
83
|
|
84
|
+
# Create a new Status stanza
|
85
|
+
#
|
86
|
+
# @param [<:away, :chat, :dnd, :xa>] state the state of the status
|
87
|
+
# @param [#to_s] message a message to send with the status
|
72
88
|
def self.new(state = nil, message = nil)
|
73
89
|
node = super()
|
74
90
|
node.state = state
|
@@ -76,48 +92,112 @@ class Presence
|
|
76
92
|
node
|
77
93
|
end
|
78
94
|
|
79
|
-
|
95
|
+
# Check if the state is available
|
96
|
+
#
|
97
|
+
# @return [true, false]
|
98
|
+
def available?
|
99
|
+
self.state == :available
|
100
|
+
end
|
101
|
+
|
102
|
+
# Check if the state is away
|
103
|
+
#
|
104
|
+
# @return [true, false]
|
105
|
+
def away?
|
106
|
+
self.state == :away
|
107
|
+
end
|
108
|
+
|
109
|
+
# Check if the state is chat
|
110
|
+
#
|
111
|
+
# @return [true, false]
|
112
|
+
def chat?
|
113
|
+
self.state == :chat
|
114
|
+
end
|
115
|
+
|
116
|
+
# Check if the state is dnd
|
117
|
+
#
|
118
|
+
# @return [true, false]
|
119
|
+
def dnd?
|
120
|
+
self.state == :dnd
|
121
|
+
end
|
122
|
+
|
123
|
+
# Check if the state is xa
|
124
|
+
#
|
125
|
+
# @return [true, false]
|
126
|
+
def xa?
|
127
|
+
self.state == :xa
|
128
|
+
end
|
80
129
|
|
81
|
-
|
130
|
+
# Set the type attribute
|
82
131
|
# Ensures type is nil or :unavailable
|
83
|
-
|
84
|
-
|
132
|
+
#
|
133
|
+
# @param [<:unavailable, nil>] type the type
|
134
|
+
def type=(type)
|
135
|
+
if type && type.to_sym != :unavailable
|
136
|
+
raise ArgumentError, "Invalid type (#{type}). Must be nil or unavailable"
|
137
|
+
end
|
85
138
|
super
|
86
139
|
end
|
87
140
|
|
88
|
-
|
141
|
+
# Set the state
|
89
142
|
# Ensure state is one of :available, :away, :chat, :dnd, :xa or nil
|
143
|
+
#
|
144
|
+
# @param [<:available, :away, :chat, :dnd, :xa, nil>] state
|
90
145
|
def state=(state) # :nodoc:
|
91
146
|
state = state.to_sym if state
|
92
147
|
state = nil if state == :available
|
93
|
-
|
148
|
+
if state && !VALID_STATES.include?(state)
|
149
|
+
raise ArgumentError, "Invalid Status (#{state}), use: #{VALID_STATES*' '}"
|
150
|
+
end
|
94
151
|
|
95
152
|
set_content_for :show, state
|
96
153
|
end
|
97
154
|
|
98
|
-
|
99
|
-
#
|
100
|
-
|
155
|
+
# Get the state of the status
|
156
|
+
#
|
157
|
+
# @return [<:available, :away, :chat, :dnd, :xa>]
|
158
|
+
def state
|
101
159
|
state = type || content_from(:show)
|
102
160
|
state = :available if state.blank?
|
103
161
|
state.to_sym
|
104
162
|
end
|
105
163
|
|
106
|
-
|
107
|
-
#
|
164
|
+
# Set the priority of the status
|
165
|
+
# Ensures priority is between -128 and 127
|
166
|
+
#
|
167
|
+
# @param [Fixnum<-128...127>] new_priority
|
108
168
|
def priority=(new_priority) # :nodoc:
|
109
|
-
|
169
|
+
if new_priority && !(-128..127).include?(new_priority.to_i)
|
170
|
+
raise ArgumentError, 'Priority must be between -128 and +127'
|
171
|
+
end
|
110
172
|
set_content_for :priority, new_priority
|
111
|
-
|
112
173
|
end
|
113
174
|
|
114
|
-
|
175
|
+
# Get the priority of the status
|
176
|
+
#
|
177
|
+
# @return [Fixnum<-128...127>]
|
178
|
+
def priority
|
179
|
+
read_content(:priority).to_i
|
180
|
+
end
|
115
181
|
|
116
|
-
|
182
|
+
# Get the status message
|
183
|
+
#
|
184
|
+
# @return [String, nil]
|
185
|
+
def message
|
186
|
+
read_content :status
|
187
|
+
end
|
188
|
+
|
189
|
+
# Set the status message
|
190
|
+
#
|
191
|
+
# @param [String, nil] message
|
192
|
+
def message=(message)
|
193
|
+
set_content_for :status, message
|
194
|
+
end
|
117
195
|
|
118
|
-
##
|
119
196
|
# Compare status based on priority
|
120
197
|
# raises an error if the JIDs aren't the same
|
198
|
+
#
|
199
|
+
# @param [Blather::Stanza::Presence::Status] o
|
200
|
+
# @return [true,false]
|
121
201
|
def <=>(o)
|
122
202
|
unless self.from && o.from && self.from.stripped == o.from.stripped
|
123
203
|
raise ArgumentError, "Cannot compare status from different JIDs: #{[self.from, o.from].inspect}"
|