celluloid-io 0.14.1 → 0.15.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c82454c284234ca1c206dab2aaea9cb4190b8e60
4
- data.tar.gz: b66f5869c880be9551294363865dfd7c5555e377
3
+ metadata.gz: 7ba7ea0fac5d91976c3b8a556686e8d4b778fc7b
4
+ data.tar.gz: 65297d64467f098af4097564c9b266b83d273b09
5
5
  SHA512:
6
- metadata.gz: 57b61a4028497fd37fedc84ea1fc4ffe485475959931e115f1d8485b9cd7b517420fbec83b6a2e85f4e2a57f7ac79e6d62eb5d4f5069fed12e66f9ed07e29488
7
- data.tar.gz: 7f2f28bf81ae7bf8c91fe43bf5456da3a40123e6e7c81bb774bb3da99e0f8b14eb6d0a6e319173a861f445781a12bab05641f6dbc4c274191df3cdf07dc9aa1e
6
+ metadata.gz: 65b04ba6086bf29c11e8b12faf2d7f674660be68b67c77161d4658b7248885602f7cb3dff056af97355ba9e3ab9a3d32e9879e65468f344a3cff19bc65856a99
7
+ data.tar.gz: af01de9578c5408dea445db8ff076d75e75bc3ddca754c4c07895f486c9fed15bd10beab6f3808f2d291be38994e3d6e3af389ed88a7eb813cb8339b26c94840
data/.travis.yml CHANGED
@@ -10,7 +10,6 @@ rvm:
10
10
  matrix:
11
11
  allow_failures:
12
12
  - rvm: ruby-head
13
- - rvm: jruby-19mode
14
13
  - rvm: jruby-head
15
14
  - rvm: rbx-19mode
16
15
 
data/CHANGES.md CHANGED
@@ -1,7 +1,9 @@
1
- 0.14.1 (2013-06-01)
2
- -------------------
3
- * Remove obsolete code for condition owners which is broken by the
4
- Celluloid 0.14.1 release.
1
+ 0.15.0.pre (2013-08-21)
2
+ -----------------------
3
+ * Improved DNS resolver with less NIH and more Ruby stdlib goodness
4
+ * Better match Ruby stdlib TCPServer API
5
+ * Add missing #setsockopt method on Celluloid::IO::TCPServer
6
+ * Add missing #peeraddr method on Celluloid::IO::SSLSocket
5
7
 
6
8
  0.14.0 (2013-05-07)
7
9
  -------------------
data/Gemfile CHANGED
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
4
  gem 'coveralls', require: false
5
- gem 'celluloid', github: 'celluloid/celluloid', branch: '0-14-stable'
5
+ gem 'celluloid', github: 'celluloid/celluloid', branch: 'master'
data/README.md CHANGED
@@ -30,7 +30,7 @@ library just to take advantage of Celluloid::IO's event loop and you can
30
30
  freely switch between evented and blocking IO even over the lifetime of a
31
31
  single connection.
32
32
 
33
- Celluloid::IO uses the [nio4r gem](https://github.com/tarcieri/nio4r)
33
+ Celluloid::IO uses the [nio4r gem](https://github.com/celluloid/nio4r)
34
34
  to monitor IO objects, which provides cross-platform and cross-Ruby
35
35
  implementation access to high-performance system calls such as epoll
36
36
  and kqueue.
data/benchmarks/actor.rb CHANGED
@@ -37,7 +37,7 @@ end
37
37
 
38
38
  Benchmark.ips do |ips|
39
39
  ips.report("spawn") { ExampleActor.new.terminate }
40
-
40
+
41
41
  ips.report("calls") { example_actor.example_method }
42
42
 
43
43
  ips.report("async calls") do |n|
data/celluloid-io.gemspec CHANGED
@@ -15,8 +15,8 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Celluloid::IO::VERSION
17
17
 
18
- gem.add_dependency 'celluloid', '>= 0.14.1'
19
- gem.add_dependency 'nio4r', '>= 0.4.5'
18
+ gem.add_dependency 'celluloid', '>= 0.15.0.pre'
19
+ gem.add_dependency 'nio4r', '>= 0.5.0'
20
20
 
21
21
  gem.add_development_dependency 'rake'
22
22
  gem.add_development_dependency 'rspec'
@@ -5,36 +5,22 @@ module Celluloid
5
5
  # Asynchronous DNS resolver using Celluloid::IO::UDPSocket
6
6
  class DNSResolver
7
7
  RESOLV_CONF = '/etc/resolv.conf'
8
- HOSTS = '/etc/hosts'
9
8
  DNS_PORT = 53
10
-
9
+
11
10
  @mutex = Mutex.new
12
11
  @identifier = 1
13
-
12
+
14
13
  def self.generate_id
15
14
  @mutex.synchronize { @identifier = (@identifier + 1) & 0xFFFF }
16
15
  end
17
-
16
+
18
17
  def self.nameservers(config = RESOLV_CONF)
19
18
  File.read(config).scan(/^\s*nameserver\s+([0-9.:]+)/).flatten
20
19
  end
21
20
 
22
- # FIXME: Y U NO Resolv::Hosts?
23
- def self.hosts(hostfile = HOSTS)
24
- hosts = {}
25
- File.open(hostfile) do |f|
26
- f.each_line do |host_entry|
27
- entries = host_entry.gsub(/#.*$/, '').gsub(/\s+/, ' ').split(' ')
28
- addr = entries.shift
29
- entries.each { |e| hosts[e] ||= addr }
30
- end
31
- end
32
- hosts
33
- end
34
-
35
21
  def initialize
36
- @nameservers, @hosts = self.class.nameservers, self.class.hosts
37
-
22
+ @nameservers = self.class.nameservers
23
+
38
24
  # TODO: fall back on other nameservers if the first one is unavailable
39
25
  @server = @nameservers.first
40
26
 
@@ -42,42 +28,61 @@ module Celluloid
42
28
  # Celluloid::IO::UDPSocket
43
29
  @socket = UDPSocket.new
44
30
  end
45
-
46
- def resolve(hostname)
47
- host = @hosts[hostname]
48
- if host
49
- begin
50
- return Resolv::IPv4.create(host)
51
- rescue ArgumentError
52
- end
53
31
 
54
- begin
55
- return Resolv::IPv6.create(host)
56
- rescue ArgumentError
32
+ def resolve(hostname)
33
+ if host = resolve_hostname(hostname)
34
+ unless ip_address = resolve_host(host)
35
+ raise Resolv::ResolvError, "invalid entry in hosts file: #{host}"
57
36
  end
58
-
59
- raise Resolv::ResolvError, "invalid entry in hosts file: #{host}"
37
+ return ip_address
60
38
  end
61
-
62
- query = Resolv::DNS::Message.new
63
- query.id = self.class.generate_id
64
- query.rd = 1
65
- query.add_question hostname, Resolv::DNS::Resource::IN::A
66
-
39
+
40
+ query = build_query(hostname)
67
41
  @socket.send query.encode, 0, @server, DNS_PORT
68
42
  data, _ = @socket.recvfrom(512)
69
43
  response = Resolv::DNS::Message.decode(data)
70
-
44
+
71
45
  addrs = []
72
46
  # The answer might include IN::CNAME entries so filters them out
73
47
  # to include IN::A & IN::AAAA entries only.
74
- response.each_answer { |name, ttl, value| addrs << (value.respond_to?(:address) ? value.address : nil) }
75
- addrs.compact!
76
-
48
+ response.each_answer { |name, ttl, value| addrs << value.address if value.respond_to?(:address) }
49
+
77
50
  return if addrs.empty?
78
51
  return addrs.first if addrs.size == 1
79
52
  addrs
80
53
  end
54
+
55
+ private
56
+
57
+ def resolve_hostname(hostname)
58
+ # Resolv::Hosts#getaddresses pushes onto a stack
59
+ # so since we want the first occurance, simply
60
+ # pop off the stack.
61
+ resolv.getaddresses(hostname).pop rescue nil
62
+ end
63
+
64
+ def resolv
65
+ @resolv ||= Resolv::Hosts.new
66
+ end
67
+
68
+ def build_query(hostname)
69
+ Resolv::DNS::Message.new.tap do |query|
70
+ query.id = self.class.generate_id
71
+ query.rd = 1
72
+ query.add_question hostname, Resolv::DNS::Resource::IN::A
73
+ end
74
+ end
75
+
76
+ def resolve_host(host)
77
+ resolve_ip(Resolv::IPv4, host) || resolve_ip(Resolv::IPv6, host)
78
+ end
79
+
80
+ def resolve_ip(klass, host)
81
+ begin
82
+ klass.create(host)
83
+ rescue ArgumentError
84
+ end
85
+ end
81
86
  end
82
87
  end
83
88
  end
@@ -7,7 +7,7 @@ module Celluloid
7
7
  extend Forwardable
8
8
 
9
9
  def_delegators :@socket, :read_nonblock, :write_nonblock, :close, :closed?,
10
- :cert, :cipher, :client_ca, :peer_cert, :peer_cert_chain, :verify_result
10
+ :cert, :cipher, :client_ca, :peer_cert, :peer_cert_chain, :verify_result, :peeraddr
11
11
 
12
12
  def initialize(io, ctx = OpenSSL::SSL::SSLContext.new)
13
13
  super()
@@ -5,10 +5,10 @@ module Celluloid
5
5
  # TCPServer with combined blocking and evented support
6
6
  class TCPServer
7
7
  extend Forwardable
8
- def_delegators :@server, :listen, :sysaccept, :close, :closed?, :addr
8
+ def_delegators :@server, :listen, :sysaccept, :close, :closed?, :addr, :setsockopt
9
9
 
10
- def initialize(hostname, port)
11
- @server = ::TCPServer.new(hostname, port)
10
+ def initialize(hostname_or_port, port = nil)
11
+ @server = ::TCPServer.new(hostname_or_port, port)
12
12
  end
13
13
 
14
14
  def accept
@@ -37,7 +37,7 @@ module Celluloid
37
37
  # local end to establish the connection.
38
38
  def initialize(remote_host, remote_port = nil, local_host = nil, local_port = nil)
39
39
  super()
40
-
40
+
41
41
  # Allow users to pass in a Ruby TCPSocket directly
42
42
  if remote_host.is_a? ::TCPSocket
43
43
  @addr = nil
@@ -65,7 +65,7 @@ module Celluloid
65
65
  unless @addr
66
66
  addrs = Array(DNSResolver.new.resolve(remote_host))
67
67
  raise Resolv::ResolvError, "DNS result has no information for #{remote_host}" if addrs.empty?
68
-
68
+
69
69
  # Pseudorandom round-robin DNS support :/
70
70
  @addr = addrs[rand(addrs.size)]
71
71
  end
@@ -22,7 +22,7 @@ module Celluloid
22
22
  # Open a UNIX connection.
23
23
  def initialize(socket_path, &block)
24
24
  super()
25
-
25
+
26
26
  # Allow users to pass in a Ruby UNIXSocket directly
27
27
  if socket_path.is_a? ::UNIXSocket
28
28
  @socket = socket_path
@@ -1,5 +1,5 @@
1
1
  module Celluloid
2
2
  module IO
3
- VERSION = "0.14.1"
3
+ VERSION = "0.15.0.pre"
4
4
  end
5
5
  end
@@ -1,26 +1,33 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Celluloid::IO::DNSResolver do
4
- it "resolves domain names" do
5
- resolver = Celluloid::IO::DNSResolver.new
6
- resolver.resolve("celluloid.io").should == Resolv::IPv4.create("207.97.227.245")
7
- end
4
+ describe '#resolve' do
5
+ it 'resolves hostnames' do
6
+ resolver = Celluloid::IO::DNSResolver.new
7
+ resolver.resolve('localhost').should eq Resolv::IPv4.create("127.0.0.1")
8
+ end
8
9
 
9
- it "resolves CNAME responses" do
10
- resolver = Celluloid::IO::DNSResolver.new
11
- results = resolver.resolve("www.google.com")
12
- if results.is_a?(Array)
13
- results.all? {|i| i.is_a?(Resolv::IPv4) }.should be_true
14
- else
15
- results.is_a?(Resolv::IPv4).should be_true
10
+ it "resolves domain names" do
11
+ resolver = Celluloid::IO::DNSResolver.new
12
+ resolver.resolve("celluloid.io").should == Resolv::IPv4.create("207.97.227.245")
16
13
  end
17
- # www.yahoo.com will be resolved randomly whether multiple or
18
- # single entry.
19
- results = resolver.resolve("www.yahoo.com")
20
- if results.is_a?(Array)
21
- results.all? {|i| i.is_a?(Resolv::IPv4) }.should be_true
22
- else
23
- results.is_a?(Resolv::IPv4).should be_true
14
+
15
+ it "resolves CNAME responses" do
16
+ resolver = Celluloid::IO::DNSResolver.new
17
+ results = resolver.resolve("www.google.com")
18
+ if results.is_a?(Array)
19
+ results.all? {|i| i.should be_an_instance_of(Resolv::IPv4) }
20
+ else
21
+ results.should be_an_instance_of(Resolv::IPv4)
22
+ end
23
+ # www.yahoo.com will be resolved randomly whether multiple or
24
+ # single entry.
25
+ results = resolver.resolve("www.yahoo.com")
26
+ if results.is_a?(Array)
27
+ results.all? {|i| i.should be_an_instance_of(Resolv::IPv4) }
28
+ else
29
+ results.should be_an_instance_of(Resolv::IPv4)
30
+ end
24
31
  end
25
32
  end
26
33
  end
@@ -59,6 +59,14 @@ describe Celluloid::IO::SSLSocket do
59
59
  end
60
60
  end
61
61
 
62
+ context "duck typing ::SSLSocket" do
63
+ it "responds to #peeraddr" do
64
+ with_ssl_sockets do |ssl_client, ssl_peer|
65
+ expect{ ssl_client.peeraddr }.to_not raise_error
66
+ end
67
+ end
68
+ end
69
+
62
70
  context "inside Celluloid::IO" do
63
71
  it "connects to SSL servers over TCP" do
64
72
  with_ssl_sockets do |ssl_client, ssl_peer|
@@ -4,6 +4,10 @@ describe Celluloid::IO::TCPServer do
4
4
  describe "#accept" do
5
5
  let(:payload) { 'ohai' }
6
6
 
7
+ it "can be initialized without a host" do
8
+ expect{ server = Celluloid::IO::TCPServer.new(2000); server.close }.to_not raise_error
9
+ end
10
+
7
11
  context "inside Celluloid::IO" do
8
12
  it "should be evented" do
9
13
  with_tcp_server do |subject|
@@ -79,6 +79,32 @@ describe Celluloid::IO::TCPSocket do
79
79
  }.to raise_error(Errno::ECONNREFUSED)
80
80
  end
81
81
 
82
+ context 'eof?' do
83
+ it "blocks actor then returns by close" do
84
+ with_connected_sockets do |subject, peer|
85
+ started_at = Time.now
86
+ Thread.new{ sleep 0.5; peer.close; }
87
+ within_io_actor { subject.eof? }
88
+ (Time.now - started_at).should > 0.5
89
+ end
90
+ end
91
+
92
+ it "blocks until gets the next byte" do
93
+ with_connected_sockets do |subject, peer|
94
+ peer << 0x00
95
+ peer.flush
96
+ expect {
97
+ within_io_actor {
98
+ subject.read(1)
99
+ Celluloid.timeout(0.5) {
100
+ subject.eof?.should be_false
101
+ }
102
+ }
103
+ }.to raise_error(Celluloid::Task::TimeoutError)
104
+ end
105
+ end
106
+ end
107
+
82
108
  context "readpartial" do
83
109
  it "raises EOFError when reading from a closed socket" do
84
110
  with_connected_sockets do |subject, peer|
@@ -90,7 +116,7 @@ describe Celluloid::IO::TCPSocket do
90
116
  end
91
117
 
92
118
  it "raises IOError when active sockets are closed across threads" do
93
- pending "not implemented"
119
+ pending "not implemented"
94
120
 
95
121
  with_connected_sockets do |subject, peer|
96
122
  actor = ExampleActor.new
@@ -26,7 +26,7 @@ describe Celluloid::IO::UNIXServer do
26
26
  peer.read(payload.size).should eq payload
27
27
  end
28
28
  end
29
-
29
+
30
30
  it "raises if server already up" do
31
31
  with_unix_server do |subject|
32
32
  within_io_actor do
@@ -55,7 +55,7 @@ describe Celluloid::IO::UNIXServer do
55
55
  peer.read(payload.size).should eq payload
56
56
  end
57
57
  end
58
-
58
+
59
59
  it "raises if server already up" do
60
60
  with_unix_server do |subject|
61
61
  expect {
@@ -63,7 +63,7 @@ describe Celluloid::IO::UNIXServer do
63
63
  }.to raise_error(Errno::EADDRINUSE)
64
64
  end
65
65
  end
66
-
66
+
67
67
  end
68
68
  end
69
69
  end
@@ -92,6 +92,32 @@ describe Celluloid::IO::UNIXSocket do
92
92
  }.to raise_error(EOFError)
93
93
  end
94
94
  end
95
+
96
+ context 'eof?' do
97
+ it "blocks actor then returns by close" do
98
+ with_connected_sockets do |subject, peer|
99
+ started_at = Time.now
100
+ Thread.new{ sleep 0.5; peer.close; }
101
+ within_io_actor { subject.eof? }
102
+ (Time.now - started_at).should > 0.5
103
+ end
104
+ end
105
+
106
+ it "blocks until gets the next byte" do
107
+ with_connected_sockets do |subject, peer|
108
+ peer << 0x00
109
+ peer.flush
110
+ expect {
111
+ within_io_actor {
112
+ subject.read(1)
113
+ Celluloid.timeout(0.5) {
114
+ subject.eof?.should be_false
115
+ }
116
+ }
117
+ }.to raise_error(Celluloid::Task::TimeoutError)
118
+ end
119
+ end
120
+ end
95
121
  end
96
122
 
97
123
  context "outside Celluloid::IO" do
data/spec/spec_helper.rb CHANGED
@@ -6,21 +6,23 @@ require 'coveralls'
6
6
  Coveralls.wear!
7
7
 
8
8
  logfile = File.open(File.expand_path("../../log/test.log", __FILE__), 'a')
9
- Celluloid.logger = Logger.new(logfile)
9
+ logfile.sync = true
10
+
11
+ logger = Celluloid.logger = Logger.new(logfile)
12
+
13
+ Celluloid.shutdown_timeout = 1
10
14
 
11
15
  RSpec.configure do |config|
16
+ config.filter_run :focus => true
17
+ config.run_all_when_everything_filtered = true
18
+
12
19
  config.before do
20
+ Celluloid.logger = logger
13
21
  Celluloid.shutdown
22
+
14
23
  Celluloid.boot
15
- FileUtils.rm("/tmp/cell_sock") if File.exist?("/tmp/cell_sock")
16
- end
17
- end
18
24
 
19
- # FIXME: Hax until test termination can be cleaned up
20
- module Celluloid
21
- class << self
22
- undef :shutdown
23
- def shutdown; end # hax: noop!
25
+ FileUtils.rm("/tmp/cell_sock") if File.exist?("/tmp/cell_sock")
24
26
  end
25
27
  end
26
28
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: celluloid-io
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.1
4
+ version: 0.15.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-01 00:00:00.000000000 Z
11
+ date: 2013-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '>='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.14.1
19
+ version: 0.15.0.pre
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.14.1
26
+ version: 0.15.0.pre
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nio4r
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
- version: 0.4.5
33
+ version: 0.5.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
- version: 0.4.5
40
+ version: 0.5.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -177,9 +177,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
177
177
  version: '0'
178
178
  required_rubygems_version: !ruby/object:Gem::Requirement
179
179
  requirements:
180
- - - '>='
180
+ - - '>'
181
181
  - !ruby/object:Gem::Version
182
- version: '0'
182
+ version: 1.3.1
183
183
  requirements: []
184
184
  rubyforge_project:
185
185
  rubygems_version: 2.0.3