skates 0.1.11 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -85,7 +85,7 @@ Skates's edge versions are located at Github : http://github.com/julien51/skates
85
85
 
86
86
  == REQUIREMENTS :
87
87
 
88
- Gems : Eventmachine, nokogiri (please, use build from the guthub repo, since 1.2.3 is not supported by Skates), YAML, log4r, sax-machine, templater
88
+ Gems : Eventmachine, nokogiri, YAML, log4r, sax-machine, templater
89
89
 
90
90
  == LICENSE:
91
91
 
@@ -16,41 +16,40 @@ module Skates
16
16
  end
17
17
 
18
18
  ##
19
- # Connects the ClientConnection based on SRV records for the jid's domain, if no host or port has been specified.
20
- # In any case, we give priority to the specified host and port.
19
+ # Connects the ClientConnection based on SRV records for the jid's domain, if no host has been provided.
20
+ # It will not resolve if params["host"] is an IP.
21
+ # And it will always use
21
22
  def self.connect(params, handler = nil)
22
- return super(params, handler) if params["host"] && params["port"]
23
-
24
- begin
25
- srv = []
26
- Resolv::DNS.open { |dns|
27
- # If ruby version is too old and SRV is unknown, this will raise a NameError
28
- # which is caught below
29
- host_from_jid = params["jid"].split("/").first.split("@").last
30
- Skates.logger.debug {
31
- "RESOLVING: _xmpp-client._tcp.#{host_from_jid} (SRV)"
32
- }
33
- srv = dns.getresources("_xmpp-client._tcp.#{host_from_jid}", Resolv::DNS::Resource::IN::SRV)
34
- }
35
- # Sort SRV records: lowest priority first, highest weight first
36
- srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
37
- # And now, for each record, let's try to connect.
38
- srv.each { |record|
39
- begin
40
- params["host"] = record.target.to_s
41
- params["port"] = Integer(record.port)
42
- super(params, handler)
43
- # Success
44
- break
45
- rescue NotConnected
46
- # Try next SRV record
47
- end
48
- }
49
- rescue NameError
23
+ params["host"] ||= params["jid"].split("/").first.split("@").last
24
+ super(params, handler)
25
+ end
26
+
27
+ ##
28
+ # Resolution for clients, based on SRV records
29
+ def self.resolve(host, &block)
30
+ Resolv::DNS.open { |dns|
31
+ # If ruby version is too old and SRV is unknown, this will raise a NameError
32
+ # which is caught below
50
33
  Skates.logger.debug {
51
- "Resolv::DNS does not support SRV records. Please upgrade to ruby-1.8.3 or later! \n#{$!} : #{$!.backtrace.join("\n")}"
34
+ "RESOLVING: #{srv_for_host(host)} (SRV)"
52
35
  }
53
- end
36
+ begin
37
+ srv = dns.getresources("_xmpp-client._tcp.#{host}", Resolv::DNS::Resource::IN::SRV)
38
+ # Sort SRV records: lowest priority first, highest weight first
39
+ srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
40
+ # And now, for each record, let's try to connect.
41
+ srv.each { |record|
42
+ ip = record.target.to_s
43
+ port = Integer(record.port)
44
+ break if block.call({"host" => ip, "port" => port})
45
+ }
46
+ block.call(false) # bleh, we couldn't resolve to any valid. Too bad.
47
+ rescue NameError
48
+ Skates.logger.debug {
49
+ "Resolv::DNS does not support SRV records. Please upgrade to ruby-1.8.3 or later! \n#{$!} : #{$!.backtrace.join("\n")}"
50
+ }
51
+ end
52
+ }
54
53
  end
55
54
 
56
55
  ##
@@ -4,6 +4,11 @@ module Skates
4
4
  # Upon stanza reception, and depending on the status (connected... etc), this component will handle or forward the stanzas.
5
5
  class ComponentConnection < XmppConnection
6
6
 
7
+ def self.connect(params, handler)
8
+ params["host"] ||= params["jid"]
9
+ super(params, handler)
10
+ end
11
+
7
12
  ##
8
13
  # Creates a new ComponentConnection and waits for data in the stream
9
14
  def initialize(params)
@@ -72,6 +77,28 @@ module Skates
72
77
  'jabber:component:accept'
73
78
  end
74
79
 
80
+ ##
81
+ # Resolution for Components, based on SRV records
82
+ def self.resolve(host, &block)
83
+ Resolv::DNS.open { |dns|
84
+ # If ruby version is too old and SRV is unknown, this will raise a NameError
85
+ # which is caught below
86
+ Skates.logger.debug {
87
+ "RESOLVING: #{host} "
88
+ }
89
+ found = false
90
+ records = dns.getresources(host, Resolv::DNS::Resource::IN::A)
91
+ records.each do |record|
92
+ ip = record.address.to_s
93
+ if block.call({"host" => ip})
94
+ found = true
95
+ break
96
+ end
97
+ end
98
+ block.call(false) unless found # bleh, we couldn't resolve to any valid. Too bad.
99
+ }
100
+ end
101
+
75
102
  private
76
103
 
77
104
  def handshake(stanza)
@@ -38,6 +38,9 @@ module Skates
38
38
  empty_directory :initializers_directory do |d|
39
39
  d.destination = "#{application_name}/config/initializers"
40
40
  end
41
+ empty_directory :destructors_directory do |d|
42
+ d.destination = "#{application_name}/config/destructors"
43
+ end
41
44
  empty_directory :tmp_directory do |d|
42
45
  d.destination = "#{application_name}/tmp"
43
46
  end
@@ -28,6 +28,13 @@ module Skates
28
28
 
29
29
  @@max_stanza_size = 65535
30
30
 
31
+ ##
32
+ # This will the host asynscrhonously and calls the block for each IP:Port pair.
33
+ # if the block returns true, no other record will be tried. If it returns false, the block will be called with the next pair.
34
+ def self.resolve(host, &block)
35
+ block.call(false)
36
+ end
37
+
31
38
  ##
32
39
  # Maximum Stanza size. Default is 65535
33
40
  def self.max_stanza_size
@@ -45,16 +52,26 @@ module Skates
45
52
  # It passes itself (as handler) and the configuration
46
53
  # This can very well be overwritten by subclasses.
47
54
  def self.connect(params, handler)
48
- Skates.logger.debug {
49
- "CONNECTING TO #{params["host"]}:#{params["port"]} with #{handler.inspect} as connection handler" # Very low level Logging
50
- }
51
- begin
52
- EventMachine.connect(params["host"], params["port"], self, params.merge({"handler" => handler}))
53
- rescue RuntimeError
54
- Skates.logger.error {
55
- "CONNECTION ERROR : #{$!.class} => #{$!}" # Very low level Logging
56
- }
57
- raise NotConnected
55
+ if params["host"] =~ /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/
56
+ params["port"] = params["port"] ? params["port"].to_i : 5222
57
+ _connect(params, handler)
58
+ else
59
+ resolve(params["host"]) do |host_info|
60
+ if host_info
61
+ begin
62
+ _connect(params.merge(host_info), handler)
63
+ true # connected! Yay!
64
+ rescue NotConnected
65
+ # It will try the next pair of ip/port
66
+ false
67
+ end
68
+ else
69
+ Skates.logger.error {
70
+ "Sorry, we couldn't resolve #{srv_for_host(params["host"])} to any host that accept XMPP connections. Please provide a params[\"host\"]."
71
+ }
72
+ EM.stop_event_loop
73
+ end
74
+ end
58
75
  end
59
76
  end
60
77
 
@@ -167,6 +184,26 @@ module Skates
167
184
  }
168
185
  end
169
186
  end
187
+
188
+ def self.srv_for_host(host)
189
+ "#{host}"
190
+ end
191
+
192
+ def self._connect(params, handler)
193
+ Skates.logger.debug {
194
+ "CONNECTING TO #{params["host"]}:#{params["port"]} with #{handler.inspect} as connection handler" # Very low level Logging
195
+ }
196
+ begin
197
+ EventMachine.connect(params["host"], params["port"], self, params.merge({"handler" => handler}))
198
+ rescue RuntimeError
199
+ Skates.logger.error {
200
+ "CONNECTION ERROR : #{$!.class} => #{$!}" # Very low level Logging
201
+ }
202
+ raise NotConnected
203
+ end
204
+
205
+ end
206
+
170
207
  end
171
208
 
172
209
  end
@@ -6,8 +6,8 @@ describe Skates::ClientConnection do
6
6
  include SkatesSpecHelper
7
7
 
8
8
  before(:each) do
9
- @params = {"jid" => "jid@server.tld", "password" => "password", "port" => 1234, "host" => "myhost.com"}
10
- @client = Skates::ClientConnection.connect(@params, handler_mock)
9
+ @params = {"jid" => "jid@server.tld", "password" => "password"}
10
+ @client = Skates::ClientConnection.connect(@params.merge({"host" => "0.0.0.0", "port" => 5222}), handler_mock)
11
11
  @client.stub!(:send_xml).and_return(true)
12
12
  end
13
13
 
@@ -18,37 +18,42 @@ describe Skates::ClientConnection do
18
18
  end
19
19
 
20
20
  describe "connect" do
21
- it "should not try to resolve the dns if both the port and host are provided" do
22
- Resolv::DNS.should_not_receive(:open)
23
- @client = Skates::ClientConnection.connect(@params, handler_mock)
21
+ end
22
+
23
+ describe "when resolving the hostname" do
24
+ before(:each) do
25
+ @params.delete("host")
26
+ @params.delete("port")
27
+ @srv = [
28
+ mock(Resolv::DNS::Resource, :priority => 10, :target => "12.13.14.15", :port => 1234),
29
+ mock(Resolv::DNS::Resource, :priority => 3, :target => "12.13.14.16", :port => 4567),
30
+ mock(Resolv::DNS::Resource, :priority => 100, :target => "12.13.14.17", :port => 8910)
31
+ ]
32
+ @mock_dns = mock(Object)
33
+ Resolv::DNS.stub!(:open).and_yield(@mock_dns)
34
+ @mock_dns.stub!(:getresources).and_return(@srv)
24
35
  end
25
36
 
26
- describe "when host and port are not provided" do
27
- before(:each) do
28
- @params.delete("host")
29
- @params.delete("port")
30
- @srv = [
31
- mock(Resolv::DNS::Resource, :priority => 10, :target => "xmpp.server.tld", :port => 1234),
32
- mock(Resolv::DNS::Resource, :priority => 3, :target => "xmpp2.server.tld", :port => 4567),
33
- mock(Resolv::DNS::Resource, :priority => 100, :target => "xmpp3.server.tld", :port => 8910)
34
- ]
35
- @mock_dns = mock(Object)
36
- Resolv::DNS.stub!(:open).and_yield(@mock_dns)
37
- @mock_dns.stub!(:getresources).with("_xmpp-client._tcp.server.tld", Resolv::DNS::Resource::IN::SRV).and_return(@srv)
38
- end
39
-
40
- it "should get resources assiated with _xmpp-client._tcp.host.tld}" do
41
- Resolv::DNS.should_receive(:open).and_yield(@mock_dns)
42
- @mock_dns.should_receive(:getresources).with("_xmpp-client._tcp.server.tld", Resolv::DNS::Resource::IN::SRV).and_return(@srv)
43
- @client = Skates::ClientConnection.connect(@params, handler_mock)
44
- end
45
-
46
- it "should sort the srv records" do
47
- @client = Skates::ClientConnection.connect(@params, handler_mock)
48
- @srv.map {|srv| srv.target }.should == ["xmpp2.server.tld", "xmpp.server.tld", "xmpp3.server.tld"]
37
+ it "should get resources assiated with _xmpp-client._tcp.host.tld}" do
38
+ Resolv::DNS.should_receive(:open).and_yield(@mock_dns)
39
+ @mock_dns.should_receive(:getresources).with("_xmpp-client._tcp.server.tld", Resolv::DNS::Resource::IN::SRV).and_return(@srv)
40
+ Skates::ClientConnection.resolve("server.tld")
41
+ end
42
+
43
+ it "should call the block with the highest priority" do
44
+ Skates::ClientConnection.resolve("xmpp.server.tld") do |params|
45
+ params["host"].should == "12.13.14.16"
46
+ params["port"].should == 4567
47
+ true
48
+ end
49
+ end
50
+
51
+ it "should call the block as many times as needed if they're not connecting" do
52
+ conn = mock(Skates::ClientConnection, :_connect => false)
53
+ conn.should_receive(:_connect).exactly(3).times
54
+ Skates::ClientConnection.resolve("xmpp.server.tld") do |ip, port|
55
+ conn._connect(ip, port)
49
56
  end
50
-
51
- it "should try to connect to each record until one of the them actually connects"
52
57
  end
53
58
  end
54
59
 
@@ -6,7 +6,7 @@ describe Skates::ComponentConnection do
6
6
  include SkatesSpecHelper
7
7
 
8
8
  before(:each) do
9
- @params = {"jid" => "jid@server", "password" => "password", "port" => 1234, "host" => "myhost.com"}
9
+ @params = {"jid" => "jid@server", "password" => "password", "port" => 1234, "host" => "0.0.0.0"}
10
10
  @component = Skates::ComponentConnection.connect(@params, handler_mock)
11
11
  @component.stub!(:send_xml).and_return(true)
12
12
  end
@@ -132,4 +132,13 @@ describe Skates::ComponentConnection do
132
132
 
133
133
  end
134
134
 
135
+ describe "when resolving" do
136
+ it "should resolve records" do
137
+ Skates::ComponentConnection.resolve("xmpp2.superfeedr.com") do |res|
138
+ res["host"].should == "173.45.226.99"
139
+ true
140
+ end
141
+ end
142
+ end
143
+
135
144
  end
@@ -7,24 +7,49 @@ describe Skates::XmppConnection do
7
7
 
8
8
  before(:each) do
9
9
  @params = {"jid" => "jid@server", "password" => "password", "port" => 1234, "host" => "myhost.com"}
10
- @connection = Skates::XmppConnection.connect(@params, handler_mock)
10
+ @connection = Skates::XmppConnection._connect(@params, handler_mock)
11
11
  end
12
12
 
13
- describe "connect" do
13
+ describe "_connect" do
14
14
  it "should connect EventMachine and return it" do
15
15
  EventMachine.should_receive(:connect).with(@params["host"], @params["port"], Skates::XmppConnection, hash_including("handler" => handler_mock)).and_return(@connection)
16
- Skates::XmppConnection.connect(@params, handler_mock).should == @connection
16
+ Skates::XmppConnection._connect(@params, handler_mock).should == @connection
17
17
  end
18
18
 
19
19
  it "should rescue Connection Errors" do
20
20
  EventMachine.stub!(:connect).with(@params["host"], @params["port"], Skates::XmppConnection, hash_including("handler" => handler_mock)).and_raise(RuntimeError)
21
21
  lambda {
22
- Skates::XmppConnection.connect(@params, handler_mock)
22
+ Skates::XmppConnection._connect(@params, handler_mock)
23
23
  }.should raise_error(Skates::NotConnected)
24
24
  end
25
25
 
26
26
  end
27
27
 
28
+ describe "connect" do
29
+ describe "connect" do
30
+ it "should not try to resolve the dns if a host IP has been provided" do
31
+ @params["host"] = "123.123.123.123"
32
+ Skates::XmppConnection.should_not_receive(:resolve)
33
+ Skates::XmppConnection.connect(@params, handler_mock)
34
+ end
35
+
36
+ describe "when a host is provided, which is not an IP" do
37
+ it "should resolve it" do
38
+ @params["host"] = "domain.tld"
39
+ Skates::XmppConnection.should_receive(:resolve)
40
+ Skates::XmppConnection.connect(@params, handler_mock)
41
+ end
42
+ end
43
+
44
+ describe "when no host is provided, and no port either" do
45
+ it "should resolve the host to an IP" do
46
+ Skates::XmppConnection.should_receive(:resolve)
47
+ Skates::XmppConnection.connect(@params, handler_mock)
48
+ end
49
+ end
50
+ end
51
+ end
52
+
28
53
  describe "initialize" do
29
54
  it "should assign @connected to false" do
30
55
  @connection.instance_variable_get("@connected").should be_false
@@ -193,5 +218,5 @@ describe Skates::XmppConnection do
193
218
  @connection.__send__(:receive_data, data)
194
219
  end
195
220
  end
196
-
221
+
197
222
  end
@@ -13,4 +13,6 @@ require File.dirname(__FILE__) + "/dependencies"
13
13
  Skates::Runner::run(ARGV[0] || "development") do
14
14
  # Run the initializers, too. This is done here since some initializers might need EventMachine to be started.
15
15
  Dir.glob('config/initializers/*.rb').each { |f| require f }
16
- end
16
+ end
17
+ # Run the destructors, too. They're called when the app exits.
18
+ Dir.glob('config/destructors/*.rb').each { |f| require f }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skates
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - julien Genestoux