async-io 1.15.5 → 1.16.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 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.