skates 0.1.11 → 0.2.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.
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