vines 0.4.9 → 0.4.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4a444c695d79a88f165a9f86f2989eb27e128e79
4
- data.tar.gz: 3b271ce86f7ada201e8788daef5d8c207190615b
3
+ metadata.gz: 377b65dfeb6ebd0ed33d7dcd0ddb99e125114597
4
+ data.tar.gz: 0a3addc473971d37aad7c4011909e22162fcf382
5
5
  SHA512:
6
- metadata.gz: 8c258a7e3237ec24854ade1d9ac66de591440c48635e4a184a89abe0bf9171f4b48fea23f391fe665da6938a2d0c2964f4b0beb99e4f8959f1e225477fec0fa7
7
- data.tar.gz: 30f2397168e45ac1e8ed911b6110750b2deb823f64e1f0908a60355f5a6732d4d938fa370945156b18c662e4091f8cb88653065a073c79dd7c1ebe728a48a1b8
6
+ metadata.gz: a10339115953bedabc5b5fae4ec56cd4281f4ac9ecc9b5484a870826f687238240d48350bd7b1dadc99f5d88b6bf5710572542794a74c3332dc8fe15a3a0ba5d
7
+ data.tar.gz: 8d65071c1112f5df81cbb347060f9a416520809f4d794b99bab6a1cfee4bc2c532ff299fa2fb8a8bb793df942dd56253351336189772de7d0a674169693213ff
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Welcome to Vines
1
+ # Vines XMPP Server
2
2
 
3
3
  Vines is an XMPP chat server that supports thousands of simultaneous connections,
4
4
  using EventMachine for asynchronous IO. User data is stored in a
@@ -72,6 +72,7 @@ end
72
72
  resolv
73
73
  set
74
74
  socket
75
+ uri
75
76
  yaml
76
77
 
77
78
  vines/cli
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Vines
4
4
  class Cluster
5
- # Subscribes to the redis nodes:all broadcast channel to listen for
5
+ # Subscribes to the redis `nodes:all` broadcast channel to listen for
6
6
  # heartbeats from other cluster members. Also subscribes to a channel
7
7
  # exclusively for this particular node, listening for stanzas routed to us
8
8
  # from other nodes.
@@ -22,6 +22,8 @@ module Vines
22
22
  # Create a new redis connection and subscribe to the nodes:all broadcast
23
23
  # channel as well as the channel for this cluster node. Redis connections
24
24
  # in subscribe mode cannot be used for other key/value operations.
25
+ #
26
+ # Returns nothing.
25
27
  def subscribe
26
28
  conn = @cluster.connect
27
29
  conn.subscribe(ALL)
@@ -35,6 +37,8 @@ module Vines
35
37
 
36
38
  # Recursively process incoming messages from the queue, guaranteeing they
37
39
  # are processed in the order they are received.
40
+ #
41
+ # Returns nothing.
38
42
  def process_messages
39
43
  @messages.pop do |channel, message|
40
44
  Fiber.new do
@@ -46,6 +50,11 @@ module Vines
46
50
 
47
51
  # Process messages as they arrive on the pubsub channels to which we're
48
52
  # subscribed.
53
+ #
54
+ # channel - The String channel name on which the message was received.
55
+ # message - The JSON formatted message String.
56
+ #
57
+ # Returns nothing.
49
58
  def on_message(channel, message)
50
59
  doc = JSON.parse(message)
51
60
  case channel
@@ -56,9 +65,13 @@ module Vines
56
65
  log.error("Cluster subscription message failed: #{e}")
57
66
  end
58
67
 
59
- # Process a message sent to the nodes:all broadcast channel. In the case
68
+ # Process a message sent to the `nodes:all` broadcast channel. In the case
60
69
  # of node heartbeats, we update the last time we heard from this node so
61
70
  # we can cleanup its session if it goes offline.
71
+ #
72
+ # message - The parsed Hash of received message data.
73
+ #
74
+ # Returns nothing.
62
75
  def to_all(message)
63
76
  case message[TYPE]
64
77
  when ONLINE, HEARTBEAT
@@ -71,6 +84,10 @@ module Vines
71
84
  # Process a message published to this node's channel. Messages sent to
72
85
  # this channel are stanzas that need to be routed to connections attached
73
86
  # to this node.
87
+ #
88
+ # message - The parsed Hash of received message data.
89
+ #
90
+ # Returns nothing.
74
91
  def to_node(message)
75
92
  case message[TYPE]
76
93
  when STANZA then route_stanza(message)
@@ -80,6 +97,10 @@ module Vines
80
97
 
81
98
  # Send the stanza, from a remote cluster node, to locally connected
82
99
  # streams for the destination user.
100
+ #
101
+ # message - The parsed Hash of received message data.
102
+ #
103
+ # Returns nothing.
83
104
  def route_stanza(message)
84
105
  node = Nokogiri::XML(message[STANZA]).root rescue nil
85
106
  return unless node
@@ -95,6 +116,10 @@ module Vines
95
116
 
96
117
  # Update the roster information, that's cached in locally connected
97
118
  # streams, for this user.
119
+ #
120
+ # message - The parsed Hash of received message data.
121
+ #
122
+ # Returns nothing.
98
123
  def update_user(message)
99
124
  jid = JID.new(message['jid']).bare
100
125
  if user = @cluster.storage(jid.domain).find_user(jid)
@@ -10,6 +10,10 @@ module Vines
10
10
 
11
11
  # Register a nickname that can be used in the config file to specify this
12
12
  # storage implementation.
13
+ #
14
+ # name - The String name for this storage backend.
15
+ #
16
+ # Returns nothing.
13
17
  def self.register(name)
14
18
  @@nicks[name.to_sym] = self
15
19
  end
@@ -25,15 +29,18 @@ module Vines
25
29
  # with blocking IO don't need to worry about threading or blocking the
26
30
  # EventMachine reactor thread if they wrap their methods with this one.
27
31
  #
28
- # For example:
29
- # def find_user(jid)
30
- # some_blocking_lookup(jid)
31
- # end
32
- # defer :find_user
32
+ # Examples
33
+ #
34
+ # def find_user(jid)
35
+ # some_blocking_lookup(jid)
36
+ # end
37
+ # defer :find_user
33
38
  #
34
39
  # Storage classes that use asynchronous IO (through an EventMachine
35
40
  # enabled library like em-http-request or em-redis) don't need any special
36
41
  # consideration and must not use this method.
42
+ #
43
+ # Returns nothing.
37
44
  def self.defer(method)
38
45
  old = instance_method(method)
39
46
  define_method method do |*args|
@@ -50,11 +57,14 @@ module Vines
50
57
  # authenticate method as usual. This allows storage classes to implement
51
58
  # their native authentication logic and not worry about handling LDAP.
52
59
  #
53
- # For example:
54
- # def authenticate(username, password)
55
- # some_user_lookup_by_password(username, password)
56
- # end
57
- # wrap_ldap :authenticate
60
+ # Examples
61
+ #
62
+ # def authenticate(username, password)
63
+ # some_user_lookup_by_password(username, password)
64
+ # end
65
+ # wrap_ldap :authenticate
66
+ #
67
+ # Returns nothing.
58
68
  def self.wrap_ldap(method)
59
69
  old = instance_method(method)
60
70
  define_method method do |*args|
@@ -64,21 +74,24 @@ module Vines
64
74
 
65
75
  # Wrap a method with Fiber yield and resume logic. The method must yield
66
76
  # its result to a block. This makes it easier to write asynchronous
67
- # implementations of +authenticate+, +find_user+, and +save_user+ that
77
+ # implementations of `authenticate`, `find_user`, and `save_user` that
68
78
  # block and return a result rather than yielding.
69
79
  #
70
- # For example:
71
- # def find_user(jid)
72
- # http = EM::HttpRequest.new(url).get
73
- # http.callback { yield build_user_from_http_response(http) }
74
- # end
75
- # fiber :find_user
80
+ # Examples
76
81
  #
77
- # Because +find_user+ has been wrapped in Fiber logic, we can call it
82
+ # def find_user(jid)
83
+ # http = EM::HttpRequest.new(url).get
84
+ # http.callback { yield build_user_from_http_response(http) }
85
+ # end
86
+ # fiber :find_user
87
+ #
88
+ # Because `find_user` has been wrapped in Fiber logic, we can call it
78
89
  # synchronously even though it uses asynchronous EventMachine calls.
79
90
  #
80
- # user = storage.find_user('alice@wonderland.lit')
81
- # puts user.nil?
91
+ # user = storage.find_user('alice@wonderland.lit')
92
+ # puts user.nil?
93
+ #
94
+ # Returns nothing.
82
95
  def self.fiber(method)
83
96
  old = instance_method(method)
84
97
  define_method method do |*args|
@@ -90,21 +103,26 @@ module Vines
90
103
  end
91
104
  end
92
105
 
93
- # Return +true+ if users are authenticated against an LDAP directory.
106
+ # Return true if users are authenticated against an LDAP directory.
94
107
  def ldap?
95
108
  !!ldap
96
109
  end
97
110
 
98
- # Validate the username and password pair and return a +Vines::User+ object
99
- # on success. Return +nil+ on failure.
111
+ # Validate the username and password pair.
112
+ #
113
+ # username - The String login JID to verify.
114
+ # password - The String password the user presented to the server.
100
115
  #
101
- # For example:
102
- # user = storage.authenticate('alice@wonderland.lit', 'secr3t')
103
- # puts user.nil?
116
+ # Examples
117
+ #
118
+ # user = storage.authenticate('alice@wonderland.lit', 'secr3t')
119
+ # puts user.nil?
104
120
  #
105
121
  # This default implementation validates the password against a bcrypt hash
106
122
  # of the password stored in the database. Sub-classes not using bcrypt
107
123
  # passwords must override this method.
124
+ #
125
+ # Returns a Vines::User object on success, nil on failure.
108
126
  def authenticate(username, password)
109
127
  user = find_user(username)
110
128
  hash = BCrypt::Password.new(user.password) rescue nil
@@ -112,92 +130,141 @@ module Vines
112
130
  end
113
131
  wrap_ldap :authenticate
114
132
 
115
- # Return the +Vines::User+ associated with the JID. Return +nil+ if the user
116
- # could not be found. JID may be +nil+, a +String+, or a +Vines::JID+
117
- # object. It may be a bare JID or a full JID. Implementations of this method
118
- # must convert the JID to a bare JID before searching for the user in the
119
- # database.
133
+ # Find the user in the storage database by their unique JID.
120
134
  #
121
- # user = storage.find_user('alice@wonderland.lit')
122
- # puts user.nil?
135
+ # jid - The String or JID of the user, possibly nil. This may be either a
136
+ # bare JID or full JID. Implementations of this method must convert
137
+ # the JID to a bare JID before searching for the user in the database.
138
+ #
139
+ # Examples
140
+ #
141
+ # # Bare JID lookup.
142
+ # user = storage.find_user('alice@wonderland.lit')
143
+ # puts user.nil?
144
+ #
145
+ # # Full JID lookup.
146
+ # user = storage.find_user('alice@wonderland.lit/tea')
147
+ # puts user.nil?
148
+ #
149
+ # Returns the User identified by the JID, nil if not found.
123
150
  def find_user(jid)
124
151
  raise 'subclass must implement'
125
152
  end
126
153
 
127
- # Persist the +Vines::User+ object to the database and return when the save
128
- # is complete.
154
+ # Persist the user to the database, and return when the save is complete.
155
+ #
156
+ # user - The User to persist.
129
157
  #
130
- # alice = Vines::User.new(:jid => 'alice@wonderland.lit')
131
- # storage.save_user(alice)
132
- # puts 'saved'
158
+ # Examples
159
+ #
160
+ # alice = Vines::User.new(jid: 'alice@wonderland.lit')
161
+ # storage.save_user(alice)
162
+ # puts 'saved'
163
+ #
164
+ # Returns nothing.
133
165
  def save_user(user)
134
166
  raise 'subclass must implement'
135
167
  end
136
168
 
137
- # Return the Nokogiri::XML::Node for the vcard stored for this JID. Return
138
- # nil if the vcard could not be found. JID may be +nil+, a +String+, or a
139
- # +Vines::JID+ object. It may be a bare JID or a full JID. Implementations
140
- # of this method must convert the JID to a bare JID before searching for the
141
- # vcard in the database.
169
+ # Find the user's vcard by their unique JID.
170
+ #
171
+ # jid - The String or JID of the user, possibly nil. This may be either a
172
+ # bare JID or full JID. Implementations of this method must convert
173
+ # the JID to a bare JID before searching for the vcard in the database.
174
+ #
175
+ # Examples
176
+ #
177
+ # card = storage.find_vcard('alice@wonderland.lit')
178
+ # puts card.nil?
142
179
  #
143
- # card = storage.find_vcard('alice@wonderland.lit')
144
- # puts card.nil?
180
+ # Returns the vcard's Nokogiri::XML::Node, nil if not found.
145
181
  def find_vcard(jid)
146
182
  raise 'subclass must implement'
147
183
  end
148
184
 
149
- # Save the vcard to the database and return when the save is complete. JID
150
- # may be a +String+ or a +Vines::JID+ object. It may be a bare JID or a
151
- # full JID. Implementations of this method must convert the JID to a bare
152
- # JID before saving the vcard. Card is a +Nokogiri::XML::Node+ object.
185
+ # Save the vcard to the database, and return when the save is complete.
153
186
  #
154
- # card = Nokogiri::XML('<vCard>...</vCard>').root
155
- # storage.save_vcard('alice@wonderland.lit', card)
156
- # puts 'saved'
187
+ # jid - The String or JID of the user, possibly nil. This may be either a
188
+ # bare JID or full JID. Implementations of this method must convert
189
+ # the JID to a bare JID before saving the vcard.
190
+ # card - The vcard's Nokogiri::XML::Node.
191
+ #
192
+ # Examples
193
+ #
194
+ # card = Nokogiri::XML('<vCard>...</vCard>').root
195
+ # storage.save_vcard('alice@wonderland.lit', card)
196
+ # puts 'saved'
197
+ #
198
+ # Returns nothing.
157
199
  def save_vcard(jid, card)
158
200
  raise 'subclass must implement'
159
201
  end
160
202
 
161
- # Return the Nokogiri::XML::Node for the XML fragment stored for this JID.
162
- # Return nil if the fragment could not be found. JID may be +nil+, a
163
- # +String+, or a +Vines::JID+ object. It may be a bare JID or a full JID.
164
- # Implementations of this method must convert the JID to a bare JID before
165
- # searching for the fragment in the database.
166
- #
167
- # Private XML storage uniquely identifies fragments by JID, root element name,
203
+ # Find the private XML fragment previously stored by the user. Private
204
+ # XML storage uniquely identifies fragments by JID, root element name,
168
205
  # and root element namespace.
169
206
  #
170
- # root = Nokogiri::XML('<custom xmlns="urn:custom:ns"/>').root
171
- # fragment = storage.find_fragment('alice@wonderland.lit', root)
172
- # puts fragment.nil?
207
+ # jid - The String or JID of the user, possibly nil. This may be either a
208
+ # bare JID or full JID. Implementations of this method must convert
209
+ # the JID to a bare JID before searching for the fragment in the database.
210
+ # node - The XML::Node that uniquely identifies the fragment by element
211
+ # name and namespace.
212
+ #
213
+ # Examples
214
+ #
215
+ # root = Nokogiri::XML('<custom xmlns="urn:custom:ns"/>').root
216
+ # fragment = storage.find_fragment('alice@wonderland.lit', root)
217
+ # puts fragment.nil?
218
+ #
219
+ # Returns the fragment's Nokogiri::XML::Node or nil if not found.
173
220
  def find_fragment(jid, node)
174
221
  raise 'subclass must implement'
175
222
  end
176
223
 
177
- # Save the XML fragment to the database and return when the save is complete.
178
- # JID may be a +String+ or a +Vines::JID+ object. It may be a bare JID or a
179
- # full JID. Implementations of this method must convert the JID to a bare
180
- # JID before saving the fragment. Fragment is a +Nokogiri::XML::Node+ object.
224
+ # Save the XML fragment to the database, and return when the save is complete.
225
+ #
226
+ # jid - The String or JID of the user, possibly nil. This may be
227
+ # either a bare JID or full JID. Implementations of this method
228
+ # must convert the JID to a bare JID before searching for the
229
+ # fragment.
230
+ # fragment - The XML::Node to save.
231
+ #
232
+ # Examples
181
233
  #
182
- # fragment = Nokogiri::XML('<custom xmlns="urn:custom:ns">some data</custom>').root
183
- # storage.save_fragment('alice@wonderland.lit', fragment)
184
- # puts 'saved'
234
+ # fragment = Nokogiri::XML('<custom xmlns="urn:custom:ns">some data</custom>').root
235
+ # storage.save_fragment('alice@wonderland.lit', fragment)
236
+ # puts 'saved'
237
+ #
238
+ # Returns nothing.
185
239
  def save_fragment(jid, fragment)
186
240
  raise 'subclass must implement'
187
241
  end
188
242
 
189
243
  private
190
244
 
191
- # Return true if any of the arguments are nil or empty strings.
192
- # For example:
193
- # username, password = 'alice@wonderland.lit', ''
194
- # empty?(username, password) #=> true
245
+ # Determine if any of the arguments are nil or empty strings.
246
+ #
247
+ # Examples
248
+ #
249
+ # username, password = 'alice@wonderland.lit', ''
250
+ # empty?(username, password) #=> true
251
+ #
252
+ # Returns true if any of the arguments are nil or empty strings.
195
253
  def empty?(*args)
196
254
  args.flatten.any? {|arg| (arg || '').strip.empty? }
197
255
  end
198
256
 
199
- # Return a +proc+ suitable for running on the +EM.defer+ thread pool that traps
200
- # and logs any errors thrown by the provided block.
257
+ # Create a proc suitable for running on the EM.defer thread pool, that
258
+ # traps and logs any errors thrown by the provided block.
259
+ #
260
+ # block - The block to wrap in error handling.
261
+ #
262
+ # Examples
263
+ #
264
+ # op = operation { do_something_on_thread_pool() }
265
+ # EM.defer(op)
266
+ #
267
+ # Returns a Proc.
201
268
  def operation
202
269
  proc do
203
270
  begin
@@ -209,10 +276,15 @@ module Vines
209
276
  end
210
277
  end
211
278
 
212
- # Return a +Vines::User+ object if we are able to bind to the LDAP server
213
- # using the username and password. Return +nil+ if authentication failed. If
279
+ # Bind to the LDAP server using the provided username and password. If
214
280
  # authentication succeeds, but the user is not yet stored in our database,
215
281
  # save the user to the database.
282
+ #
283
+ # username - The String JID to authenticate.
284
+ # password - The String password the user provided.
285
+ # block - The block that receives the authenticated User or nil.
286
+ #
287
+ # Returns the authenticated User or nil if authentication failed.
216
288
  def authenticate_with_ldap(username, password, &block)
217
289
  op = operation { ldap.authenticate(username, password) }
218
290
  cb = proc {|user| save_ldap_user(user, &block) }
@@ -220,9 +292,14 @@ module Vines
220
292
  end
221
293
  fiber :authenticate_with_ldap
222
294
 
223
- # Save missing users to the storage database after they're authenticated with
224
- # LDAP. This allows admins to define users once in LDAP and have them sync
225
- # to the chat database the first time they successfully sign in.
295
+ # Save missing users to the storage database after they're authenticated
296
+ # with LDAP. This allows admins to define users once in LDAP and have them
297
+ # sync to the chat database the first time they successfully sign in.
298
+ #
299
+ # user - The User to persist, possibly nil.
300
+ # block - The block that receives the saved User, possibly nil.
301
+ #
302
+ # Returns nothing.
226
303
  def save_ldap_user(user, &block)
227
304
  Fiber.new do
228
305
  if user.nil?