Class: Vines::Storage
- Inherits:
-
Object
- Object
- Vines::Storage
- Includes:
- Log
- Defined in:
- lib/vines/storage.rb,
lib/vines/storage/ldap.rb,
lib/vines/storage/null.rb,
lib/vines/storage/local.rb
Defined Under Namespace
Constant Summary collapse
- @@nicks =
{}
Instance Attribute Summary collapse
-
#ldap ⇒ Object
Returns the value of attribute ldap.
Class Method Summary collapse
-
.defer(method) ⇒ Object
Wrap a blocking IO method in a new method that pushes the original method onto EventMachine’s thread pool using EM#defer.
-
.fiber(method) ⇒ Object
Wrap a method with Fiber yield and resume logic.
- .from_name(name, &block) ⇒ Object
-
.register(name) ⇒ Object
Register a nickname that can be used in the config file to specify this storage implementation.
-
.wrap_ldap(method) ⇒ Object
Wrap an authenticate method with a new method that uses LDAP if it’s enabled in the config file.
Instance Method Summary collapse
-
#authenticate(username, password) ⇒ Object
Validate the username and password pair.
-
#find_fragment(jid, node) ⇒ Object
Find the private XML fragment previously stored by the user.
-
#find_user(jid) ⇒ Object
Find the user in the storage database by their unique JID.
-
#find_vcard(jid) ⇒ Object
Find the user’s vcard by their unique JID.
-
#ldap? ⇒ Boolean
Return true if users are authenticated against an LDAP directory.
-
#save_fragment(jid, fragment) ⇒ Object
Save the XML fragment to the database, and return when the save is complete.
-
#save_user(user) ⇒ Object
Persist the user to the database, and return when the save is complete.
-
#save_vcard(jid, card) ⇒ Object
Save the vcard to the database, and return when the save is complete.
Methods included from Log
Instance Attribute Details
#ldap ⇒ Object
Returns the value of attribute ldap.
7 8 9 |
# File 'lib/vines/storage.rb', line 7 def ldap @ldap end |
Class Method Details
.defer(method) ⇒ Object
Wrap a blocking IO method in a new method that pushes the original method onto EventMachine’s thread pool using EM#defer. Storage classes implemented with blocking IO don’t need to worry about threading or blocking the EventMachine reactor thread if they wrap their methods with this one.
Examples
def find_user(jid)
some_blocking_lookup(jid)
end
defer :find_user
Storage classes that use asynchronous IO (through an EventMachine enabled library like em-http-request or em-redis) don’t need any special consideration and must not use this method.
Returns nothing.
44 45 46 47 48 49 50 51 52 53 |
# File 'lib/vines/storage.rb', line 44 def self.defer(method) old = instance_method(method) define_method method do |*args| fiber = Fiber.current op = operation { old.bind(self).call(*args) } cb = proc {|result| fiber.resume(result) } EM.defer(op, cb) Fiber.yield end end |
.fiber(method) ⇒ Object
Wrap a method with Fiber yield and resume logic. The method must yield its result to a block. This makes it easier to write asynchronous implementations of ‘authenticate`, `find_user`, and `save_user` that block and return a result rather than yielding.
Examples
def find_user(jid)
http = EM::HttpRequest.new(url).get
http.callback { yield build_user_from_http_response(http) }
end
fiber :find_user
Because ‘find_user` has been wrapped in Fiber logic, we can call it synchronously even though it uses asynchronous EventMachine calls.
user = storage.find_user('[email protected]')
puts user.nil?
Returns nothing.
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/vines/storage.rb', line 95 def self.fiber(method) old = instance_method(method) define_method method do |*args| fiber, yielding = Fiber.current, true old.bind(self).call(*args) do |user| fiber.resume(user) rescue yielding = false end Fiber.yield if yielding end end |
.from_name(name, &block) ⇒ Object
21 22 23 24 25 |
# File 'lib/vines/storage.rb', line 21 def self.from_name(name, &block) klass = @@nicks[name.to_sym] raise "#{name} storage class not found" unless klass klass.new(&block) end |
.register(name) ⇒ Object
Register a nickname that can be used in the config file to specify this storage implementation.
name - The String name for this storage backend.
Returns nothing.
17 18 19 |
# File 'lib/vines/storage.rb', line 17 def self.register(name) @@nicks[name.to_sym] = self end |
.wrap_ldap(method) ⇒ Object
Wrap an authenticate method with a new method that uses LDAP if it’s enabled in the config file. If LDAP is not enabled, invoke the original authenticate method as usual. This allows storage classes to implement their native authentication logic and not worry about handling LDAP.
Examples
def authenticate(username, password)
some_user_lookup_by_password(username, password)
end
wrap_ldap :authenticate
Returns nothing.
68 69 70 71 72 73 |
# File 'lib/vines/storage.rb', line 68 def self.wrap_ldap(method) old = instance_method(method) define_method method do |*args| ldap? ? authenticate_with_ldap(*args) : old.bind(self).call(*args) end end |
Instance Method Details
#authenticate(username, password) ⇒ Object
Validate the username and password pair.
username - The String login JID to verify. password - The String password the user presented to the server.
Examples
user = storage.authenticate('[email protected]', 'secr3t')
puts user.nil?
This default implementation validates the password against a bcrypt hash of the password stored in the database. Sub-classes not using bcrypt passwords must override this method.
Returns a Vines::User object on success, nil on failure.
126 127 128 129 130 |
# File 'lib/vines/storage.rb', line 126 def authenticate(username, password) user = find_user(username) hash = BCrypt::Password.new(user.password) rescue nil (hash && hash == password) ? user : nil end |
#find_fragment(jid, node) ⇒ Object
Find the private XML fragment previously stored by the user. Private XML storage uniquely identifies fragments by JID, root element name, and root element namespace.
jid - The String or JID of the user, possibly nil. This may be either a
bare JID or full JID. Implementations of this method must convert
the JID to a bare JID before searching for the fragment in the database.
node - The XML::Node that uniquely identifies the fragment by element
name and namespace.
Examples
root = Nokogiri::XML('<custom xmlns="urn:custom:ns"/>').root
fragment = storage.find_fragment('[email protected]', root)
puts fragment.nil?
Returns the fragment’s Nokogiri::XML::Node or nil if not found.
220 221 222 |
# File 'lib/vines/storage.rb', line 220 def find_fragment(jid, node) raise 'subclass must implement' end |
#find_user(jid) ⇒ Object
Find the user in the storage database by their unique JID.
jid - The String or JID of the user, possibly nil. This may be either a
bare JID or full JID. Implementations of this method must convert
the JID to a bare JID before searching for the user in the database.
Examples
# Bare JID lookup.
user = storage.find_user('[email protected]')
puts user.nil?
# Full JID lookup.
user = storage.find_user('[email protected]/tea')
puts user.nil?
Returns the User identified by the JID, nil if not found.
150 151 152 |
# File 'lib/vines/storage.rb', line 150 def find_user(jid) raise 'subclass must implement' end |
#find_vcard(jid) ⇒ Object
Find the user’s vcard by their unique JID.
jid - The String or JID of the user, possibly nil. This may be either a
bare JID or full JID. Implementations of this method must convert
the JID to a bare JID before searching for the vcard in the database.
Examples
card = storage.find_vcard('[email protected]')
puts card.nil?
Returns the vcard’s Nokogiri::XML::Node, nil if not found.
181 182 183 |
# File 'lib/vines/storage.rb', line 181 def find_vcard(jid) raise 'subclass must implement' end |
#ldap? ⇒ Boolean
Return true if users are authenticated against an LDAP directory.
107 108 109 |
# File 'lib/vines/storage.rb', line 107 def ldap? !!ldap end |
#save_fragment(jid, fragment) ⇒ Object
Save the XML fragment to the database, and return when the save is complete.
jid - The String or JID of the user, possibly nil. This may be
either a bare JID or full JID. Implementations of this method
must convert the JID to a bare JID before searching for the
fragment.
fragment - The XML::Node to save.
Examples
fragment = Nokogiri::XML('<custom xmlns="urn:custom:ns">some data</custom>').root
storage.save_fragment('[email protected]', fragment)
puts 'saved'
Returns nothing.
239 240 241 |
# File 'lib/vines/storage.rb', line 239 def save_fragment(jid, fragment) raise 'subclass must implement' end |
#save_user(user) ⇒ Object
Persist the user to the database, and return when the save is complete.
user - The User to persist.
Examples
alice = Vines::User.new(jid: '[email protected]')
storage.save_user(alice)
puts 'saved'
Returns nothing.
165 166 167 |
# File 'lib/vines/storage.rb', line 165 def save_user(user) raise 'subclass must implement' end |
#save_vcard(jid, card) ⇒ Object
Save the vcard to the database, and return when the save is complete.
jid - The String or JID of the user, possibly nil. This may be either a
bare JID or full JID. Implementations of this method must convert
the JID to a bare JID before saving the vcard.
card - The vcard’s Nokogiri::XML::Node.
Examples
card = Nokogiri::XML('<vCard>...</vCard>').root
storage.save_vcard('[email protected]', card)
puts 'saved'
Returns nothing.
199 200 201 |
# File 'lib/vines/storage.rb', line 199 def save_vcard(jid, card) raise 'subclass must implement' end |