async-io 1.7.0 → 1.8.0
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 +4 -4
- data/README.md +1 -1
- data/async-io.gemspec +1 -1
- data/lib/async/io/notification.rb +0 -2
- data/lib/async/io/stream.rb +47 -16
- data/lib/async/io/version.rb +1 -1
- data/spec/async/io/ssl_server_spec.rb +86 -22
- data/spec/async/io/stream_spec.rb +46 -2
- metadata +4 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: b298c4c118c511eaabda86500a8d08bf02b01cd156e0858cb962f4d3005ce665
         | 
| 4 | 
            +
              data.tar.gz: 1a231a883488b441d599991043409204b2f282df470fdd8b15d18afa6f9b8e06
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8b87b6ca52a9e6164e4c6e549eaa2581d2c71908488f1f8235f0a2a8bbe25dd6e551a419b65f9ebd4be6b5c0182e99315c552cf36cc309777d311cd79397accc
         | 
| 7 | 
            +
              data.tar.gz: 1cd79fdb63398e13ce10041b4facf4bb1dc5498065c18eac8f3265cd2f842f6360b6f31e2b41acf11df29c62096810940050f4e51a7bceb4e9e242af9cfbf81d
         | 
    
        data/README.md
    CHANGED
    
    
    
        data/async-io.gemspec
    CHANGED
    
    | @@ -17,7 +17,7 @@ Gem::Specification.new do |spec| | |
| 17 17 | 
             
            	spec.has_rdoc      = "yard"
         | 
| 18 18 |  | 
| 19 19 | 
             
            	spec.add_dependency "async", "~> 1.3"
         | 
| 20 | 
            -
            	spec.add_development_dependency "async-rspec", "~> 1. | 
| 20 | 
            +
            	spec.add_development_dependency "async-rspec", "~> 1.4"
         | 
| 21 21 |  | 
| 22 22 | 
             
            	spec.add_development_dependency "bundler", "~> 1.3"
         | 
| 23 23 | 
             
            	spec.add_development_dependency "rake", "~> 10.0"
         | 
    
        data/lib/async/io/stream.rb
    CHANGED
    
    | @@ -38,27 +38,49 @@ module Async | |
| 38 38 | 
             
            			end
         | 
| 39 39 |  | 
| 40 40 | 
             
            			attr :io
         | 
| 41 | 
            +
            			attr :block_size
         | 
| 41 42 |  | 
| 42 43 | 
             
            			# Reads `size` bytes from the stream. If size is not specified, read until end of file.
         | 
| 43 44 | 
             
            			def read(size = nil)
         | 
| 44 | 
            -
            				return  | 
| 45 | 
            +
            				return '' if size == 0
         | 
| 46 | 
            +
            				
         | 
| 47 | 
            +
            				if size
         | 
| 48 | 
            +
            					if size <= @block_size
         | 
| 49 | 
            +
            						fill_read_buffer until @eof or @read_buffer.size >= size
         | 
| 50 | 
            +
            					else
         | 
| 51 | 
            +
            						fill_read_buffer(size - @read_buffer.size) until @eof or @read_buffer.size >= size
         | 
| 52 | 
            +
            					end
         | 
| 53 | 
            +
            				else
         | 
| 54 | 
            +
            					fill_read_buffer until @eof
         | 
| 55 | 
            +
            				end
         | 
| 45 56 |  | 
| 46 | 
            -
            				 | 
| 57 | 
            +
            				return consume_read_buffer(size)
         | 
| 58 | 
            +
            			end
         | 
| 59 | 
            +
            			
         | 
| 60 | 
            +
            			# Read at most `size` bytes from the stream. Will avoid reading from the underlying stream if possible.
         | 
| 61 | 
            +
            			def read_partial(size = nil)
         | 
| 62 | 
            +
            				return '' if size == 0
         | 
| 63 | 
            +
            				
         | 
| 64 | 
            +
            				if @read_buffer.empty? and !@eof
         | 
| 47 65 | 
             
            					fill_read_buffer
         | 
| 48 66 | 
             
            				end
         | 
| 49 | 
            -
             | 
| 67 | 
            +
            				
         | 
| 50 68 | 
             
            				return consume_read_buffer(size)
         | 
| 51 69 | 
             
            			end
         | 
| 52 | 
            -
             | 
| 70 | 
            +
            			
         | 
| 53 71 | 
             
            			# Writes `string` to the buffer. When the buffer is full or #sync is true the
         | 
| 54 72 | 
             
            			# buffer is flushed to the underlying `io`.
         | 
| 55 73 | 
             
            			# @param string the string to write to the buffer.
         | 
| 56 74 | 
             
            			# @return the number of bytes appended to the buffer.
         | 
| 57 75 | 
             
            			def write(string)
         | 
| 58 | 
            -
            				@write_buffer  | 
| 59 | 
            -
             | 
| 60 | 
            -
            				 | 
| 61 | 
            -
            					 | 
| 76 | 
            +
            				if @write_buffer.empty? and string.bytesize >= @block_size
         | 
| 77 | 
            +
            					syswrite(string)
         | 
| 78 | 
            +
            				else
         | 
| 79 | 
            +
            					@write_buffer << string
         | 
| 80 | 
            +
            					
         | 
| 81 | 
            +
            					if @write_buffer.size >= @block_size
         | 
| 82 | 
            +
            						flush
         | 
| 83 | 
            +
            					end
         | 
| 62 84 | 
             
            				end
         | 
| 63 85 |  | 
| 64 86 | 
             
            				return string.bytesize
         | 
| @@ -73,8 +95,10 @@ module Async | |
| 73 95 |  | 
| 74 96 | 
             
            			# Flushes buffered data to the stream.
         | 
| 75 97 | 
             
            			def flush
         | 
| 76 | 
            -
            				 | 
| 77 | 
            -
             | 
| 98 | 
            +
            				unless @write_buffer.empty?
         | 
| 99 | 
            +
            					syswrite(@write_buffer)
         | 
| 100 | 
            +
            					@write_buffer.clear
         | 
| 101 | 
            +
            				end
         | 
| 78 102 | 
             
            			end
         | 
| 79 103 |  | 
| 80 104 | 
             
            			def gets(separator = $/)
         | 
| @@ -138,15 +162,13 @@ module Async | |
| 138 162 | 
             
            			private
         | 
| 139 163 |  | 
| 140 164 | 
             
            			# Fills the buffer from the underlying stream.
         | 
| 141 | 
            -
            			def fill_read_buffer
         | 
| 142 | 
            -
            				if  | 
| 143 | 
            -
            					@read_buffer << buffer
         | 
| 144 | 
            -
            				else
         | 
| 165 | 
            +
            			def fill_read_buffer(size = @block_size)
         | 
| 166 | 
            +
            				if !sysread(size, @read_buffer)
         | 
| 145 167 | 
             
            					@eof = true
         | 
| 146 168 | 
             
            				end
         | 
| 147 169 | 
             
            			end
         | 
| 148 170 |  | 
| 149 | 
            -
            			# Consumes `size` bytes from the buffer.
         | 
| 171 | 
            +
            			# Consumes at most `size` bytes from the buffer.
         | 
| 150 172 | 
             
            			# @param size [Integer|nil] The amount of data to consume. If nil, consume entire buffer.
         | 
| 151 173 | 
             
            			def consume_read_buffer(size = nil)
         | 
| 152 174 | 
             
            				# If we are at eof, and the read buffer is empty, we can't consume anything.
         | 
| @@ -154,7 +176,7 @@ module Async | |
| 154 176 |  | 
| 155 177 | 
             
            				result = nil
         | 
| 156 178 |  | 
| 157 | 
            -
            				if size == nil || size  | 
| 179 | 
            +
            				if size == nil || size >= @read_buffer.size
         | 
| 158 180 | 
             
            					# Consume the entire read buffer:
         | 
| 159 181 | 
             
            					result = @read_buffer.dup
         | 
| 160 182 | 
             
            					@read_buffer.clear
         | 
| @@ -187,6 +209,15 @@ module Async | |
| 187 209 |  | 
| 188 210 | 
             
            				return written
         | 
| 189 211 | 
             
            			end
         | 
| 212 | 
            +
            			
         | 
| 213 | 
            +
            			# Read to 
         | 
| 214 | 
            +
            			def sysread(size, buffer)
         | 
| 215 | 
            +
            				if buffer.empty?
         | 
| 216 | 
            +
            					@io.read(size, buffer)
         | 
| 217 | 
            +
            				elsif chunk = @io.read(size)
         | 
| 218 | 
            +
            					buffer << chunk
         | 
| 219 | 
            +
            				end
         | 
| 220 | 
            +
            			end
         | 
| 190 221 | 
             
            		end
         | 
| 191 222 | 
             
            	end
         | 
| 192 223 | 
             
            end
         | 
    
        data/lib/async/io/version.rb
    CHANGED
    
    
| @@ -25,36 +25,100 @@ require_relative 'generic_examples' | |
| 25 25 |  | 
| 26 26 | 
             
            RSpec.describe Async::IO::SSLServer do
         | 
| 27 27 | 
             
            	include_context Async::RSpec::Reactor
         | 
| 28 | 
            -
            	include_context Async::RSpec::SSL::VerifiedContexts
         | 
| 29 | 
            -
            	include_context Async::RSpec::SSL::ValidCertificate
         | 
| 30 28 |  | 
| 31 | 
            -
            	 | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
            		 | 
| 39 | 
            -
            		 | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
            					 | 
| 29 | 
            +
            	context 'single host' do
         | 
| 30 | 
            +
            		include_context Async::RSpec::SSL::VerifiedContexts
         | 
| 31 | 
            +
            		include_context Async::RSpec::SSL::ValidCertificate
         | 
| 32 | 
            +
            		
         | 
| 33 | 
            +
            		let(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6780, reuse_port: true)}
         | 
| 34 | 
            +
            		let(:server_endpoint) {Async::IO::SecureEndpoint.new(endpoint, ssl_context: server_context)}
         | 
| 35 | 
            +
            		let(:client_endpoint) {Async::IO::SecureEndpoint.new(endpoint, ssl_context: client_context)}
         | 
| 36 | 
            +
            		
         | 
| 37 | 
            +
            		let(:data) {"What one programmer can do in one month, two programmers can do in two months."}
         | 
| 38 | 
            +
            		
         | 
| 39 | 
            +
            		it 'can accept_each connections' do
         | 
| 40 | 
            +
            			# Accept a single incoming connection and then finish.
         | 
| 41 | 
            +
            			server_task = reactor.async do |task|
         | 
| 42 | 
            +
            				server_endpoint.bind do |server|
         | 
| 43 | 
            +
            					server.listen(10)
         | 
| 44 | 
            +
            					
         | 
| 45 | 
            +
            					server.accept_each do |peer, address|
         | 
| 46 | 
            +
            						data = peer.read(512)
         | 
| 47 | 
            +
            						peer.write(data)
         | 
| 48 | 
            +
            					end
         | 
| 46 49 | 
             
            				end
         | 
| 47 50 | 
             
            			end
         | 
| 51 | 
            +
            			
         | 
| 52 | 
            +
            			reactor.async do
         | 
| 53 | 
            +
            				client_endpoint.connect do |client|
         | 
| 54 | 
            +
            					client.write(data)
         | 
| 55 | 
            +
            					
         | 
| 56 | 
            +
            					expect(client.read(512)).to be == data
         | 
| 57 | 
            +
            				end
         | 
| 58 | 
            +
            				
         | 
| 59 | 
            +
            				server_task.stop
         | 
| 60 | 
            +
            			end
         | 
| 48 61 | 
             
            		end
         | 
| 62 | 
            +
            	end
         | 
| 63 | 
            +
            	
         | 
| 64 | 
            +
            	context 'multiple hosts' do
         | 
| 65 | 
            +
            		let(:hosts) {['test.com', 'example.com']}
         | 
| 66 | 
            +
            		
         | 
| 67 | 
            +
            		include_context Async::RSpec::SSL::HostCertificates
         | 
| 49 68 |  | 
| 50 | 
            -
            		 | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 69 | 
            +
            		let(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6782, reuse_port: true)}
         | 
| 70 | 
            +
            		let(:server_endpoint) {Async::IO::SecureEndpoint.new(endpoint, ssl_context: server_context)}
         | 
| 71 | 
            +
            		let(:valid_client_endpoint) {Async::IO::SecureEndpoint.new(endpoint, hostname: 'example.com', ssl_context: client_context)}
         | 
| 72 | 
            +
            		let(:invalid_client_endpoint) {Async::IO::SecureEndpoint.new(endpoint, hostname: 'fleeb.com', ssl_context: client_context)}
         | 
| 73 | 
            +
            		
         | 
| 74 | 
            +
            		let(:data) {"What one programmer can do in one month, two programmers can do in two months."}
         | 
| 75 | 
            +
            		
         | 
| 76 | 
            +
            		it 'can select correct host' do
         | 
| 77 | 
            +
            			# Accept a single incoming connection and then finish.
         | 
| 78 | 
            +
            			server_task = reactor.async do |task|
         | 
| 79 | 
            +
            				server_endpoint.bind do |server|
         | 
| 80 | 
            +
            					server.listen(10)
         | 
| 81 | 
            +
            					
         | 
| 82 | 
            +
            					server.accept_each do |peer, address|
         | 
| 83 | 
            +
            						expect(peer.hostname).to be == 'example.com'
         | 
| 84 | 
            +
            						
         | 
| 85 | 
            +
            						data = peer.read(512)
         | 
| 86 | 
            +
            						peer.write(data)
         | 
| 87 | 
            +
            					end
         | 
| 88 | 
            +
            				end
         | 
| 89 | 
            +
            			end
         | 
| 90 | 
            +
            			
         | 
| 91 | 
            +
            			reactor.async do
         | 
| 92 | 
            +
            				valid_client_endpoint.connect do |client|
         | 
| 93 | 
            +
            					client.write(data)
         | 
| 94 | 
            +
            					
         | 
| 95 | 
            +
            					expect(client.read(512)).to be == data
         | 
| 96 | 
            +
            				end
         | 
| 53 97 |  | 
| 54 | 
            -
            				 | 
| 98 | 
            +
            				server_task.stop
         | 
| 99 | 
            +
            			end
         | 
| 100 | 
            +
            		end
         | 
| 101 | 
            +
            		
         | 
| 102 | 
            +
            		it 'it fails with invalid host' do
         | 
| 103 | 
            +
            			# Accept a single incoming connection and then finish.
         | 
| 104 | 
            +
            			server_task = reactor.async do |task|
         | 
| 105 | 
            +
            				server_endpoint.bind do |server|
         | 
| 106 | 
            +
            					server.listen(10)
         | 
| 107 | 
            +
            					
         | 
| 108 | 
            +
            					server.accept_each do |peer, address|
         | 
| 109 | 
            +
            						peer.close
         | 
| 110 | 
            +
            					end
         | 
| 111 | 
            +
            				end
         | 
| 55 112 | 
             
            			end
         | 
| 56 113 |  | 
| 57 | 
            -
            			 | 
| 114 | 
            +
            			reactor.async do
         | 
| 115 | 
            +
            				expect do
         | 
| 116 | 
            +
            					invalid_client_endpoint.connect do |client|
         | 
| 117 | 
            +
            					end
         | 
| 118 | 
            +
            				end.to raise_error(OpenSSL::SSL::SSLError, /handshake failure/)
         | 
| 119 | 
            +
            				
         | 
| 120 | 
            +
            				server_task.stop
         | 
| 121 | 
            +
            			end
         | 
| 58 122 | 
             
            		end
         | 
| 59 123 | 
             
            	end
         | 
| 60 124 | 
             
            end
         | 
| @@ -26,16 +26,60 @@ RSpec.describe Async::IO::Stream do | |
| 26 26 |  | 
| 27 27 | 
             
            	describe '#read' do
         | 
| 28 28 | 
             
            		it "should read everything" do
         | 
| 29 | 
            -
            			io. | 
| 29 | 
            +
            			io.write "Hello World"
         | 
| 30 30 | 
             
            			io.seek(0)
         | 
| 31 31 |  | 
| 32 | 
            -
            			expect( | 
| 32 | 
            +
            			expect(io).to receive(:read).and_call_original.twice
         | 
| 33 | 
            +
            			
         | 
| 34 | 
            +
            			expect(stream.read).to be == "Hello World"
         | 
| 35 | 
            +
            			expect(stream).to be_eof
         | 
| 36 | 
            +
            		end
         | 
| 37 | 
            +
            		
         | 
| 38 | 
            +
            		it "should read only the amount requested" do
         | 
| 39 | 
            +
            			io.write "Hello World"
         | 
| 40 | 
            +
            			io.seek(0)
         | 
| 41 | 
            +
            			
         | 
| 42 | 
            +
            			expect(io).to receive(:read).and_call_original.twice
         | 
| 43 | 
            +
            			
         | 
| 44 | 
            +
            			expect(stream.read(4)).to be == "Hell"
         | 
| 45 | 
            +
            			expect(stream).to_not be_eof
         | 
| 46 | 
            +
            			
         | 
| 47 | 
            +
            			expect(stream.read(20)).to be == "o World"
         | 
| 33 48 | 
             
            			expect(stream).to be_eof
         | 
| 34 49 | 
             
            		end
         | 
| 35 50 | 
             
            	end
         | 
| 36 51 |  | 
| 52 | 
            +
            	describe '#flush' do
         | 
| 53 | 
            +
            		it "should not call write if write buffer is empty" do
         | 
| 54 | 
            +
            			expect(io).to_not receive(:write)
         | 
| 55 | 
            +
            			
         | 
| 56 | 
            +
            			stream.flush
         | 
| 57 | 
            +
            		end
         | 
| 58 | 
            +
            		
         | 
| 59 | 
            +
            		it "should flush underlying data when it exceeds block size" do
         | 
| 60 | 
            +
            			expect(io).to receive(:write).and_call_original.once
         | 
| 61 | 
            +
            			
         | 
| 62 | 
            +
            			stream.block_size.times do
         | 
| 63 | 
            +
            				stream.write("!")
         | 
| 64 | 
            +
            			end
         | 
| 65 | 
            +
            		end
         | 
| 66 | 
            +
            	end
         | 
| 67 | 
            +
            	
         | 
| 68 | 
            +
            	describe '#read_partial' do
         | 
| 69 | 
            +
            		it "should avoid calling read" do
         | 
| 70 | 
            +
            			io.write "Hello World" * 1024
         | 
| 71 | 
            +
            			io.seek(0)
         | 
| 72 | 
            +
            			
         | 
| 73 | 
            +
            			expect(io).to receive(:read).and_call_original.once
         | 
| 74 | 
            +
            			
         | 
| 75 | 
            +
            			expect(stream.read_partial(11)).to be == "Hello World"
         | 
| 76 | 
            +
            		end
         | 
| 77 | 
            +
            	end
         | 
| 78 | 
            +
            	
         | 
| 37 79 | 
             
            	describe '#write' do
         | 
| 38 80 | 
             
            		it "should read one line" do
         | 
| 81 | 
            +
            			expect(io).to receive(:write).and_call_original.once
         | 
| 82 | 
            +
            			
         | 
| 39 83 | 
             
            			stream.write "Hello World\n"
         | 
| 40 84 | 
             
            			stream.flush
         | 
| 41 85 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: async-io
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.8.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Samuel Williams
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2018-04- | 
| 11 | 
            +
            date: 2018-04-26 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: async
         | 
| @@ -30,14 +30,14 @@ dependencies: | |
| 30 30 | 
             
                requirements:
         | 
| 31 31 | 
             
                - - "~>"
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: '1. | 
| 33 | 
            +
                    version: '1.4'
         | 
| 34 34 | 
             
              type: :development
         | 
| 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: '1. | 
| 40 | 
            +
                    version: '1.4'
         | 
| 41 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 42 | 
             
              name: bundler
         | 
| 43 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         |