vines 0.1.0 → 0.1.1

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.
Files changed (66) hide show
  1. data/README +1 -1
  2. data/Rakefile +12 -2
  3. data/conf/config.rb +1 -0
  4. data/lib/vines/config.rb +8 -0
  5. data/lib/vines/contact.rb +2 -4
  6. data/lib/vines/error.rb +1 -1
  7. data/lib/vines/router.rb +26 -18
  8. data/lib/vines/stanza/presence.rb +3 -1
  9. data/lib/vines/stanza.rb +8 -1
  10. data/lib/vines/stream/client/bind.rb +9 -1
  11. data/lib/vines/stream/client/session.rb +146 -0
  12. data/lib/vines/stream/client.rb +19 -78
  13. data/lib/vines/stream/component.rb +6 -2
  14. data/lib/vines/stream/http/auth.rb +22 -0
  15. data/lib/vines/stream/http/bind.rb +32 -0
  16. data/lib/vines/stream/http/bind_restart.rb +36 -0
  17. data/lib/vines/stream/http/ready.rb +25 -0
  18. data/lib/vines/stream/http/request.rb +33 -0
  19. data/lib/vines/stream/http/session.rb +116 -0
  20. data/lib/vines/stream/http/sessions.rb +65 -0
  21. data/lib/vines/stream/http/start.rb +23 -0
  22. data/lib/vines/stream/http.rb +119 -77
  23. data/lib/vines/stream/server.rb +8 -3
  24. data/lib/vines/stream/state.rb +6 -1
  25. data/lib/vines/stream.rb +31 -19
  26. data/lib/vines/user.rb +2 -4
  27. data/lib/vines/version.rb +1 -1
  28. data/lib/vines.rb +10 -4
  29. data/test/config_test.rb +34 -33
  30. data/test/contact_test.rb +42 -0
  31. data/test/error_test.rb +2 -2
  32. data/test/jid_test.rb +7 -7
  33. data/test/kit_test.rb +10 -10
  34. data/test/rake_test_loader.rb +9 -0
  35. data/test/router_test.rb +4 -3
  36. data/test/stanza/iq/roster_test.rb +8 -10
  37. data/test/stanza/iq/session_test.rb +2 -3
  38. data/test/stanza/iq/vcard_test.rb +4 -5
  39. data/test/stanza/message_test.rb +17 -11
  40. data/test/stanza/presence/subscribe_test.rb +3 -4
  41. data/test/storage/couchdb_test.rb +9 -10
  42. data/test/storage/ldap_test.rb +30 -37
  43. data/test/storage/local_test.rb +6 -6
  44. data/test/storage/redis_test.rb +6 -6
  45. data/test/storage/sql_test.rb +5 -5
  46. data/test/storage/storage_tests.rb +11 -11
  47. data/test/storage_test.rb +4 -5
  48. data/test/stream/client/auth_test.rb +15 -16
  49. data/test/stream/client/ready_test.rb +4 -5
  50. data/test/stream/client/session_test.rb +21 -0
  51. data/test/stream/component/handshake_test.rb +6 -7
  52. data/test/stream/component/ready_test.rb +9 -10
  53. data/test/stream/component/start_test.rb +6 -7
  54. data/test/stream/http/auth_test.rb +68 -0
  55. data/test/stream/http/ready_test.rb +56 -0
  56. data/test/stream/http/sessions_test.rb +50 -0
  57. data/test/stream/http/start_test.rb +51 -0
  58. data/test/stream/parser_test.rb +5 -5
  59. data/test/stream/server/outbound/auth_test.rb +12 -13
  60. data/test/stream/server/ready_test.rb +10 -11
  61. data/test/token_bucket_test.rb +7 -7
  62. data/test/user_test.rb +8 -6
  63. metadata +45 -14
  64. data/lib/vines/stream/http/http_request.rb +0 -22
  65. data/lib/vines/stream/http/http_state.rb +0 -139
  66. data/lib/vines/stream/http/http_states.rb +0 -53
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ module Vines
4
+ class Stream
5
+ class Http
6
+ class Request
7
+ attr_reader :rid, :stream
8
+
9
+ def initialize(stream, rid, content_type)
10
+ @stream, @rid, @content = stream, rid, content_type
11
+ @received = Time.now
12
+ end
13
+
14
+ # Return the number of seconds since this request was received.
15
+ def age
16
+ Time.now - @received
17
+ end
18
+
19
+ # Send an HTTP 200 OK response wrapping the XMPP node content back
20
+ # to the client.
21
+ def reply(node)
22
+ body = node.to_s
23
+ header = [
24
+ "HTTP/1.1 200 OK",
25
+ "Content-Type: #{@content}",
26
+ "Content-Length: #{body.bytesize}"
27
+ ].join("\r\n")
28
+ @stream.stream_write([header, body].join("\r\n\r\n"))
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: UTF-8
2
+
3
+ module Vines
4
+ class Stream
5
+ class Http
6
+ class Session < Client::Session
7
+ include Nokogiri::XML
8
+
9
+ attr_accessor :content_type, :hold, :inactivity, :wait
10
+
11
+ CONTENT_TYPE = 'text/xml; charset=utf-8'.freeze
12
+
13
+ def initialize(stream)
14
+ super
15
+ @state = Http::Start.new(stream)
16
+ @inactivity, @wait, @hold = 20, 60, 1
17
+ @replied = Time.now
18
+ @requests, @responses = [], []
19
+ @content_type = CONTENT_TYPE
20
+ end
21
+
22
+ def close
23
+ Sessions.delete(@id)
24
+ router.delete(self)
25
+ @requests.each {|req| req.stream.close_connection }
26
+ @requests.clear
27
+ @responses.clear
28
+ @state = Client::Closed.new(nil)
29
+ @unbound = true
30
+ @available = false
31
+ broadcast_unavailable
32
+ end
33
+
34
+ def ready?
35
+ @state.class == Http::Ready
36
+ end
37
+
38
+ def requests
39
+ @requests.clone
40
+ end
41
+
42
+ def expired?
43
+ respond_to_expired_requests
44
+ @requests.empty? && (Time.now - @replied > @inactivity)
45
+ end
46
+
47
+ # Resume this session from its most recent state with a new client
48
+ # stream and incoming node.
49
+ def resume(stream, node)
50
+ stream.session.requests.each do |req|
51
+ request(req)
52
+ end
53
+ stream.session = self
54
+ @state.stream = stream
55
+ @state.node(node)
56
+ end
57
+
58
+ def request(request)
59
+ if @responses.any?
60
+ request.reply(wrap_body(@responses.join))
61
+ @replied = Time.now
62
+ @responses.clear
63
+ else
64
+ while @requests.size >= @hold
65
+ @requests.shift.reply(wrap_body(''))
66
+ @replied = Time.now
67
+ end
68
+ @requests << request
69
+ end
70
+ end
71
+
72
+ # Send an HTTP 200 OK response wrapping the XMPP node content back
73
+ # to the client.
74
+ def reply(node)
75
+ @requests.shift.reply(node)
76
+ @replied = Time.now
77
+ end
78
+
79
+ # Write the XMPP node to the client stream after wrapping it in a BOSH
80
+ # body tag. If there's a waiting request, the node is written
81
+ # immediately. If not, it's queued until the next request arrives.
82
+ def write(node)
83
+ if request = @requests.shift
84
+ request.reply(wrap_body(node))
85
+ @replied = Time.now
86
+ else
87
+ @responses << node.to_s
88
+ end
89
+ end
90
+
91
+ def unbind!(stream)
92
+ @requests.reject! {|req| req.stream == stream }
93
+ end
94
+
95
+ private
96
+
97
+ def respond_to_expired_requests
98
+ expired = @requests.select {|req| req.age > @wait }
99
+ expired.each do |request|
100
+ request.reply(wrap_body(''))
101
+ @requests.delete(request)
102
+ @replied = Time.now
103
+ end
104
+ end
105
+
106
+ def wrap_body(data)
107
+ doc = Document.new
108
+ doc.create_element('body') do |node|
109
+ node.add_namespace(nil, NAMESPACES[:http_bind])
110
+ node.inner_html = data.to_s
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: UTF-8
2
+
3
+ module Vines
4
+ class Stream
5
+ class Http
6
+ # Sessions is a cache of Http::Session objects for transient HTTP
7
+ # connections. The cache is monitored for expired client connections.
8
+ class Sessions
9
+ include Vines::Log
10
+
11
+ @@instance = nil
12
+ def self.instance
13
+ @@instance ||= self.new
14
+ end
15
+
16
+ def self.[](sid)
17
+ instance[sid]
18
+ end
19
+
20
+ def self.[]=(sid, session)
21
+ instance[sid] = session
22
+ end
23
+
24
+ def self.delete(sid)
25
+ instance.delete(sid)
26
+ end
27
+
28
+ def initialize
29
+ @sessions = {}
30
+ start_timer
31
+ end
32
+
33
+ def []=(sid, session)
34
+ @sessions[sid] = session
35
+ end
36
+
37
+ def [](sid)
38
+ @sessions[sid]
39
+ end
40
+
41
+ def delete(sid)
42
+ @sessions.delete(sid)
43
+ end
44
+
45
+ private
46
+
47
+ # Check for expired clients to cleanup every second.
48
+ def start_timer
49
+ @timer ||= EventMachine::PeriodicTimer.new(1) { cleanup }
50
+ end
51
+
52
+ # Remove cached information for all expired connections. An expired
53
+ # HTTP client is one that has no queued requests and has had no activity
54
+ # for over 20 seconds.
55
+ def cleanup
56
+ @sessions.each_value do |session|
57
+ session.close if session.expired?
58
+ end
59
+ rescue Exception => e
60
+ log.error("Expired session cleanup failed: #{e}")
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ module Vines
4
+ class Stream
5
+ class Http
6
+ class Start < State
7
+ def initialize(stream, success=Auth)
8
+ super
9
+ end
10
+
11
+ def node(node)
12
+ raise StreamErrors::NotAuthorized unless body?(node)
13
+ if session = Sessions[node['sid']]
14
+ session.resume(stream, node)
15
+ else
16
+ stream.start(node)
17
+ advance
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,108 +3,150 @@
3
3
  module Vines
4
4
  class Stream
5
5
  class Http < Client
6
- include Thin
7
- include Vines::Log
8
-
9
- attr_accessor :last_broadcast_presence, :last_activity
6
+ attr_accessor :session
10
7
 
11
8
  def initialize(config)
12
- @config = config
13
- @domain = nil
14
- @requested_roster = false
15
- @available = false
16
- @unbound = false
17
- @last_broadcast_presence = nil
18
- @request = Thin::Request.new
19
- @@http_states ||= HttpStates.new
20
- @state = Auth.new(self)
9
+ super
10
+ @session = Http::Session.new(self)
11
+ end
12
+
13
+ def post_init
14
+ super
15
+ router.delete(self)
16
+ @parser = ::Http::Parser.new.tap do |p|
17
+ body = ''
18
+ p.on_body = proc {|data| body << data }
19
+ p.on_message_complete = proc {
20
+ process_request(body)
21
+ body = ''
22
+ }
23
+ end
24
+ end
25
+
26
+ # Return true if this session ID matches the stream's session ID. Clients
27
+ # are only allowed one session per stream so they must send the same
28
+ # session ID on each request.
29
+ def valid_session?(sid)
30
+ @session.id == sid
21
31
  end
22
32
 
23
- def user
24
- @http_state.user
33
+ def max_stanza_size
34
+ @config[:http].max_stanza_size
25
35
  end
26
36
 
27
- def user=(user)
28
- @http_state.user = user
37
+ def max_resources_per_account
38
+ @config[:http].max_resources_per_account
29
39
  end
30
40
 
31
- def receive_data(data)
32
- #TODO: make sure we add max stanza size enforcement
33
- if @request.parse(data)
34
- process_http_request(@request)
35
- @request = Thin::Request.new
41
+ def process_request(body)
42
+ # proxy server ping
43
+ if body.empty?
44
+ req = Request.new(self, nil, 'text/plain')
45
+ req.reply('online')
46
+ close_connection_after_writing
47
+ else
48
+ body = Nokogiri::XML(body).root
49
+ req = Request.new(self, body['rid'], @session.content_type)
50
+ @session.request(req)
51
+ @nodes.push(body)
36
52
  end
37
- rescue InvalidRequest => e
38
- error(StreamErrors::NotWellFormed.new)
39
53
  end
40
54
 
55
+ # Alias the Stream#write method before overriding it so we can call
56
+ # it later from a Session instance.
57
+ alias :stream_write :write
58
+
59
+ # Override Stream#write to queue stanzas rather than immediately writing
60
+ # to the stream. Stanza responses must be paired with a queued request.
41
61
  def write(data)
42
- @http_state.write(data)
62
+ @session.write(data)
63
+ end
64
+
65
+ # Return an array of Node objects inside the body element.
66
+ # TODO This parses the XML again just to strip namespaces. Figure out
67
+ # Nokogiri namespace handling instead.
68
+ def parse_body(body)
69
+ body.namespace = nil
70
+ body.elements.map do |node|
71
+ Nokogiri::XML(node.to_s.sub(' xmlns="jabber:client"', '')).root
72
+ end
43
73
  end
44
74
 
45
- def setup_new_client(rid, domain)
46
- sid = Kit.uuid
47
- log.info("Setting up a new client SID: #{sid} for RID: #{rid}.")
48
- @http_state = HttpState.new(self, sid, rid, domain)
49
- @@http_states[sid] = @http_state
75
+ def start(node)
76
+ domain, type, hold, wait, rid = %w[to content hold wait rid].map {|a| (node[a] || '').strip }
77
+ version = node.attribute_with_ns('version', NAMESPACES[:bosh]).value rescue nil
78
+
79
+ @session.inactivity = 20
80
+ @session.domain = domain
81
+ @session.content_type = type unless type.empty?
82
+ @session.hold = hold.to_i unless hold.empty?
83
+ @session.wait = wait.to_i unless wait.empty?
84
+
85
+ raise StreamErrors::UndefinedCondition.new('rid required') if rid.empty?
86
+ raise StreamErrors::UnsupportedVersion unless version == '1.0'
87
+ raise StreamErrors::HostUnknown unless @config.vhost?(domain)
88
+ raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns'] == NAMESPACES[:http_bind]
89
+
90
+ Sessions[@session.id] = @session
91
+ router << @session
92
+ send_stream_header
50
93
  end
51
94
 
52
- def unbind
53
- #router.delete(@http_state)
54
- log.info("HTTP Stream disconnected:\tfrom=#{@remote_addr}\tto=#{@local_addr}")
55
- log.info("Streams connected: #{router.size}")
95
+ def terminate
96
+ doc = Nokogiri::XML::Document.new
97
+ node = doc.create_element('body',
98
+ 'type' => 'terminate',
99
+ 'xmlns' => NAMESPACES[:http_bind])
100
+ @session.reply(node)
101
+ close_stream
56
102
  end
57
103
 
58
- def process_http_request(request)
59
- if request.body.string.empty?
60
- #Respond to proxy servers' status pings
61
- log.info("A status request has been received.")
62
- send_data("Online")
63
- close_connection_after_writing
64
- return
65
- end
66
- body = Nokogiri::XML(request.body.string).root
67
- body.namespace = nil
68
- #TODO: Confirm this is a valid body stanza.
69
- # If it isn't a body, return proxy ping result
70
-
71
- if body['sid']
72
- @http_state = @@http_states[body['sid']]
73
- unless @http_state
74
- log.info("Client was not found #{body['sid']}")
75
- send_bosh_error
76
- return
77
- end
78
- @domain = @http_state.domain
79
- @user = @http_state.user
80
- @http_state.request(body['rid'])
81
- if body['restart']
82
- @http_state.handle_restart
83
- router << @http_state
84
- @state = Bind.new(self)
85
- end
104
+ private
86
105
 
87
- body.elements.each do |node|
88
- @nodes.push(Nokogiri::XML(node.to_s.sub(' xmlns="jabber:client"', '')).root)
106
+ def send_stream_header
107
+ doc = Nokogiri::XML::Document.new
108
+ node = doc.create_element('body',
109
+ 'charsets' => 'UTF-8',
110
+ 'from' => @session.domain,
111
+ 'hold' => @session.hold,
112
+ 'inactivity' => @session.inactivity,
113
+ 'polling' => '5',
114
+ 'requests' => '2',
115
+ 'sid' => @session.id,
116
+ 'ver' => '1.6',
117
+ 'wait' => @session.wait,
118
+ 'xmpp:version' => '1.0',
119
+ 'xmlns' => NAMESPACES[:http_bind],
120
+ 'xmlns:xmpp' => NAMESPACES[:bosh],
121
+ 'xmlns:stream' => NAMESPACES[:stream])
122
+
123
+ node << doc.create_element('stream:features') do |el|
124
+ el << doc.create_element('mechanisms') do |mechanisms|
125
+ mechanisms.default_namespace = NAMESPACES[:sasl]
126
+ mechanisms << doc.create_element('mechanism', 'PLAIN')
89
127
  end
90
- else
91
- self.setup_new_client(body['rid'], body['to'])
92
128
  end
129
+ @session.reply(node)
93
130
  end
94
131
 
95
- def send_bosh_error
96
- body = "<body type='terminate' condition='remote-connection-failed' xmlns='http://jabber.org/protocol/httpbind'/>"
97
- header = [
98
- "HTTP/1.1 404 OK",
99
- "Content-Type: text/xml; charset=utf-8",
100
- "Content-Length: #{body.bytesize}"
101
- ].join("\r\n")
102
-
103
- send_data([header, body].join("\r\n\r\n"))
132
+ # Override +Stream#send_stream_error+ to wrap the error XML in a BOSH
133
+ # terminate body tag.
134
+ def send_stream_error(e)
135
+ doc = Nokogiri::XML::Document.new
136
+ node = doc.create_element('body',
137
+ 'condition' => 'remote-stream-error',
138
+ 'type' => 'terminate',
139
+ 'xmlns' => NAMESPACES[:http_bind],
140
+ 'xmlns:stream' => NAMESPACES[:stream])
141
+ node.inner_html = e.to_xml
142
+ @session.reply(node)
104
143
  end
105
144
 
106
- def domain
107
- @http_state.domain
145
+ # Override +Stream#close_stream+ to simply close the connection without
146
+ # writing a closing stream tag.
147
+ def close_stream
148
+ close_connection_after_writing
149
+ @session.close
108
150
  end
109
151
  end
110
152
  end
@@ -57,7 +57,8 @@ module Vines
57
57
  @srv = options[:srv]
58
58
  @callback = options[:callback]
59
59
  @outbound = @remote_domain && @domain
60
- @state = @outbound ? Outbound::Start.new(self) : Start.new(self)
60
+ start = @outbound ? Outbound::Start.new(self) : Start.new(self)
61
+ advance(start)
61
62
  end
62
63
 
63
64
  def post_init
@@ -73,9 +74,13 @@ module Vines
73
74
  close_connection unless cert_domain_matches?(@remote_domain)
74
75
  end
75
76
 
77
+ def stream_type
78
+ :server
79
+ end
80
+
76
81
  def unbind
77
82
  super
78
- if @outbound && @state.class != Ready
83
+ if @outbound && !ready?
79
84
  Server.connect(@config, @remote_domain, @domain, @srv, @callback)
80
85
  end
81
86
  end
@@ -92,7 +97,7 @@ module Vines
92
97
  end
93
98
 
94
99
  def ready?
95
- @state.class == Server::Ready
100
+ state.class == Server::Ready
96
101
  end
97
102
 
98
103
  def start(node)
@@ -9,8 +9,9 @@ module Vines
9
9
  include Nokogiri::XML
10
10
  include Vines::Log
11
11
 
12
- attr_reader :stream
12
+ attr_accessor :stream
13
13
 
14
+ BODY = 'body'.freeze
14
15
  STREAM = 'stream'.freeze
15
16
 
16
17
  def initialize(stream, success=nil)
@@ -43,6 +44,10 @@ module Vines
43
44
  node.name == STREAM && namespace(node) == NAMESPACES[:stream]
44
45
  end
45
46
 
47
+ def body?(node)
48
+ node.name == BODY && namespace(node) == NAMESPACES[:http_bind]
49
+ end
50
+
46
51
  def namespace(node)
47
52
  node.namespace ? node.namespace.href : nil
48
53
  end
data/lib/vines/stream.rb CHANGED
@@ -10,13 +10,12 @@ module Vines
10
10
  ERROR = 'error'.freeze
11
11
  PAD = 20
12
12
 
13
+ attr_reader :domain
13
14
  attr_accessor :user
14
15
 
15
16
  def post_init
16
17
  router << self
17
- @remote_addr, @local_addr = [get_peername, get_sockname].map do |addr|
18
- addr ? Socket.unpack_sockaddr_in(addr)[0, 2].reverse.join(':') : 'unknown'
19
- end
18
+ @remote_addr, @local_addr = addresses
20
19
  @user, @closed, @stanza_size = nil, false, 0
21
20
  @bucket = TokenBucket.new(100, 10)
22
21
  @store = Store.new
@@ -49,20 +48,10 @@ module Vines
49
48
  end
50
49
  end
51
50
 
52
- # Send the stanza to all recipients, stamping it with from and
53
- # to addresses first.
54
- def broadcast(stanza, recipients)
55
- stanza['from'] = @user.jid.to_s
56
- recipients.each do |recipient|
57
- stanza['to'] = recipient.user.jid.to_s
58
- recipient.write(stanza)
59
- end
60
- end
61
-
62
51
  # Returns the storage system for the domain. If no domain is given,
63
52
  # the stream's storage mechanism is returned.
64
- def storage(domain=@domain)
65
- @config.vhosts[domain]
53
+ def storage(domain=nil)
54
+ @config.vhosts[domain || self.domain]
66
55
  end
67
56
 
68
57
  # Reload the user's information into their active connections. Call this
@@ -114,6 +103,8 @@ module Vines
114
103
  log.info { "Streams connected: #{router.size}" }
115
104
  end
116
105
 
106
+ # Advance the stream's state machine to the new state. XML nodes received
107
+ # by the stream will be passed to this state's +node+ method.
117
108
  def advance(state)
118
109
  @state = state
119
110
  end
@@ -126,11 +117,11 @@ module Vines
126
117
  when SaslError, StanzaError
127
118
  write(e.to_xml)
128
119
  when StreamError
129
- write(e.to_xml)
120
+ send_stream_error(e)
130
121
  close_stream
131
122
  else
132
123
  log.error(e)
133
- write(StreamErrors::InternalServerError.new.to_xml)
124
+ send_stream_error(StreamErrors::InternalServerError.new)
134
125
  close_stream
135
126
  end
136
127
  end
@@ -141,6 +132,21 @@ module Vines
141
132
 
142
133
  private
143
134
 
135
+ # Return the remote and local socket addresses used by this connection.
136
+ def addresses
137
+ [get_peername, get_sockname].map do |addr|
138
+ addr ? Socket.unpack_sockaddr_in(addr)[0, 2].reverse.join(':') : 'unknown'
139
+ end
140
+ end
141
+
142
+ # Write the StreamError's xml to the stream. Subclasses can override
143
+ # this method with custom error writing behavior.
144
+ def send_stream_error(e)
145
+ write(e.to_xml)
146
+ end
147
+
148
+ # Write a closing stream tag to the stream then close the stream. Subclasses
149
+ # can override this method for custom close behavior.
144
150
  def close_stream
145
151
  write('</stream:stream>')
146
152
  close_connection_after_writing
@@ -170,7 +176,7 @@ module Vines
170
176
  if error?(node)
171
177
  close_stream
172
178
  else
173
- @state.node(node)
179
+ state.node(node)
174
180
  end
175
181
  rescue Exception => e
176
182
  error(e)
@@ -191,8 +197,14 @@ module Vines
191
197
  ["#{label} stanza:".ljust(PAD), from, to, node])
192
198
  end
193
199
 
200
+ # Returns the current state of the stream's state machine. Provided as a
201
+ # method so subclasses can override the behavior.
202
+ def state
203
+ @state
204
+ end
205
+
194
206
  def tls_files
195
- %w[crt key].map {|ext| File.join(VINES_ROOT, 'conf', 'certs', "#{@domain}.#{ext}") }
207
+ %w[crt key].map {|ext| File.join(VINES_ROOT, 'conf', 'certs', "#{domain}.#{ext}") }
196
208
  end
197
209
  end
198
210
  end
data/lib/vines/user.rb CHANGED
@@ -16,12 +16,10 @@ module Vines
16
16
  end
17
17
 
18
18
  def <=>(user)
19
- self.jid.to_s <=> user.jid.to_s
19
+ user.is_a?(User) ? self.jid.to_s <=> user.jid.to_s : nil
20
20
  end
21
21
 
22
- def eql?(user)
23
- user.is_a?(User) && self == user
24
- end
22
+ alias :eql? :==
25
23
 
26
24
  def hash
27
25
  jid.to_s.hash
data/lib/vines/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module Vines
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
data/lib/vines.rb CHANGED
@@ -52,12 +52,12 @@ end
52
52
  em-redis
53
53
  eventmachine
54
54
  fiber
55
+ http/parser
55
56
  logger
56
57
  net/ldap
57
58
  nokogiri
58
59
  openssl
59
60
  socket
60
- thin
61
61
  uri
62
62
  yaml
63
63
 
@@ -108,6 +108,7 @@ end
108
108
  vines/stream/parser
109
109
 
110
110
  vines/stream/client
111
+ vines/stream/client/session
111
112
  vines/stream/client/start
112
113
  vines/stream/client/tls
113
114
  vines/stream/client/auth_restart
@@ -123,9 +124,14 @@ end
123
124
  vines/stream/component/ready
124
125
 
125
126
  vines/stream/http
126
- vines/stream/http/http_state
127
- vines/stream/http/http_states
128
- vines/stream/http/http_request
127
+ vines/stream/http/session
128
+ vines/stream/http/sessions
129
+ vines/stream/http/request
130
+ vines/stream/http/start
131
+ vines/stream/http/auth
132
+ vines/stream/http/bind_restart
133
+ vines/stream/http/bind
134
+ vines/stream/http/ready
129
135
 
130
136
  vines/stream/server
131
137
  vines/stream/server/start