class Vines::Storage::Sql
Public Class Methods
new(&block)
click to toggle source
# File lib/vines/storage/sql.rb, line 51 def initialize(&block) @config = {} instance_eval(&block) required = [:adapter, :database] required << [:host, :port] unless @config[:adapter] == 'sqlite3' required.flatten.each {|key| raise "Must provide #{key}" unless @config[key] } [:username, :password].each {|key| @config.delete(key) if empty?(@config[key]) } establish_connection end
with_connection(method, args={})
click to toggle source
Wrap the method with ActiveRecord connection pool logic, so we properly return connections to the pool when we're finished with them. This also defers the original method by pushing it onto the EM thread pool because ActiveRecord uses blocking IO.
# File lib/vines/storage/sql.rb, line 30 def self.with_connection(method, args={}) deferrable = args.key?(:defer) ? args[:defer] : true old = instance_method(method) define_method method do |*args| ActiveRecord::Base.connection_pool.with_connection do old.bind(self).call(*args) end end defer(method) if deferrable end
Public Instance Methods
create_schema(args={})
click to toggle source
Create the tables and indexes used by this storage engine.
# File lib/vines/storage/sql.rb, line 177 def create_schema(args={}) args[:force] ||= false ActiveRecord::Schema.define do create_table :users, force: args[:force] do |t| t.string :jid, limit: 512, null: false t.string :name, limit: 256, null: true t.string :password, limit: 256, null: true t.text :vcard, null: true end add_index :users, :jid, unique: true create_table :contacts, force: args[:force] do |t| t.integer :user_id, null: false t.string :jid, limit: 512, null: false t.string :name, limit: 256, null: true t.string :ask, limit: 128, null: true t.string :subscription, limit: 128, null: false end add_index :contacts, [:user_id, :jid], unique: true create_table :groups, force: args[:force] do |t| t.string :name, limit: 256, null: false end add_index :groups, :name, unique: true create_table :contacts_groups, id: false, force: args[:force] do |t| t.integer :contact_id, null: false t.integer :group_id, null: false end add_index :contacts_groups, [:contact_id, :group_id], unique: true create_table :fragments, force: args[:force] do |t| t.integer :user_id, null: false t.string :root, limit: 256, null: false t.string :namespace, limit: 256, null: false t.text :xml, null: false end add_index :fragments, [:user_id, :root, :namespace], unique: true create_table :offline_messages do |t| t.string :from, null: false t.string :to, limit: 512,null: false t.text :body, null: false end add_index :offline_messages,[:from,:to] end end
delete_offline_messages(jid)
click to toggle source
# File lib/vines/storage/sql.rb, line 122 def delete_offline_messages(jid) jid = JID.new(jid).bare.to_s return if jid.empty? Sql::OfflineMessage.destroy_all(:to=>jid) end
fetch_offline_messages(jid)
click to toggle source
# File lib/vines/storage/sql.rb, line 128 def fetch_offline_messages(jid) jid = JID.new(jid).bare.to_s offline_msgs = offline_messages_to_jid(jid) || {} end
find_fragment(jid, node)
click to toggle source
# File lib/vines/storage/sql.rb, line 155 def find_fragment(jid, node) jid = JID.new(jid).bare.to_s return if jid.empty? if fragment = fragment_by_jid(jid, node) Nokogiri::XML(fragment.xml).root rescue nil end end
find_user(jid)
click to toggle source
# File lib/vines/storage/sql.rb, line 61 def find_user(jid) jid = JID.new(jid).bare.to_s return if jid.empty? xuser = user_by_jid(jid) return Vines::User.new(jid: jid).tap do |user| user.name, user.password = xuser.name, xuser.password xuser.contacts.each do |contact| groups = contact.groups.map {|group| group.name } user.roster << Vines::Contact.new( jid: contact.jid, name: contact.name, subscription: contact.subscription, ask: contact.ask, groups: groups) end end if xuser end
find_vcard(jid)
click to toggle source
# File lib/vines/storage/sql.rb, line 137 def find_vcard(jid) jid = JID.new(jid).bare.to_s return if jid.empty? if xuser = user_by_jid(jid) Nokogiri::XML(xuser.vcard).root rescue nil end end
offline_messages_present?(jid)
click to toggle source
# File lib/vines/storage/sql.rb, line 116 def offline_messages_present?(jid) jid = JID.new(jid).bare.to_s return if jid.empty? offline_messages_to_jid(jid) end
save_fragment(jid, node)
click to toggle source
# File lib/vines/storage/sql.rb, line 164 def save_fragment(jid, node) jid = JID.new(jid).bare.to_s fragment = fragment_by_jid(jid, node) || Sql::Fragment.new( user: user_by_jid(jid), root: node.name, namespace: node.namespace.href) fragment.xml = node.to_xml fragment.save end
save_offline_message(msg)
click to toggle source
# File lib/vines/storage/sql.rb, line 133 def save_offline_message(msg) Sql::OfflineMessage.create(msg) end
save_user(user)
click to toggle source
# File lib/vines/storage/sql.rb, line 80 def save_user(user) xuser = user_by_jid(user.jid) || Sql::User.new(jid: user.jid.bare.to_s) xuser.name = user.name xuser.password = user.password # remove deleted contacts from roster xuser.contacts.delete(xuser.contacts.select do |contact| !user.contact?(contact.jid) end) # update contacts xuser.contacts.each do |contact| fresh = user.contact(contact.jid) contact.update_attributes( name: fresh.name, ask: fresh.ask, subscription: fresh.subscription, groups: groups(fresh)) end # add new contacts to roster jids = xuser.contacts.map {|c| c.jid } user.roster.select {|contact| !jids.include?(contact.jid.bare.to_s) } .each do |contact| xuser.contacts.build( user: xuser, jid: contact.jid.bare.to_s, name: contact.name, ask: contact.ask, subscription: contact.subscription, groups: groups(contact)) end xuser.save end
save_vcard(jid, card)
click to toggle source
# File lib/vines/storage/sql.rb, line 146 def save_vcard(jid, card) xuser = user_by_jid(jid) if xuser xuser.vcard = card.to_xml xuser.save end end
Private Instance Methods
establish_connection()
click to toggle source
# File lib/vines/storage/sql.rb, line 229 def establish_connection ActiveRecord::Base.logger = Logger.new('/dev/null') ActiveRecord::Base.establish_connection(@config) # has_and_belongs_to_many requires a connection so configure the # associations here rather than in the class definitions above. Sql::Contact.has_and_belongs_to_many :groups Sql::Group.has_and_belongs_to_many :contacts end
fragment_by_jid(jid, node)
click to toggle source
# File lib/vines/storage/sql.rb, line 243 def fragment_by_jid(jid, node) jid = JID.new(jid).bare.to_s clause = 'user_id=(select id from users where jid=?) and root=? and namespace=?' Sql::Fragment.where(clause, jid, node.name, node.namespace.href).first end
groups(contact)
click to toggle source
# File lib/vines/storage/sql.rb, line 249 def groups(contact) contact.groups.map {|name| Sql::Group.find_or_create_by_name(name.strip) } end
offline_messages_to_jid(jid)
click to toggle source
# File lib/vines/storage/sql.rb, line 253 def offline_messages_to_jid(jid) jid = JID.new(jid).bare.to_s Sql::OfflineMessage.find_all_by_to(jid) end
user_by_jid(jid)
click to toggle source
# File lib/vines/storage/sql.rb, line 238 def user_by_jid(jid) jid = JID.new(jid).bare.to_s Sql::User.find_by_jid(jid, :include => {:contacts => :groups}) end