vines 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +3 -0
 - data/README.md +48 -0
 - data/Rakefile +6 -58
 - data/bin/vines +12 -2
 - data/conf/certs/ca-bundle.crt +568 -39
 - data/conf/config.rb +9 -42
 - data/lib/vines.rb +1 -8
 - data/lib/vines/command/cert.rb +4 -4
 - data/lib/vines/command/init.rb +3 -3
 - data/lib/vines/config.rb +9 -0
 - data/lib/vines/kit.rb +2 -7
 - data/lib/vines/storage/local.rb +50 -17
 - data/lib/vines/store.rb +6 -4
 - data/lib/vines/stream.rb +1 -1
 - data/lib/vines/stream/http/session.rb +0 -0
 - data/lib/vines/stream/http/sessions.rb +0 -0
 - data/lib/vines/stream/parser.rb +3 -2
 - data/lib/vines/token_bucket.rb +19 -10
 - data/lib/vines/version.rb +1 -1
 - data/test/cluster/publisher_test.rb +45 -33
 - data/test/cluster/sessions_test.rb +32 -39
 - data/test/cluster/subscriber_test.rb +93 -78
 - data/test/config/host_test.rb +2 -4
 - data/test/config/pubsub_test.rb +132 -126
 - data/test/config_test.rb +2 -4
 - data/test/contact_test.rb +80 -66
 - data/test/error_test.rb +54 -55
 - data/test/jid_test.rb +1 -2
 - data/test/kit_test.rb +22 -17
 - data/test/router_test.rb +187 -146
 - data/test/stanza/iq/disco_info_test.rb +59 -59
 - data/test/stanza/iq/disco_items_test.rb +36 -34
 - data/test/stanza/iq/private_storage_test.rb +138 -143
 - data/test/stanza/iq/roster_test.rb +198 -175
 - data/test/stanza/iq/session_test.rb +17 -18
 - data/test/stanza/iq/vcard_test.rb +117 -116
 - data/test/stanza/iq/version_test.rb +47 -46
 - data/test/stanza/iq_test.rb +53 -49
 - data/test/stanza/message_test.rb +92 -89
 - data/test/stanza/presence/probe_test.rb +2 -5
 - data/test/stanza/presence/subscribe_test.rb +67 -54
 - data/test/stanza/pubsub/create_test.rb +86 -108
 - data/test/stanza/pubsub/delete_test.rb +141 -114
 - data/test/stanza/pubsub/publish_test.rb +256 -320
 - data/test/stanza/pubsub/subscribe_test.rb +169 -150
 - data/test/stanza/pubsub/unsubscribe_test.rb +111 -142
 - data/test/stanza_test.rb +61 -54
 - data/test/storage/ldap_test.rb +1 -2
 - data/test/storage/local_test.rb +3 -5
 - data/test/storage/null_test.rb +3 -4
 - data/test/storage/storage_tests.rb +1 -3
 - data/test/storage_test.rb +1 -2
 - data/test/store_test.rb +1 -2
 - data/test/stream/client/auth_test.rb +61 -63
 - data/test/stream/client/ready_test.rb +7 -8
 - data/test/stream/client/session_test.rb +19 -18
 - data/test/stream/component/handshake_test.rb +40 -37
 - data/test/stream/component/ready_test.rb +76 -61
 - data/test/stream/component/start_test.rb +7 -8
 - data/test/stream/http/auth_test.rb +3 -4
 - data/test/stream/http/ready_test.rb +52 -60
 - data/test/stream/http/request_test.rb +1 -3
 - data/test/stream/http/sessions_test.rb +2 -3
 - data/test/stream/http/start_test.rb +3 -4
 - data/test/stream/parser_test.rb +3 -4
 - data/test/stream/sasl_test.rb +105 -86
 - data/test/stream/server/auth_test.rb +40 -36
 - data/test/stream/server/outbound/auth_test.rb +3 -4
 - data/test/stream/server/ready_test.rb +51 -51
 - data/test/test_helper.rb +42 -0
 - data/test/token_bucket_test.rb +38 -18
 - data/test/user_test.rb +79 -49
 - data/vines.gemspec +33 -0
 - data/web/chat/javascripts/app.js +1 -1
 - data/web/lib/coffeescripts/layout.coffee +1 -1
 - data/web/lib/javascripts/base.js +10 -10
 - data/web/lib/javascripts/jquery.js +4 -4
 - metadata +31 -128
 - data/README +0 -35
 - data/lib/vines/storage/couchdb.rb +0 -129
 - data/lib/vines/storage/mongodb.rb +0 -132
 - data/lib/vines/storage/redis.rb +0 -127
 - data/lib/vines/storage/sql.rb +0 -220
 - data/test/rake_test_loader.rb +0 -17
 - data/test/storage/couchdb_test.rb +0 -107
 - data/test/storage/mock_mongo.rb +0 -40
 - data/test/storage/mongodb_test.rb +0 -81
 - data/test/storage/redis_test.rb +0 -51
 - data/test/storage/sql_test.rb +0 -62
 
    
        data/README
    DELETED
    
    | 
         @@ -1,35 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            == Welcome to Vines
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            Vines is an XMPP chat server that supports thousands of simultaneous connections
         
     | 
| 
       4 
     | 
    
         
            -
            by using EventMachine for asynchronous IO. User data is stored in a SQL database,
         
     | 
| 
       5 
     | 
    
         
            -
            CouchDB, MongoDB, Redis, the file system, or a custom storage implementation
         
     | 
| 
       6 
     | 
    
         
            -
            that you provide. LDAP authentication can be used so user names and passwords
         
     | 
| 
       7 
     | 
    
         
            -
            aren't stored in the chat database. SSL encryption is mandatory on all client
         
     | 
| 
       8 
     | 
    
         
            -
            and server connections.
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            The Vines XMPP server includes a web chat client. The web application is available
         
     | 
| 
       11 
     | 
    
         
            -
            immediately after starting the chat server at http://localhost:5280/chat/.
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            Additional documentation can be found at www.getvines.org.
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
            == Usage
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
            1. gem install vines
         
     | 
| 
       18 
     | 
    
         
            -
            2. vines init wonderland.lit
         
     | 
| 
       19 
     | 
    
         
            -
            3. cd wonderland.lit && vines start
         
     | 
| 
       20 
     | 
    
         
            -
            4. Login with your favorite chat program (iChat, Adium, Pidgin, etc.) to
         
     | 
| 
       21 
     | 
    
         
            -
               start chatting!
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            == Dependencies
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
            Vines requires Ruby 1.9.2 or better. Instructions for installing the
         
     | 
| 
       26 
     | 
    
         
            -
            needed OS packages, as well as Ruby itself, are available at
         
     | 
| 
       27 
     | 
    
         
            -
            http://www.getvines.org/ruby.
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
            == Contact
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
            * David Graham <david@negativecode.com>
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            == License
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
            Vines is released under the MIT license. Check the LICENSE file for details.
         
     | 
| 
         @@ -1,129 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # encoding: UTF-8
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Vines
         
     | 
| 
       4 
     | 
    
         
            -
              class Storage
         
     | 
| 
       5 
     | 
    
         
            -
                class CouchDB < Storage
         
     | 
| 
       6 
     | 
    
         
            -
                  register :couchdb
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
                  %w[host port database tls username password].each do |name|
         
     | 
| 
       9 
     | 
    
         
            -
                    define_method(name) do |*args|
         
     | 
| 
       10 
     | 
    
         
            -
                      if args.first
         
     | 
| 
       11 
     | 
    
         
            -
                        @config[name.to_sym] = args.first
         
     | 
| 
       12 
     | 
    
         
            -
                      else
         
     | 
| 
       13 
     | 
    
         
            -
                        @config[name.to_sym]
         
     | 
| 
       14 
     | 
    
         
            -
                      end
         
     | 
| 
       15 
     | 
    
         
            -
                    end
         
     | 
| 
       16 
     | 
    
         
            -
                  end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                  def initialize(&block)
         
     | 
| 
       19 
     | 
    
         
            -
                    @config = {}
         
     | 
| 
       20 
     | 
    
         
            -
                    instance_eval(&block)
         
     | 
| 
       21 
     | 
    
         
            -
                    [:host, :port, :database].each {|key| raise "Must provide #{key}" unless @config[key] }
         
     | 
| 
       22 
     | 
    
         
            -
                    @url = url(@config)
         
     | 
| 
       23 
     | 
    
         
            -
                  end
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                  def find_user(jid)
         
     | 
| 
       26 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       27 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       28 
     | 
    
         
            -
                    doc = get("user:#{jid}")
         
     | 
| 
       29 
     | 
    
         
            -
                    return unless doc && doc['type'] == 'User'
         
     | 
| 
       30 
     | 
    
         
            -
                    User.new(jid: jid).tap do |user|
         
     | 
| 
       31 
     | 
    
         
            -
                      user.name, user.password = doc.values_at('name', 'password')
         
     | 
| 
       32 
     | 
    
         
            -
                      (doc['roster'] || {}).each_pair do |jid, props|
         
     | 
| 
       33 
     | 
    
         
            -
                        user.roster << Contact.new(
         
     | 
| 
       34 
     | 
    
         
            -
                          jid: jid,
         
     | 
| 
       35 
     | 
    
         
            -
                          name: props['name'],
         
     | 
| 
       36 
     | 
    
         
            -
                          subscription: props['subscription'],
         
     | 
| 
       37 
     | 
    
         
            -
                          ask: props['ask'],
         
     | 
| 
       38 
     | 
    
         
            -
                          groups: props['groups'] || [])
         
     | 
| 
       39 
     | 
    
         
            -
                      end
         
     | 
| 
       40 
     | 
    
         
            -
                    end
         
     | 
| 
       41 
     | 
    
         
            -
                  end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                  def save_user(user)
         
     | 
| 
       44 
     | 
    
         
            -
                    id = "user:#{user.jid.bare}"
         
     | 
| 
       45 
     | 
    
         
            -
                    doc = get(id) || {'_id' => id}
         
     | 
| 
       46 
     | 
    
         
            -
                    doc['type'] = 'User'
         
     | 
| 
       47 
     | 
    
         
            -
                    doc['name'] = user.name
         
     | 
| 
       48 
     | 
    
         
            -
                    doc['password'] = user.password
         
     | 
| 
       49 
     | 
    
         
            -
                    doc['roster'] = {}
         
     | 
| 
       50 
     | 
    
         
            -
                    user.roster.each do |contact|
         
     | 
| 
       51 
     | 
    
         
            -
                      doc['roster'][contact.jid.bare.to_s] = contact.to_h
         
     | 
| 
       52 
     | 
    
         
            -
                    end
         
     | 
| 
       53 
     | 
    
         
            -
                    save_doc(doc)
         
     | 
| 
       54 
     | 
    
         
            -
                  end
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
                  def find_vcard(jid)
         
     | 
| 
       57 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       58 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       59 
     | 
    
         
            -
                    doc = get("vcard:#{jid}")
         
     | 
| 
       60 
     | 
    
         
            -
                    return unless doc && doc['type'] == 'Vcard'
         
     | 
| 
       61 
     | 
    
         
            -
                    Nokogiri::XML(doc['card']).root rescue nil
         
     | 
| 
       62 
     | 
    
         
            -
                  end
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
                  def save_vcard(jid, card)
         
     | 
| 
       65 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       66 
     | 
    
         
            -
                    id = "vcard:#{jid}"
         
     | 
| 
       67 
     | 
    
         
            -
                    doc = get(id) || {'_id' => id}
         
     | 
| 
       68 
     | 
    
         
            -
                    doc['type'] = 'Vcard'
         
     | 
| 
       69 
     | 
    
         
            -
                    doc['card'] = card.to_xml
         
     | 
| 
       70 
     | 
    
         
            -
                    save_doc(doc)
         
     | 
| 
       71 
     | 
    
         
            -
                  end
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                  def find_fragment(jid, node)
         
     | 
| 
       74 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       75 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       76 
     | 
    
         
            -
                    doc = get(fragment_id(jid, node))
         
     | 
| 
       77 
     | 
    
         
            -
                    return unless doc && doc['type'] == 'Fragment'
         
     | 
| 
       78 
     | 
    
         
            -
                    Nokogiri::XML(doc['xml']).root rescue nil
         
     | 
| 
       79 
     | 
    
         
            -
                  end
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
                  def save_fragment(jid, node)
         
     | 
| 
       82 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       83 
     | 
    
         
            -
                    id = fragment_id(jid, node)
         
     | 
| 
       84 
     | 
    
         
            -
                    doc = get(id) || {'_id' => id}
         
     | 
| 
       85 
     | 
    
         
            -
                    doc['type'] = 'Fragment'
         
     | 
| 
       86 
     | 
    
         
            -
                    doc['xml'] = node.to_xml
         
     | 
| 
       87 
     | 
    
         
            -
                    save_doc(doc)
         
     | 
| 
       88 
     | 
    
         
            -
                  end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
                  private
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
                  def fragment_id(jid, node)
         
     | 
| 
       93 
     | 
    
         
            -
                    id = Digest::SHA1.hexdigest("#{node.name}:#{node.namespace.href}")
         
     | 
| 
       94 
     | 
    
         
            -
                    "fragment:#{jid}:#{id}"
         
     | 
| 
       95 
     | 
    
         
            -
                  end
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                  def url(config)
         
     | 
| 
       98 
     | 
    
         
            -
                    scheme = config[:tls] ? 'https' : 'http'
         
     | 
| 
       99 
     | 
    
         
            -
                    user, password = config.values_at(:username, :password)
         
     | 
| 
       100 
     | 
    
         
            -
                    credentials = empty?(user, password) ? '' : "%s:%s@" % [user, password]
         
     | 
| 
       101 
     | 
    
         
            -
                    "%s://%s%s:%s/%s" % [scheme, credentials, *config.values_at(:host, :port, :database)]
         
     | 
| 
       102 
     | 
    
         
            -
                  end
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
                  def get(jid)
         
     | 
| 
       105 
     | 
    
         
            -
                    http = EM::HttpRequest.new("#{@url}/#{escape(jid)}").get
         
     | 
| 
       106 
     | 
    
         
            -
                    http.errback { yield }
         
     | 
| 
       107 
     | 
    
         
            -
                    http.callback do
         
     | 
| 
       108 
     | 
    
         
            -
                      doc = if http.response_header.status == 200
         
     | 
| 
       109 
     | 
    
         
            -
                        JSON.parse(http.response) rescue nil
         
     | 
| 
       110 
     | 
    
         
            -
                      end
         
     | 
| 
       111 
     | 
    
         
            -
                      yield doc
         
     | 
| 
       112 
     | 
    
         
            -
                    end
         
     | 
| 
       113 
     | 
    
         
            -
                  end
         
     | 
| 
       114 
     | 
    
         
            -
                  fiber :get
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
                  def save_doc(doc)
         
     | 
| 
       117 
     | 
    
         
            -
                    head = {'Content-Type' => 'application/json'}
         
     | 
| 
       118 
     | 
    
         
            -
                    http = EM::HttpRequest.new(@url).post(head: head, body: doc.to_json)
         
     | 
| 
       119 
     | 
    
         
            -
                    http.callback { yield }
         
     | 
| 
       120 
     | 
    
         
            -
                    http.errback  { yield }
         
     | 
| 
       121 
     | 
    
         
            -
                  end
         
     | 
| 
       122 
     | 
    
         
            -
                  fiber :save_doc
         
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
                  def escape(jid)
         
     | 
| 
       125 
     | 
    
         
            -
                    URI.escape(jid, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
         
     | 
| 
       126 
     | 
    
         
            -
                  end
         
     | 
| 
       127 
     | 
    
         
            -
                end
         
     | 
| 
       128 
     | 
    
         
            -
              end
         
     | 
| 
       129 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,132 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # encoding: UTF-8
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Vines
         
     | 
| 
       4 
     | 
    
         
            -
              class Storage
         
     | 
| 
       5 
     | 
    
         
            -
                class MongoDB < Storage
         
     | 
| 
       6 
     | 
    
         
            -
                  register :mongodb
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
                  %w[database tls username password pool].each do |name|
         
     | 
| 
       9 
     | 
    
         
            -
                    define_method(name) do |*args|
         
     | 
| 
       10 
     | 
    
         
            -
                      if args.first
         
     | 
| 
       11 
     | 
    
         
            -
                        @config[name.to_sym] = args.first
         
     | 
| 
       12 
     | 
    
         
            -
                      else
         
     | 
| 
       13 
     | 
    
         
            -
                        @config[name.to_sym]
         
     | 
| 
       14 
     | 
    
         
            -
                      end
         
     | 
| 
       15 
     | 
    
         
            -
                    end
         
     | 
| 
       16 
     | 
    
         
            -
                  end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                  def initialize(&block)
         
     | 
| 
       19 
     | 
    
         
            -
                    @config, @hosts = {}, []
         
     | 
| 
       20 
     | 
    
         
            -
                    instance_eval(&block)
         
     | 
| 
       21 
     | 
    
         
            -
                    raise "Must provide database" unless @config[:database]
         
     | 
| 
       22 
     | 
    
         
            -
                    raise "Must provide at least one host connection" if @hosts.empty?
         
     | 
| 
       23 
     | 
    
         
            -
                  end
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                  def host(name, port)
         
     | 
| 
       26 
     | 
    
         
            -
                    pair = [name, port]
         
     | 
| 
       27 
     | 
    
         
            -
                    raise "duplicate hosts not allowed: #{name}:#{port}" if @hosts.include?(pair)
         
     | 
| 
       28 
     | 
    
         
            -
                    @hosts << pair
         
     | 
| 
       29 
     | 
    
         
            -
                  end
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                  def find_user(jid)
         
     | 
| 
       32 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       33 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       34 
     | 
    
         
            -
                    doc = get(:users, jid)
         
     | 
| 
       35 
     | 
    
         
            -
                    return unless doc
         
     | 
| 
       36 
     | 
    
         
            -
                    User.new(jid: jid).tap do |user|
         
     | 
| 
       37 
     | 
    
         
            -
                      user.name, user.password = doc.values_at('name', 'password')
         
     | 
| 
       38 
     | 
    
         
            -
                      (doc['roster'] || {}).each_pair do |jid, props|
         
     | 
| 
       39 
     | 
    
         
            -
                        user.roster << Contact.new(
         
     | 
| 
       40 
     | 
    
         
            -
                          jid: jid,
         
     | 
| 
       41 
     | 
    
         
            -
                          name: props['name'],
         
     | 
| 
       42 
     | 
    
         
            -
                          subscription: props['subscription'],
         
     | 
| 
       43 
     | 
    
         
            -
                          ask: props['ask'],
         
     | 
| 
       44 
     | 
    
         
            -
                          groups: props['groups'] || [])
         
     | 
| 
       45 
     | 
    
         
            -
                      end
         
     | 
| 
       46 
     | 
    
         
            -
                    end
         
     | 
| 
       47 
     | 
    
         
            -
                  end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                  def save_user(user)
         
     | 
| 
       50 
     | 
    
         
            -
                    id = user.jid.bare.to_s
         
     | 
| 
       51 
     | 
    
         
            -
                    doc = get(:users, id) || {'_id' => id}
         
     | 
| 
       52 
     | 
    
         
            -
                    doc['name'] = user.name
         
     | 
| 
       53 
     | 
    
         
            -
                    doc['password'] = user.password
         
     | 
| 
       54 
     | 
    
         
            -
                    doc['roster'] = {}
         
     | 
| 
       55 
     | 
    
         
            -
                    user.roster.each do |contact|
         
     | 
| 
       56 
     | 
    
         
            -
                      doc['roster'][contact.jid.bare.to_s] = contact.to_h
         
     | 
| 
       57 
     | 
    
         
            -
                    end
         
     | 
| 
       58 
     | 
    
         
            -
                    save_doc(:users, doc)
         
     | 
| 
       59 
     | 
    
         
            -
                  end
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                  def find_vcard(jid)
         
     | 
| 
       62 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       63 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       64 
     | 
    
         
            -
                    doc = get(:vcards, jid)
         
     | 
| 
       65 
     | 
    
         
            -
                    return unless doc
         
     | 
| 
       66 
     | 
    
         
            -
                    Nokogiri::XML(doc['card']).root rescue nil
         
     | 
| 
       67 
     | 
    
         
            -
                  end
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                  def save_vcard(jid, card)
         
     | 
| 
       70 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       71 
     | 
    
         
            -
                    doc = get(:vcards, jid) || {'_id' => jid}
         
     | 
| 
       72 
     | 
    
         
            -
                    doc['card'] = card.to_xml
         
     | 
| 
       73 
     | 
    
         
            -
                    save_doc(:vcards, doc)
         
     | 
| 
       74 
     | 
    
         
            -
                  end
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
                  def find_fragment(jid, node)
         
     | 
| 
       77 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       78 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       79 
     | 
    
         
            -
                    doc = get(:fragments, fragment_id(jid, node))
         
     | 
| 
       80 
     | 
    
         
            -
                    return unless doc
         
     | 
| 
       81 
     | 
    
         
            -
                    Nokogiri::XML(doc['xml']).root rescue nil
         
     | 
| 
       82 
     | 
    
         
            -
                  end
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
                  def save_fragment(jid, node)
         
     | 
| 
       85 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       86 
     | 
    
         
            -
                    id = fragment_id(jid, node)
         
     | 
| 
       87 
     | 
    
         
            -
                    doc = get(:fragments, id) || {'_id' => id}
         
     | 
| 
       88 
     | 
    
         
            -
                    doc['xml'] = node.to_xml
         
     | 
| 
       89 
     | 
    
         
            -
                    save_doc(:fragments, doc)
         
     | 
| 
       90 
     | 
    
         
            -
                  end
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
                  private
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
                  def fragment_id(jid, node)
         
     | 
| 
       95 
     | 
    
         
            -
                    id = Digest::SHA1.hexdigest("#{node.name}:#{node.namespace.href}")
         
     | 
| 
       96 
     | 
    
         
            -
                    "#{jid}:#{id}"
         
     | 
| 
       97 
     | 
    
         
            -
                  end
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
                  def get(collection, id)
         
     | 
| 
       100 
     | 
    
         
            -
                    db.collection(collection).find_one({_id: id})
         
     | 
| 
       101 
     | 
    
         
            -
                  end
         
     | 
| 
       102 
     | 
    
         
            -
                  defer :get
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
                  def save_doc(collection, doc)
         
     | 
| 
       105 
     | 
    
         
            -
                    db.collection(collection).save(doc, safe: true)
         
     | 
| 
       106 
     | 
    
         
            -
                  end
         
     | 
| 
       107 
     | 
    
         
            -
                  defer :save_doc
         
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
                  def db
         
     | 
| 
       110 
     | 
    
         
            -
                    @db ||= connect
         
     | 
| 
       111 
     | 
    
         
            -
                  end
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
                  def connect
         
     | 
| 
       114 
     | 
    
         
            -
                    opts = {
         
     | 
| 
       115 
     | 
    
         
            -
                      pool_timeout: 5,
         
     | 
| 
       116 
     | 
    
         
            -
                      pool_size: @config[:pool] || 5,
         
     | 
| 
       117 
     | 
    
         
            -
                      ssl: @config[:tls]
         
     | 
| 
       118 
     | 
    
         
            -
                    }
         
     | 
| 
       119 
     | 
    
         
            -
                    conn = if @hosts.size == 1
         
     | 
| 
       120 
     | 
    
         
            -
                      Mongo::Connection.new(@hosts.first[0], @hosts.first[1], opts)
         
     | 
| 
       121 
     | 
    
         
            -
                    else
         
     | 
| 
       122 
     | 
    
         
            -
                      Mongo::ReplSetConnection.new(*@hosts, opts)
         
     | 
| 
       123 
     | 
    
         
            -
                    end
         
     | 
| 
       124 
     | 
    
         
            -
                    conn.db(@config[:database]).tap do |db|
         
     | 
| 
       125 
     | 
    
         
            -
                      user = @config[:username] || ''
         
     | 
| 
       126 
     | 
    
         
            -
                      pass = @config[:password] || ''
         
     | 
| 
       127 
     | 
    
         
            -
                      db.authenticate(user, pass) unless user.empty? || pass.empty?
         
     | 
| 
       128 
     | 
    
         
            -
                    end
         
     | 
| 
       129 
     | 
    
         
            -
                  end
         
     | 
| 
       130 
     | 
    
         
            -
                end
         
     | 
| 
       131 
     | 
    
         
            -
              end
         
     | 
| 
       132 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/vines/storage/redis.rb
    DELETED
    
    | 
         @@ -1,127 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # encoding: UTF-8
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Vines
         
     | 
| 
       4 
     | 
    
         
            -
              class Storage
         
     | 
| 
       5 
     | 
    
         
            -
                class Redis < Storage
         
     | 
| 
       6 
     | 
    
         
            -
                  register :redis
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
                  %w[host port database password].each do |name|
         
     | 
| 
       9 
     | 
    
         
            -
                    define_method(name) do |*args|
         
     | 
| 
       10 
     | 
    
         
            -
                      if args.first
         
     | 
| 
       11 
     | 
    
         
            -
                        @config[name.to_sym] = args.first
         
     | 
| 
       12 
     | 
    
         
            -
                      else
         
     | 
| 
       13 
     | 
    
         
            -
                        @config[name.to_sym]
         
     | 
| 
       14 
     | 
    
         
            -
                      end
         
     | 
| 
       15 
     | 
    
         
            -
                    end
         
     | 
| 
       16 
     | 
    
         
            -
                  end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                  def initialize(&block)
         
     | 
| 
       19 
     | 
    
         
            -
                    @config = {}
         
     | 
| 
       20 
     | 
    
         
            -
                    instance_eval(&block)
         
     | 
| 
       21 
     | 
    
         
            -
                  end
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                  def find_user(jid)
         
     | 
| 
       24 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       25 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       26 
     | 
    
         
            -
                    response = query(:get, "user:#{jid}")
         
     | 
| 
       27 
     | 
    
         
            -
                    return unless response
         
     | 
| 
       28 
     | 
    
         
            -
                    doc = JSON.parse(response) rescue nil
         
     | 
| 
       29 
     | 
    
         
            -
                    return unless doc
         
     | 
| 
       30 
     | 
    
         
            -
                    User.new(jid: jid).tap do |user|
         
     | 
| 
       31 
     | 
    
         
            -
                      user.name, user.password = doc.values_at('name', 'password')
         
     | 
| 
       32 
     | 
    
         
            -
                      user.roster = find_roster(jid)
         
     | 
| 
       33 
     | 
    
         
            -
                    end
         
     | 
| 
       34 
     | 
    
         
            -
                  end
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                  def save_user(user)
         
     | 
| 
       37 
     | 
    
         
            -
                    doc = {name: user.name, password: user.password}
         
     | 
| 
       38 
     | 
    
         
            -
                    contacts = user.roster.map {|c| [c.jid.to_s, c.to_h.to_json] }.flatten
         
     | 
| 
       39 
     | 
    
         
            -
                    roster = "roster:#{user.jid.bare}"
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                    redis.multi
         
     | 
| 
       42 
     | 
    
         
            -
                    redis.set("user:#{user.jid.bare}", doc.to_json)
         
     | 
| 
       43 
     | 
    
         
            -
                    redis.del(roster)
         
     | 
| 
       44 
     | 
    
         
            -
                    redis.hmset(roster, *contacts) unless contacts.empty?
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
                    req = redis.exec
         
     | 
| 
       47 
     | 
    
         
            -
                    req.callback { yield }
         
     | 
| 
       48 
     | 
    
         
            -
                    req.errback  { yield }
         
     | 
| 
       49 
     | 
    
         
            -
                  end
         
     | 
| 
       50 
     | 
    
         
            -
                  fiber :save_user
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                  def find_vcard(jid)
         
     | 
| 
       53 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       54 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       55 
     | 
    
         
            -
                    response = query(:get, "vcard:#{jid}")
         
     | 
| 
       56 
     | 
    
         
            -
                    return unless response
         
     | 
| 
       57 
     | 
    
         
            -
                    doc = JSON.parse(response) rescue nil
         
     | 
| 
       58 
     | 
    
         
            -
                    Nokogiri::XML(doc['card']).root rescue nil
         
     | 
| 
       59 
     | 
    
         
            -
                  end
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                  def save_vcard(jid, card)
         
     | 
| 
       62 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       63 
     | 
    
         
            -
                    doc = {card: card.to_xml}
         
     | 
| 
       64 
     | 
    
         
            -
                    query(:set, "vcard:#{jid}", doc.to_json)
         
     | 
| 
       65 
     | 
    
         
            -
                  end
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                  def find_fragment(jid, node)
         
     | 
| 
       68 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       69 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       70 
     | 
    
         
            -
                    response = query(:hget, "fragments:#{jid}", fragment_id(node))
         
     | 
| 
       71 
     | 
    
         
            -
                    return unless response
         
     | 
| 
       72 
     | 
    
         
            -
                    doc = JSON.parse(response) rescue nil
         
     | 
| 
       73 
     | 
    
         
            -
                    Nokogiri::XML(doc['xml']).root rescue nil
         
     | 
| 
       74 
     | 
    
         
            -
                  end
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
                  def save_fragment(jid, node)
         
     | 
| 
       77 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       78 
     | 
    
         
            -
                    doc = {xml: node.to_xml}
         
     | 
| 
       79 
     | 
    
         
            -
                    query(:hset, "fragments:#{jid}", fragment_id(node), doc.to_json)
         
     | 
| 
       80 
     | 
    
         
            -
                  end
         
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                  private
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
                  def fragment_id(node)
         
     | 
| 
       85 
     | 
    
         
            -
                    Digest::SHA1.hexdigest("#{node.name}:#{node.namespace.href}")
         
     | 
| 
       86 
     | 
    
         
            -
                  end
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                  # Retrieve the hash stored at roster:jid and return an array of
         
     | 
| 
       89 
     | 
    
         
            -
                  # +Vines::Contact+ objects.
         
     | 
| 
       90 
     | 
    
         
            -
                  def find_roster(jid)
         
     | 
| 
       91 
     | 
    
         
            -
                    jid = JID.new(jid).bare
         
     | 
| 
       92 
     | 
    
         
            -
                    roster = query(:hgetall, "roster:#{jid}")
         
     | 
| 
       93 
     | 
    
         
            -
                    Hash[*roster].map do |jid, json|
         
     | 
| 
       94 
     | 
    
         
            -
                      contact = JSON.parse(json) rescue nil
         
     | 
| 
       95 
     | 
    
         
            -
                      Contact.new(
         
     | 
| 
       96 
     | 
    
         
            -
                        jid: jid,
         
     | 
| 
       97 
     | 
    
         
            -
                        name: contact['name'],
         
     | 
| 
       98 
     | 
    
         
            -
                        subscription: contact['subscription'],
         
     | 
| 
       99 
     | 
    
         
            -
                        ask: contact['ask'],
         
     | 
| 
       100 
     | 
    
         
            -
                        groups: contact['groups'] || []) if contact
         
     | 
| 
       101 
     | 
    
         
            -
                    end.compact
         
     | 
| 
       102 
     | 
    
         
            -
                  end
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
                  def query(name, *args)
         
     | 
| 
       105 
     | 
    
         
            -
                    req = redis.send(name, *args)
         
     | 
| 
       106 
     | 
    
         
            -
                    req.callback {|response| yield response }
         
     | 
| 
       107 
     | 
    
         
            -
                    req.errback { yield }
         
     | 
| 
       108 
     | 
    
         
            -
                  end
         
     | 
| 
       109 
     | 
    
         
            -
                  fiber :query
         
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
                  # Cache and return a redis connection object. The em-hiredis gem reconnects
         
     | 
| 
       112 
     | 
    
         
            -
                  # in unbind so only create one connection.
         
     | 
| 
       113 
     | 
    
         
            -
                  def redis
         
     | 
| 
       114 
     | 
    
         
            -
                    @redis ||= connect
         
     | 
| 
       115 
     | 
    
         
            -
                  end
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                  # Return a new redis connection using the configuration attributes from the
         
     | 
| 
       118 
     | 
    
         
            -
                  # conf/config.rb file.
         
     | 
| 
       119 
     | 
    
         
            -
                  def connect
         
     | 
| 
       120 
     | 
    
         
            -
                    args = @config.values_at(:host, :port, :password, :database)
         
     | 
| 
       121 
     | 
    
         
            -
                    conn = EM::Hiredis::Client.new(*args)
         
     | 
| 
       122 
     | 
    
         
            -
                    conn.connect
         
     | 
| 
       123 
     | 
    
         
            -
                    conn
         
     | 
| 
       124 
     | 
    
         
            -
                  end
         
     | 
| 
       125 
     | 
    
         
            -
                end
         
     | 
| 
       126 
     | 
    
         
            -
              end
         
     | 
| 
       127 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/vines/storage/sql.rb
    DELETED
    
    | 
         @@ -1,220 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # encoding: UTF-8
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Vines
         
     | 
| 
       4 
     | 
    
         
            -
              class Storage
         
     | 
| 
       5 
     | 
    
         
            -
                class Sql < Storage
         
     | 
| 
       6 
     | 
    
         
            -
                  register :sql
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
                  class Contact < ActiveRecord::Base
         
     | 
| 
       9 
     | 
    
         
            -
                    belongs_to :user
         
     | 
| 
       10 
     | 
    
         
            -
                  end
         
     | 
| 
       11 
     | 
    
         
            -
                  class Fragment < ActiveRecord::Base
         
     | 
| 
       12 
     | 
    
         
            -
                    belongs_to :user
         
     | 
| 
       13 
     | 
    
         
            -
                  end
         
     | 
| 
       14 
     | 
    
         
            -
                  class Group < ActiveRecord::Base; end
         
     | 
| 
       15 
     | 
    
         
            -
                  class User < ActiveRecord::Base
         
     | 
| 
       16 
     | 
    
         
            -
                    has_many :contacts,  :dependent => :destroy
         
     | 
| 
       17 
     | 
    
         
            -
                    has_many :fragments, :dependent => :delete_all
         
     | 
| 
       18 
     | 
    
         
            -
                  end
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                  # Wrap the method with ActiveRecord connection pool logic, so we properly
         
     | 
| 
       21 
     | 
    
         
            -
                  # return connections to the pool when we're finished with them. This also
         
     | 
| 
       22 
     | 
    
         
            -
                  # defers the original method by pushing it onto the EM thread pool because
         
     | 
| 
       23 
     | 
    
         
            -
                  # ActiveRecord uses blocking IO.
         
     | 
| 
       24 
     | 
    
         
            -
                  def self.with_connection(method, args={})
         
     | 
| 
       25 
     | 
    
         
            -
                    deferrable = args.key?(:defer) ? args[:defer] : true
         
     | 
| 
       26 
     | 
    
         
            -
                    old = instance_method(method)
         
     | 
| 
       27 
     | 
    
         
            -
                    define_method method do |*args|
         
     | 
| 
       28 
     | 
    
         
            -
                      ActiveRecord::Base.connection_pool.with_connection do
         
     | 
| 
       29 
     | 
    
         
            -
                        old.bind(self).call(*args)
         
     | 
| 
       30 
     | 
    
         
            -
                      end
         
     | 
| 
       31 
     | 
    
         
            -
                    end
         
     | 
| 
       32 
     | 
    
         
            -
                    defer(method) if deferrable
         
     | 
| 
       33 
     | 
    
         
            -
                  end
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                  %w[adapter host port database username password pool].each do |name|
         
     | 
| 
       36 
     | 
    
         
            -
                    define_method(name) do |*args|
         
     | 
| 
       37 
     | 
    
         
            -
                      if args.first
         
     | 
| 
       38 
     | 
    
         
            -
                        @config[name.to_sym] = args.first
         
     | 
| 
       39 
     | 
    
         
            -
                      else
         
     | 
| 
       40 
     | 
    
         
            -
                        @config[name.to_sym]
         
     | 
| 
       41 
     | 
    
         
            -
                      end
         
     | 
| 
       42 
     | 
    
         
            -
                    end
         
     | 
| 
       43 
     | 
    
         
            -
                  end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                  def initialize(&block)
         
     | 
| 
       46 
     | 
    
         
            -
                    @config = {}
         
     | 
| 
       47 
     | 
    
         
            -
                    instance_eval(&block)
         
     | 
| 
       48 
     | 
    
         
            -
                    required = [:adapter, :database]
         
     | 
| 
       49 
     | 
    
         
            -
                    required << [:host, :port] unless @config[:adapter] == 'sqlite3'
         
     | 
| 
       50 
     | 
    
         
            -
                    required.flatten.each {|key| raise "Must provide #{key}" unless @config[key] }
         
     | 
| 
       51 
     | 
    
         
            -
                    [:username, :password].each {|key| @config.delete(key) if empty?(@config[key]) }
         
     | 
| 
       52 
     | 
    
         
            -
                    establish_connection
         
     | 
| 
       53 
     | 
    
         
            -
                  end
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                  def find_user(jid)
         
     | 
| 
       56 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       57 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       58 
     | 
    
         
            -
                    xuser = user_by_jid(jid)
         
     | 
| 
       59 
     | 
    
         
            -
                    return Vines::User.new(jid: jid).tap do |user|
         
     | 
| 
       60 
     | 
    
         
            -
                      user.name, user.password = xuser.name, xuser.password
         
     | 
| 
       61 
     | 
    
         
            -
                      xuser.contacts.each do |contact|
         
     | 
| 
       62 
     | 
    
         
            -
                        groups = contact.groups.map {|group| group.name }
         
     | 
| 
       63 
     | 
    
         
            -
                        user.roster << Vines::Contact.new(
         
     | 
| 
       64 
     | 
    
         
            -
                          jid: contact.jid,
         
     | 
| 
       65 
     | 
    
         
            -
                          name: contact.name,
         
     | 
| 
       66 
     | 
    
         
            -
                          subscription: contact.subscription,
         
     | 
| 
       67 
     | 
    
         
            -
                          ask: contact.ask,
         
     | 
| 
       68 
     | 
    
         
            -
                          groups: groups)
         
     | 
| 
       69 
     | 
    
         
            -
                      end
         
     | 
| 
       70 
     | 
    
         
            -
                    end if xuser
         
     | 
| 
       71 
     | 
    
         
            -
                  end
         
     | 
| 
       72 
     | 
    
         
            -
                  with_connection :find_user
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
                  def save_user(user)
         
     | 
| 
       75 
     | 
    
         
            -
                    xuser = user_by_jid(user.jid) || Sql::User.new(jid: user.jid.bare.to_s)
         
     | 
| 
       76 
     | 
    
         
            -
                    xuser.name = user.name
         
     | 
| 
       77 
     | 
    
         
            -
                    xuser.password = user.password
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
                    # remove deleted contacts from roster
         
     | 
| 
       80 
     | 
    
         
            -
                    xuser.contacts.delete(xuser.contacts.select do |contact|
         
     | 
| 
       81 
     | 
    
         
            -
                      !user.contact?(contact.jid)
         
     | 
| 
       82 
     | 
    
         
            -
                    end)
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
                    # update contacts
         
     | 
| 
       85 
     | 
    
         
            -
                    xuser.contacts.each do |contact|
         
     | 
| 
       86 
     | 
    
         
            -
                      fresh = user.contact(contact.jid)
         
     | 
| 
       87 
     | 
    
         
            -
                      contact.update_attributes(
         
     | 
| 
       88 
     | 
    
         
            -
                        name: fresh.name,
         
     | 
| 
       89 
     | 
    
         
            -
                        ask: fresh.ask,
         
     | 
| 
       90 
     | 
    
         
            -
                        subscription: fresh.subscription,
         
     | 
| 
       91 
     | 
    
         
            -
                        groups: groups(fresh))
         
     | 
| 
       92 
     | 
    
         
            -
                    end
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
                    # add new contacts to roster
         
     | 
| 
       95 
     | 
    
         
            -
                    jids = xuser.contacts.map {|c| c.jid }
         
     | 
| 
       96 
     | 
    
         
            -
                    user.roster.select {|contact| !jids.include?(contact.jid.bare.to_s) }
         
     | 
| 
       97 
     | 
    
         
            -
                      .each do |contact|
         
     | 
| 
       98 
     | 
    
         
            -
                        xuser.contacts.build(
         
     | 
| 
       99 
     | 
    
         
            -
                          user: xuser,
         
     | 
| 
       100 
     | 
    
         
            -
                          jid: contact.jid.bare.to_s,
         
     | 
| 
       101 
     | 
    
         
            -
                          name: contact.name,
         
     | 
| 
       102 
     | 
    
         
            -
                          ask: contact.ask,
         
     | 
| 
       103 
     | 
    
         
            -
                          subscription: contact.subscription,
         
     | 
| 
       104 
     | 
    
         
            -
                          groups: groups(contact))
         
     | 
| 
       105 
     | 
    
         
            -
                      end
         
     | 
| 
       106 
     | 
    
         
            -
                    xuser.save
         
     | 
| 
       107 
     | 
    
         
            -
                  end
         
     | 
| 
       108 
     | 
    
         
            -
                  with_connection :save_user
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
                  def find_vcard(jid)
         
     | 
| 
       111 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       112 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       113 
     | 
    
         
            -
                    if xuser = user_by_jid(jid)
         
     | 
| 
       114 
     | 
    
         
            -
                      Nokogiri::XML(xuser.vcard).root rescue nil
         
     | 
| 
       115 
     | 
    
         
            -
                    end
         
     | 
| 
       116 
     | 
    
         
            -
                  end
         
     | 
| 
       117 
     | 
    
         
            -
                  with_connection :find_vcard
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
                  def save_vcard(jid, card)
         
     | 
| 
       120 
     | 
    
         
            -
                    xuser = user_by_jid(jid)
         
     | 
| 
       121 
     | 
    
         
            -
                    if xuser
         
     | 
| 
       122 
     | 
    
         
            -
                      xuser.vcard = card.to_xml
         
     | 
| 
       123 
     | 
    
         
            -
                      xuser.save
         
     | 
| 
       124 
     | 
    
         
            -
                    end
         
     | 
| 
       125 
     | 
    
         
            -
                  end
         
     | 
| 
       126 
     | 
    
         
            -
                  with_connection :save_vcard
         
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
                  def find_fragment(jid, node)
         
     | 
| 
       129 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       130 
     | 
    
         
            -
                    return if jid.empty?
         
     | 
| 
       131 
     | 
    
         
            -
                    if fragment = fragment_by_jid(jid, node)
         
     | 
| 
       132 
     | 
    
         
            -
                      Nokogiri::XML(fragment.xml).root rescue nil
         
     | 
| 
       133 
     | 
    
         
            -
                    end
         
     | 
| 
       134 
     | 
    
         
            -
                  end
         
     | 
| 
       135 
     | 
    
         
            -
                  with_connection :find_fragment
         
     | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
                  def save_fragment(jid, node)
         
     | 
| 
       138 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       139 
     | 
    
         
            -
                    fragment = fragment_by_jid(jid, node) ||
         
     | 
| 
       140 
     | 
    
         
            -
                      Sql::Fragment.new(
         
     | 
| 
       141 
     | 
    
         
            -
                        user: user_by_jid(jid),
         
     | 
| 
       142 
     | 
    
         
            -
                        root: node.name,
         
     | 
| 
       143 
     | 
    
         
            -
                        namespace: node.namespace.href)
         
     | 
| 
       144 
     | 
    
         
            -
                    fragment.xml = node.to_xml
         
     | 
| 
       145 
     | 
    
         
            -
                    fragment.save
         
     | 
| 
       146 
     | 
    
         
            -
                  end
         
     | 
| 
       147 
     | 
    
         
            -
                  with_connection :save_fragment
         
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
                  # Create the tables and indexes used by this storage engine.
         
     | 
| 
       150 
     | 
    
         
            -
                  def create_schema(args={})
         
     | 
| 
       151 
     | 
    
         
            -
                    args[:force] ||= false
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                    ActiveRecord::Schema.define do
         
     | 
| 
       154 
     | 
    
         
            -
                      create_table :users, force: args[:force] do |t|
         
     | 
| 
       155 
     | 
    
         
            -
                        t.string :jid,      limit: 512, null: false
         
     | 
| 
       156 
     | 
    
         
            -
                        t.string :name,     limit: 256, null: true
         
     | 
| 
       157 
     | 
    
         
            -
                        t.string :password, limit: 256, null: true
         
     | 
| 
       158 
     | 
    
         
            -
                        t.text   :vcard,    null: true
         
     | 
| 
       159 
     | 
    
         
            -
                      end
         
     | 
| 
       160 
     | 
    
         
            -
                      add_index :users, :jid, unique: true
         
     | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
       162 
     | 
    
         
            -
                      create_table :contacts, force: args[:force] do |t|
         
     | 
| 
       163 
     | 
    
         
            -
                        t.integer :user_id,      null: false
         
     | 
| 
       164 
     | 
    
         
            -
                        t.string  :jid,          limit: 512, null: false
         
     | 
| 
       165 
     | 
    
         
            -
                        t.string  :name,         limit: 256, null: true
         
     | 
| 
       166 
     | 
    
         
            -
                        t.string  :ask,          limit: 128, null: true
         
     | 
| 
       167 
     | 
    
         
            -
                        t.string  :subscription, limit: 128, null: false
         
     | 
| 
       168 
     | 
    
         
            -
                      end
         
     | 
| 
       169 
     | 
    
         
            -
                      add_index :contacts, [:user_id, :jid], unique: true
         
     | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
                      create_table :groups, force: args[:force] do |t|
         
     | 
| 
       172 
     | 
    
         
            -
                        t.string :name, limit: 256, null: false
         
     | 
| 
       173 
     | 
    
         
            -
                      end
         
     | 
| 
       174 
     | 
    
         
            -
                      add_index :groups, :name, unique: true
         
     | 
| 
       175 
     | 
    
         
            -
             
     | 
| 
       176 
     | 
    
         
            -
                      create_table :contacts_groups, id: false, force: args[:force] do |t|
         
     | 
| 
       177 
     | 
    
         
            -
                        t.integer :contact_id, null: false
         
     | 
| 
       178 
     | 
    
         
            -
                        t.integer :group_id,   null: false
         
     | 
| 
       179 
     | 
    
         
            -
                      end
         
     | 
| 
       180 
     | 
    
         
            -
                      add_index :contacts_groups, [:contact_id, :group_id], unique: true
         
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
       182 
     | 
    
         
            -
                      create_table :fragments, force: args[:force] do |t|
         
     | 
| 
       183 
     | 
    
         
            -
                        t.integer :user_id,   null: false
         
     | 
| 
       184 
     | 
    
         
            -
                        t.string  :root,      limit: 256, null: false
         
     | 
| 
       185 
     | 
    
         
            -
                        t.string  :namespace, limit: 256, null: false
         
     | 
| 
       186 
     | 
    
         
            -
                        t.text    :xml,       null: false
         
     | 
| 
       187 
     | 
    
         
            -
                      end
         
     | 
| 
       188 
     | 
    
         
            -
                      add_index :fragments, [:user_id, :root, :namespace], unique: true
         
     | 
| 
       189 
     | 
    
         
            -
                    end
         
     | 
| 
       190 
     | 
    
         
            -
                  end
         
     | 
| 
       191 
     | 
    
         
            -
                  with_connection :create_schema, defer: false
         
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
                  private
         
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
                  def establish_connection
         
     | 
| 
       196 
     | 
    
         
            -
                    ActiveRecord::Base.logger = Logger.new('/dev/null')
         
     | 
| 
       197 
     | 
    
         
            -
                    ActiveRecord::Base.establish_connection(@config)
         
     | 
| 
       198 
     | 
    
         
            -
                    # has_and_belongs_to_many requires a connection so configure the
         
     | 
| 
       199 
     | 
    
         
            -
                    # associations here rather than in the class definitions above.
         
     | 
| 
       200 
     | 
    
         
            -
                    Sql::Contact.has_and_belongs_to_many :groups
         
     | 
| 
       201 
     | 
    
         
            -
                    Sql::Group.has_and_belongs_to_many :contacts
         
     | 
| 
       202 
     | 
    
         
            -
                  end
         
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
       204 
     | 
    
         
            -
                  def user_by_jid(jid)
         
     | 
| 
       205 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       206 
     | 
    
         
            -
                    Sql::User.find_by_jid(jid, :include => {:contacts => :groups})
         
     | 
| 
       207 
     | 
    
         
            -
                  end
         
     | 
| 
       208 
     | 
    
         
            -
             
     | 
| 
       209 
     | 
    
         
            -
                  def fragment_by_jid(jid, node)
         
     | 
| 
       210 
     | 
    
         
            -
                    jid = JID.new(jid).bare.to_s
         
     | 
| 
       211 
     | 
    
         
            -
                    clause = 'user_id=(select id from users where jid=?) and root=? and namespace=?'
         
     | 
| 
       212 
     | 
    
         
            -
                    Sql::Fragment.where(clause, jid, node.name, node.namespace.href).first
         
     | 
| 
       213 
     | 
    
         
            -
                  end
         
     | 
| 
       214 
     | 
    
         
            -
             
     | 
| 
       215 
     | 
    
         
            -
                  def groups(contact)
         
     | 
| 
       216 
     | 
    
         
            -
                    contact.groups.map {|name| Sql::Group.find_or_create_by_name(name.strip) }
         
     | 
| 
       217 
     | 
    
         
            -
                  end
         
     | 
| 
       218 
     | 
    
         
            -
                end
         
     | 
| 
       219 
     | 
    
         
            -
              end
         
     | 
| 
       220 
     | 
    
         
            -
            end
         
     |