Class: Vines::Storage

Inherits:
Object
  • Object
show all
Includes:
Log
Defined in:
lib/vines/storage.rb,
lib/vines/storage/sql.rb,
lib/vines/storage/ldap.rb,
lib/vines/storage/null.rb,
lib/vines/storage/local.rb

Direct Known Subclasses

Local, Null, Sql

Defined Under Namespace

Classes: Ldap, Local, Null, Sql

Constant Summary collapse

@@nicks =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Log

#log

Instance Attribute Details

#ldapObject

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.

For example: 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.



37
38
39
40
41
42
43
44
45
46
# File 'lib/vines/storage.rb', line 37

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.

For example: 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?



82
83
84
85
86
87
88
89
90
91
# File 'lib/vines/storage.rb', line 82

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



17
18
19
20
21
# File 'lib/vines/storage.rb', line 17

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.



13
14
15
# File 'lib/vines/storage.rb', line 13

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.

For example: def authenticate(username, password)

some_user_lookup_by_password(username, password)

end wrap_ldap :authenticate



58
59
60
61
62
63
# File 'lib/vines/storage.rb', line 58

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 and return a Vines::User object on success. Return nil on failure.

For example: 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.



108
109
110
111
112
# File 'lib/vines/storage.rb', line 108

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

Return the Nokogiri::XML::Node for the XML fragment stored for this JID. Return nil if the fragment could not be found. JID may be nil, a String, or a Vines::JID object. It may be a bare JID or a full JID. Implementations of this method must convert the JID to a bare JID before searching for the fragment in the database.

Private XML storage uniquely identifies fragments by JID, root element name, and root element namespace.

root = Nokogiri::XML(‘<custom xmlns=“urn:custom:ns”/>’).root fragment = storage.find_fragment(‘[email protected]’, root) puts fragment.nil?



173
174
175
# File 'lib/vines/storage.rb', line 173

def find_fragment(jid, node)
  raise 'subclass must implement'
end

#find_user(jid) ⇒ Object

Return the Vines::User associated with the JID. Return nil if the user could not be found. JID may be nil, a String, or a Vines::JID object. It may be a bare JID or a full JID. Implementations of this method must convert the JID to a bare JID before searching for the user in the database.

user = storage.find_user(‘[email protected]’) puts user.nil?



123
124
125
# File 'lib/vines/storage.rb', line 123

def find_user(jid)
  raise 'subclass must implement'
end

#find_vcard(jid) ⇒ Object

Return the Nokogiri::XML::Node for the vcard stored for this JID. Return nil if the vcard could not be found. JID may be nil, a String, or a Vines::JID object. It may be a bare JID or a full JID. Implementations of this method must convert the JID to a bare JID before searching for the vcard in the database.

card = storage.find_vcard(‘[email protected]’) puts card.nil?



145
146
147
# File 'lib/vines/storage.rb', line 145

def find_vcard(jid)
  raise 'subclass must implement'
end

#ldap?Boolean

Return true if users are authenticated against an LDAP directory.

Returns:

  • (Boolean)


94
95
96
# File 'lib/vines/storage.rb', line 94

def ldap?
  !!ldap
end

#save_fragment(jid, fragment) ⇒ Object

Save the XML fragment to the database and return when the save is complete. JID may be a String or a Vines::JID object. It may be a bare JID or a full JID. Implementations of this method must convert the JID to a bare JID before saving the fragment. Fragment is a Nokogiri::XML::Node object.

fragment = Nokogiri::XML(‘<custom xmlns=“urn:custom:ns”>some data</custom>’).root storage.save_fragment(‘[email protected]’, fragment) puts ‘saved’



185
186
187
# File 'lib/vines/storage.rb', line 185

def save_fragment(jid, fragment)
  raise 'subclass must implement'
end

#save_user(user) ⇒ Object

Persist the Vines::User object to the database and return when the save is complete.

alice = Vines::User.new(:jid => ‘[email protected]’) storage.save_user(alice) puts ‘saved’



133
134
135
# File 'lib/vines/storage.rb', line 133

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 may be a String or a Vines::JID object. It may be a bare JID or a full JID. Implementations of this method must convert the JID to a bare JID before saving the vcard. Card is a Nokogiri::XML::Node object.

card = Nokogiri::XML(‘<vCard>…</vCard>’).root storage.save_vcard(‘[email protected]’, card) puts ‘saved’



157
158
159
# File 'lib/vines/storage.rb', line 157

def save_vcard(jid, card)
  raise 'subclass must implement'
end