Class: Vines::Storage

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

Direct Known Subclasses

Local, Null, Sql

Defined Under Namespace

Classes: Local, Null, Sql

Constant Summary collapse

@@nicks =
{}

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Log

#log

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.



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

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?



63
64
65
66
67
68
69
70
71
72
# File 'lib/vines/storage.rb', line 63

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



15
16
17
18
19
# File 'lib/vines/storage.rb', line 15

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.



11
12
13
# File 'lib/vines/storage.rb', line 11

def self.register(name)
  @@nicks[name.to_sym] = self
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.



84
85
86
87
88
# File 'lib/vines/storage.rb', line 84

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?



148
149
150
# File 'lib/vines/storage.rb', line 148

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?



98
99
100
# File 'lib/vines/storage.rb', line 98

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?



120
121
122
# File 'lib/vines/storage.rb', line 120

def find_vcard(jid)
  raise 'subclass must implement'
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’



160
161
162
# File 'lib/vines/storage.rb', line 160

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’



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

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’



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

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