async-io 1.27.6 → 1.30.1

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/lib/async/io/host_endpoint.rb +1 -1
  3. data/lib/async/io/stream.rb +16 -42
  4. data/{spec/async/io/trap_spec.rb → lib/async/io/threads.rb} +37 -26
  5. data/lib/async/io/trap.rb +8 -3
  6. data/lib/async/io/version.rb +1 -1
  7. metadata +50 -99
  8. data/.editorconfig +0 -6
  9. data/.gitignore +0 -13
  10. data/.rspec +0 -3
  11. data/.travis.yml +0 -25
  12. data/.yardopts +0 -2
  13. data/Gemfile +0 -20
  14. data/README.md +0 -171
  15. data/async-io.gemspec +0 -30
  16. data/examples/allocations/byteslice.rb +0 -29
  17. data/examples/allocations/memory.rb +0 -16
  18. data/examples/allocations/read_chunks.rb +0 -18
  19. data/examples/chat/client.rb +0 -58
  20. data/examples/chat/server.rb +0 -83
  21. data/examples/defer/worker.rb +0 -29
  22. data/examples/echo/client.rb +0 -23
  23. data/examples/echo/server.rb +0 -58
  24. data/examples/issues/broken_ssl.rb +0 -15
  25. data/examples/issues/pipes.rb +0 -34
  26. data/examples/millions/client.rb +0 -44
  27. data/examples/millions/server.rb +0 -41
  28. data/examples/udp/client.rb +0 -14
  29. data/examples/udp/server.rb +0 -16
  30. data/gems/nio4r-2.3.gemfile +0 -3
  31. data/spec/addrinfo.rb +0 -16
  32. data/spec/async/io/buffer_spec.rb +0 -48
  33. data/spec/async/io/c10k_spec.rb +0 -138
  34. data/spec/async/io/echo_spec.rb +0 -75
  35. data/spec/async/io/endpoint_spec.rb +0 -105
  36. data/spec/async/io/generic_examples.rb +0 -73
  37. data/spec/async/io/generic_spec.rb +0 -107
  38. data/spec/async/io/notification_spec.rb +0 -46
  39. data/spec/async/io/protocol/line_spec.rb +0 -81
  40. data/spec/async/io/shared_endpoint/server_spec.rb +0 -72
  41. data/spec/async/io/shared_endpoint_spec.rb +0 -67
  42. data/spec/async/io/socket/tcp_spec.rb +0 -101
  43. data/spec/async/io/socket/udp_spec.rb +0 -65
  44. data/spec/async/io/socket_spec.rb +0 -149
  45. data/spec/async/io/ssl_server_spec.rb +0 -133
  46. data/spec/async/io/ssl_socket_spec.rb +0 -96
  47. data/spec/async/io/standard_spec.rb +0 -47
  48. data/spec/async/io/stream_context.rb +0 -30
  49. data/spec/async/io/stream_spec.rb +0 -337
  50. data/spec/async/io/tcp_socket_spec.rb +0 -84
  51. data/spec/async/io/udp_socket_spec.rb +0 -56
  52. data/spec/async/io/unix_endpoint_spec.rb +0 -106
  53. data/spec/async/io/unix_socket_spec.rb +0 -66
  54. data/spec/async/io/wrap/http_rb_spec.rb +0 -47
  55. data/spec/async/io/wrap/tcp_spec.rb +0 -79
  56. data/spec/spec_helper.rb +0 -15
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async'
4
- require 'async/io/notification'
5
-
6
- def defer(*args, &block)
7
- Async do
8
- notification = Async::IO::Notification.new
9
-
10
- thread = Thread.new(*args) do
11
- yield
12
- ensure
13
- notification.signal
14
- end
15
-
16
- notification.wait
17
- thread.join
18
- end
19
- end
20
-
21
- Async do
22
- 10.times do
23
- defer do
24
- puts "I'm going to sleep"
25
- sleep 1
26
- puts "I'm going to wake up"
27
- end
28
- end
29
- end
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
5
-
6
- require 'async'
7
- require 'async/io/trap'
8
- require 'async/io/host_endpoint'
9
- require 'async/io/stream'
10
-
11
- endpoint = Async::IO::Endpoint.tcp('localhost', 4578)
12
-
13
- Async do |task|
14
- endpoint.connect do |peer|
15
- stream = Async::IO::Stream.new(peer)
16
-
17
- while true
18
- task.sleep 1
19
- stream.puts "Hello World!"
20
- puts stream.gets.inspect
21
- end
22
- end
23
- end
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
5
-
6
- require 'async'
7
- require 'async/io/trap'
8
- require 'async/io/host_endpoint'
9
- require 'async/io/stream'
10
-
11
- endpoint = Async::IO::Endpoint.tcp('localhost', 4578)
12
-
13
- interrupt = Async::IO::Trap.new(:INT)
14
-
15
- Async do |top|
16
- interrupt.install!
17
-
18
- endpoint.bind do |server, task|
19
- Async.logger.info(server) {"Accepting connections on #{server.local_address.inspect}"}
20
-
21
- task.async do |subtask|
22
- interrupt.wait
23
-
24
- Async.logger.info(server) {"Closing server socket..."}
25
- server.close
26
-
27
- interrupt.default!
28
-
29
- Async.logger.info(server) {"Waiting for connections to close..."}
30
- subtask.sleep(4)
31
-
32
- Async.logger.info(server) do |buffer|
33
- buffer.puts "Stopping all tasks..."
34
- task.print_hierarchy(buffer)
35
- buffer.puts "", "Reactor Hierarchy"
36
- task.reactor.print_hierarchy(buffer)
37
- end
38
-
39
- task.stop
40
- end
41
-
42
- server.listen(128)
43
-
44
- server.accept_each do |peer|
45
- stream = Async::IO::Stream.new(peer)
46
-
47
- while chunk = stream.read_partial
48
- Async.logger.debug(self) {chunk.inspect}
49
- stream.write(chunk)
50
- stream.flush
51
-
52
- Async.logger.info(server) do |buffer|
53
- task.reactor.print_hierarchy(buffer)
54
- end
55
- end
56
- end
57
- end
58
- end
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'socket'
5
- require 'openssl'
6
-
7
- server = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
8
- server.bind(Addrinfo.tcp('127.0.0.1', 4433))
9
- server.listen(128)
10
-
11
- ssl_server = OpenSSL::SSL::SSLServer.new(server, OpenSSL::SSL::SSLContext.new)
12
-
13
- puts ssl_server.addr
14
-
15
- # openssl/ssl.rb:234:in `addr': undefined method `addr' for #<Socket:fd 8> (NoMethodError)
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # wat.rb
4
- require 'async'
5
- require_relative '../../lib/async/io'
6
- require 'digest/sha1'
7
- require 'securerandom'
8
-
9
- Async.run do |task|
10
- r, w = IO.pipe.map { |io| Async::IO.try_convert(io) }
11
-
12
- task.async do |subtask|
13
- s = Digest::SHA1.new
14
- l = 0
15
- 100.times do
16
- bytes = SecureRandom.bytes(4000)
17
- s << bytes
18
- w << bytes
19
- l += bytes.bytesize
20
- end
21
- w.close
22
- p [:write, l, s.hexdigest]
23
- end
24
-
25
- task.async do |subtask|
26
- s = Digest::SHA1.new
27
- l = 0
28
- while b = r.read(4096)
29
- s << b
30
- l += b.bytesize
31
- end
32
- p [:read, l, s.hexdigest]
33
- end
34
- end
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- $LOAD_PATH << File.expand_path("../../lib", __dir__)
5
-
6
- require 'async/reactor'
7
- require 'async/io/host_endpoint'
8
-
9
- require 'async/container'
10
- require 'async/container/forked'
11
-
12
- endpoint = Async::IO::Endpoint.parse(ARGV.pop || "tcp://localhost:7234")
13
-
14
- CONNECTIONS = 1_000_000
15
-
16
- CONCURRENCY = Async::Container.hardware_concurrency
17
- TASKS = 16
18
- REPEATS = (CONNECTIONS.to_f / (TASKS * CONCURRENCY)).ceil
19
-
20
- puts "Starting #{CONCURRENCY} processes, running #{TASKS} tasks, making #{REPEATS} connections."
21
- puts "Total number of connections: #{CONCURRENCY * TASKS * REPEATS}!"
22
-
23
- begin
24
- container = Async::Container::Forked.new
25
-
26
- container.run(count: CONCURRENCY) do
27
- Async do |task|
28
- connections = []
29
-
30
- TASKS.times do
31
- task.async do
32
- REPEATS.times do
33
- $stdout.write "."
34
- connections << endpoint.connect
35
- end
36
- end
37
- end
38
- end
39
- end
40
-
41
- container.wait
42
- ensure
43
- container.stop if container
44
- end
@@ -1,41 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- $LOAD_PATH << File.expand_path("../../lib", __dir__)
5
-
6
- require 'set'
7
-
8
- require 'async/reactor'
9
- require 'async/io/host_endpoint'
10
- require 'async/io/protocol/line'
11
-
12
- class Server
13
- def initialize
14
- @connections = []
15
- end
16
-
17
- def run(endpoint)
18
- Async do |task|
19
- task.async do |subtask|
20
- while true
21
- subtask.sleep 10
22
- puts "Connection count: #{@connections.size}"
23
- end
24
- end
25
-
26
-
27
- endpoint.accept do |peer|
28
- stream = Async::IO::Stream.new(peer)
29
-
30
- @connections << stream
31
- end
32
- end
33
- end
34
- end
35
-
36
- Async.logger.level = Logger::INFO
37
- Async.logger.info("Starting server...")
38
- server = Server.new
39
-
40
- endpoint = Async::IO::Endpoint.parse(ARGV.pop || "tcp://localhost:7234")
41
- server.run(endpoint)
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'async'
5
- require 'async/io'
6
-
7
- endpoint = Async::IO::Endpoint.udp("localhost", 5678)
8
-
9
- Async do |task|
10
- endpoint.connect do |socket|
11
- socket.send("Hello World")
12
- pp socket.recv(1024)
13
- end
14
- end
@@ -1,16 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'async'
5
- require 'async/io'
6
-
7
- endpoint = Async::IO::Endpoint.udp("localhost", 5678)
8
-
9
- Async do |task|
10
- endpoint.bind do |socket|
11
- while true
12
- data, address = socket.recvfrom(1024)
13
- socket.send(data.reverse, 0, address)
14
- end
15
- end
16
- end
@@ -1,3 +0,0 @@
1
- eval_gemfile("../Gemfile")
2
-
3
- gem "nio4r", "~> 2.3.0"
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This is useful for specs, but I hesitate to monkey patch a core class in the library itself.
4
- class Addrinfo
5
- def == other
6
- self.to_s == other.to_s
7
- end
8
-
9
- def != other
10
- self.to_s != other.to_s
11
- end
12
-
13
- def <=> other
14
- self.to_s <=> other.to_s
15
- end
16
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require 'async/io/buffer'
24
-
25
- RSpec.describe Async::IO::Buffer do
26
- include_context Async::RSpec::Memory
27
-
28
- let!(:string) {"Hello World!".b}
29
- subject! {described_class.new}
30
-
31
- it "should be binary encoding" do
32
- expect(subject.encoding).to be Encoding::BINARY
33
- end
34
-
35
- it "should not allocate strings when concatenating" do
36
- expect do
37
- subject << string
38
- end.to limit_allocations.of(String, size: 0, count: 0)
39
- end
40
-
41
- it "can append unicode strings to binary buffer" do
42
- 2.times do
43
- subject << "Føøbar"
44
- end
45
-
46
- expect(subject).to eq "FøøbarFøøbar".b
47
- end
48
- end
@@ -1,138 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require 'async/io'
24
- require 'benchmark'
25
- require 'open3'
26
-
27
- # require 'ruby-prof'
28
-
29
- RSpec.describe "c10k echo client/server", if: Process.respond_to?(:fork) do
30
- # macOS has a rediculously hard time to do this.
31
- # sudo sysctl -w net.inet.ip.portrange.first=10000
32
- # sudo sysctl -w net.inet.ip.portrange.hifirst=10000
33
- # Probably due to the use of select.
34
-
35
- let(:repeats) do
36
- if limit = Async::IO.file_descriptor_limit
37
- if limit > 1024*10
38
- 10_000
39
- else
40
- [1, limit - 100].max
41
- end
42
- else
43
- 10_000
44
- end
45
- end
46
-
47
- let(:server_address) {Async::IO::Address.tcp('0.0.0.0', 10101)}
48
-
49
- def echo_server(server_address)
50
- Async do |task|
51
- connections = []
52
-
53
- Async::IO::Socket.bind(server_address) do |server|
54
- server.listen(Socket::SOMAXCONN)
55
-
56
- while connections.size < repeats
57
- peer, address = server.accept
58
- connections << peer
59
- end
60
- end.wait
61
-
62
- puts "Releasing #{connections.size} connections..."
63
-
64
- while connection = connections.pop
65
- connection.write(".")
66
- connection.close
67
- end
68
- end
69
- end
70
-
71
- def echo_client(server_address, data, responses)
72
- Async do |task|
73
- begin
74
- Async::IO::Socket.connect(server_address) do |peer|
75
- responses << peer.read(1)
76
- end
77
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EADDRINUSE
78
- puts "#{data}: #{$!}..."
79
- # If the connection was refused, it means the server probably can't accept connections any faster than it currently is, so we simply retry.
80
- retry
81
- end
82
- end
83
- end
84
-
85
- def fork_server
86
- pid = fork do
87
- # profile = RubyProf::Profile.new(merge_fibers: true)
88
- # profile.start
89
-
90
- echo_server(server_address)
91
- # ensure
92
- # result = profile.stop
93
- # printer = RubyProf::FlatPrinter.new(result)
94
- # printer.print(STDOUT)
95
- end
96
-
97
- yield
98
- ensure
99
- Process.kill(:KILL, pid)
100
- Process.wait(pid)
101
- end
102
-
103
- around(:each) do |example|
104
- duration = Benchmark.realtime do
105
- example.run
106
- end
107
-
108
- example.reporter.message "Handled #{repeats} connections in #{duration.round(2)}s: #{(repeats/duration).round(2)}req/s"
109
- end
110
-
111
- it "should wait until all clients are connected" do
112
- fork_server do
113
- # profile = RubyProf::Profile.new(merge_fibers: true)
114
- # profile.start
115
-
116
- Async do |task|
117
- responses = []
118
-
119
- tasks = repeats.times.collect do |i|
120
- # puts "Starting client #{i} on #{task}..." if (i % 1000) == 0
121
-
122
- echo_client(server_address, "Hello World #{i}", responses)
123
- end
124
-
125
- # task.reactor.print_hierarchy
126
-
127
- tasks.each(&:wait)
128
-
129
- expect(responses.size).to be repeats
130
- end
131
-
132
- # ensure
133
- # result = profile.stop
134
- # printer = RubyProf::FlatPrinter.new(result)
135
- # printer.print(STDOUT)
136
- end
137
- end
138
- end