celluloid-io 0.14.1 → 0.15.0.pre

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.
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