async-io 1.15.5 → 1.16.0

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
  SHA256:
3
- metadata.gz: 2c298cffb1e3e465beb847df243d77b8ac8404e1cfa2c05b912098b7a9ec6c50
4
- data.tar.gz: 92836def7a7c3bec166d7adaeb48ad4491a9d19377eb0dbcefdec8389d9ed184
3
+ metadata.gz: 11d4123b62b4c9d36348dffe2ce2e450924d491db1b3bd4f4ded739140637300
4
+ data.tar.gz: f707c236c48b1169dc1d26fe9101782c7c11ab26c9c05a6e5cd19bfa784183ca
5
5
  SHA512:
6
- metadata.gz: 63a23d633e7d5edb50942ca68131d1066e0c9f51e36c2cd5acca185f1bf12135d7a1491cbcaa1c656249dbda488ac75ce382e878a501383bfefcb70c24bdeea6
7
- data.tar.gz: 6d90e23f6c212c48d66d6af5d661a22215bd563a280c42923e8fa1221521db89b494810ba0153065a0e11eb1aea2e561a3640f075ec012f3d6a8294ae8f723f3
6
+ metadata.gz: c8f33cc994bf02d7ece78d249bf85418c9f5de2c079f49053cb4f7534e5d04b12f40a468fc7ef095c0cbacd04c1fe37291726b20c07f2f34c52453ac9b8ce4cb
7
+ data.tar.gz: 65424003ca8e5904e4984af6bf558f8e7378e873f6f1ec018aea0669187786ef3d348c4c546a5ecb8e80edc526eb41eb5ac09242f714263fec1badacad3d9cf9
@@ -14,7 +14,6 @@ Gem::Specification.new do |spec|
14
14
  spec.executables = spec.files.grep(%r{^bin/}).map{|f| File.basename(f)}
15
15
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
16
  spec.require_paths = ["lib"]
17
- spec.has_rdoc = "yard"
18
17
 
19
18
  spec.add_dependency "async", "~> 1.3"
20
19
  spec.add_development_dependency "async-rspec", "~> 1.10"
@@ -123,7 +123,7 @@ module Async
123
123
  # @param local_address [Addrinfo] The local address to bind to before connecting.
124
124
  # @option protcol [Integer] The socket protocol to use.
125
125
  def self.connect(remote_address, local_address = nil, reuse_port: false, task: Task.current, **options)
126
- # Async.logger.debug(self) {"Connecting to #{remote_address.inspect}"}
126
+ Async.logger.debug(self) {"Connecting to #{remote_address.inspect}"}
127
127
 
128
128
  task.annotate "connecting to #{remote_address.inspect}"
129
129
 
@@ -140,7 +140,7 @@ module Async
140
140
  begin
141
141
  wrapper.connect(remote_address.to_sockaddr)
142
142
  task.annotate "connected to #{remote_address.inspect}"
143
- rescue
143
+ rescue Exception
144
144
  wrapper.close
145
145
  raise
146
146
  end
@@ -79,10 +79,12 @@ module Async
79
79
  return consume_read_buffer(size)
80
80
  end
81
81
 
82
+ alias readpartial read_partial
83
+
82
84
  # Efficiently read data from the stream until encountering pattern.
83
85
  # @param pattern [String] The pattern to match.
84
86
  # @return [String] The contents of the stream up until the pattern, which is consumed but not returned.
85
- def read_until(pattern, offset = 0)
87
+ def read_until(pattern, offset = 0, chomp: true)
86
88
  until index = @read_buffer.index(pattern, offset)
87
89
  offset = @read_buffer.size
88
90
 
@@ -90,7 +92,7 @@ module Async
90
92
  end
91
93
 
92
94
  @read_buffer.freeze
93
- matched = @read_buffer.byteslice(0, index)
95
+ matched = @read_buffer.byteslice(0, index+(chomp ? 0 : pattern.bytesize))
94
96
  @read_buffer = @read_buffer.byteslice(index+pattern.bytesize, @read_buffer.bytesize)
95
97
 
96
98
  return matched
@@ -120,14 +122,14 @@ module Async
120
122
 
121
123
  return string.bytesize
122
124
  end
123
-
125
+
124
126
  # Writes `string` to the stream and returns self.
125
127
  def <<(string)
126
128
  write(string)
127
129
 
128
130
  return self
129
131
  end
130
-
132
+
131
133
  # Flushes buffered data to the stream.
132
134
  def flush
133
135
  unless @write_buffer.empty?
@@ -135,13 +137,11 @@ module Async
135
137
  @write_buffer.clear
136
138
  end
137
139
  end
138
-
139
- def gets(separator = $/)
140
- flush
141
-
142
- read_until(separator)
140
+
141
+ def gets(separator = $/, **options)
142
+ read_until(separator, **options)
143
143
  end
144
-
144
+
145
145
  def puts(*args, separator: $/)
146
146
  args.each do |arg|
147
147
  @write_buffer << arg << separator
@@ -171,7 +171,7 @@ module Async
171
171
  @io.close
172
172
  end
173
173
  end
174
-
174
+
175
175
  # Returns true if the stream is at file which means there is no more data to be read.
176
176
  def eof?
177
177
  fill_read_buffer if !@eof && @read_buffer.empty?
@@ -203,7 +203,7 @@ module Async
203
203
  return false
204
204
  end
205
205
  end
206
-
206
+
207
207
  # Consumes at most `size` bytes from the buffer.
208
208
  # @param size [Integer|nil] The amount of data to consume. If nil, consume entire buffer.
209
209
  def consume_read_buffer(size = nil)
@@ -28,6 +28,32 @@ module Async
28
28
  class TCPSocket < IPSocket
29
29
  wraps ::TCPSocket
30
30
 
31
+ class StreamWrapper
32
+ def initialize(io)
33
+ @io = io
34
+ end
35
+
36
+ def sync= value
37
+ @io.sync = value
38
+ end
39
+
40
+ def close
41
+ @io.close
42
+ end
43
+
44
+ def read(*args)
45
+ @io.sysread(*args)
46
+ end
47
+
48
+ def write(*args)
49
+ @io.syswrite(*args)
50
+ end
51
+
52
+ def flush
53
+ @io.flush
54
+ end
55
+ end
56
+
31
57
  def initialize(remote_host, remote_port = nil, local_host = nil, local_port = nil)
32
58
  if remote_host.is_a? ::TCPSocket
33
59
  super(remote_host)
@@ -38,6 +64,7 @@ module Async
38
64
  # We do this unusual dance to avoid leaking an "open" socket instance.
39
65
  socket = Socket.connect(remote_address, local_address)
40
66
  fd = socket.fcntl(Fcntl::F_DUPFD)
67
+ Async.logger.debug(self) {"Connected to #{remote_address.inspect}: #{fd}"}
41
68
  socket.close
42
69
 
43
70
  super(::TCPSocket.for_fd(fd))
@@ -46,7 +73,7 @@ module Async
46
73
  # super(::TCPSocket.new(remote_host, remote_port, local_host, local_port))
47
74
  end
48
75
 
49
- @buffer = Stream.new(self)
76
+ @buffer = Stream.new(StreamWrapper.new(self))
50
77
  end
51
78
 
52
79
  class << self
@@ -58,6 +85,16 @@ module Async
58
85
  attr :buffer
59
86
 
60
87
  def_delegators :@buffer, :gets, :puts, :flush
88
+
89
+ def write(*)
90
+ @buffer.flush
91
+
92
+ super
93
+ end
94
+
95
+ def read(size)
96
+ @buffer.read_partial(size)
97
+ end
61
98
  end
62
99
 
63
100
  # Asynchronous TCP server wrappper.
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module IO
23
- VERSION = "1.15.5"
23
+ VERSION = "1.16.0"
24
24
  end
25
25
  end
@@ -39,6 +39,16 @@ RSpec.describe Async::IO::Socket do
39
39
  Async::IO::Socket.connect(address)
40
40
  end.to raise_error(Errno::ECONNREFUSED)
41
41
  end
42
+
43
+ it "should close the socket when interrupted by a timeout" do
44
+ wrapper = double()
45
+ expect(Async::IO::Socket).to receive(:build).and_return(wrapper)
46
+ expect(wrapper).to receive(:connect).and_raise Async::TimeoutError
47
+ expect(wrapper).to receive(:close)
48
+ expect do
49
+ Async::IO::Socket.connect(address)
50
+ end.to raise_error(Async::TimeoutError)
51
+ end
42
52
  end
43
53
 
44
54
  describe '#bind' do
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.15.5
4
+ version: 1.16.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-08-20 00:00:00.000000000 Z
11
+ date: 2018-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -168,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
168
  version: '0'
169
169
  requirements: []
170
170
  rubyforge_project:
171
- rubygems_version: 2.7.6
171
+ rubygems_version: 2.7.7
172
172
  signing_key:
173
173
  specification_version: 4
174
174
  summary: Provides support for asynchonous TCP, UDP, UNIX and SSL sockets.