Class: Vines::Storage
- Inherits:
-
Object
- Object
- Vines::Storage
- Includes:
- Log
- Defined in:
- lib/vines/storage.rb,
lib/vines/storage/sql.rb,
lib/vines/storage/null.rb,
lib/vines/storage/local.rb
Defined Under Namespace
Constant Summary collapse
- @@nicks =
{}
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.
Instance Method Summary collapse
-
#authenticate(username, password) ⇒ Object
Validate the username and password pair and return a
Vines::User
object on success. -
#find_fragment(jid, node) ⇒ Object
Return the Nokogiri::XML::Node for the XML fragment stored for this JID.
-
#find_user(jid) ⇒ Object
Return the
Vines::User
associated with the JID. -
#find_vcard(jid) ⇒ Object
Return the Nokogiri::XML::Node for the vcard stored for this JID.
-
#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
Vines::User
object 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
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 |