async-io 1.29.0 → 1.30.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.
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/trap.rb +4 -3
  4. data/lib/async/io/version.rb +1 -1
  5. metadata +39 -91
  6. data/.editorconfig +0 -6
  7. data/.github/workflows/development.yml +0 -55
  8. data/.gitignore +0 -13
  9. data/.rspec +0 -3
  10. data/.yardopts +0 -2
  11. data/Gemfile +0 -13
  12. data/README.md +0 -171
  13. data/async-io.gemspec +0 -30
  14. data/examples/allocations/byteslice.rb +0 -29
  15. data/examples/allocations/memory.rb +0 -16
  16. data/examples/allocations/read_chunks.rb +0 -18
  17. data/examples/chat/client.rb +0 -58
  18. data/examples/chat/server.rb +0 -83
  19. data/examples/defer/worker.rb +0 -29
  20. data/examples/echo/client.rb +0 -23
  21. data/examples/echo/server.rb +0 -58
  22. data/examples/issues/broken_ssl.rb +0 -15
  23. data/examples/issues/pipes.rb +0 -34
  24. data/examples/millions/client.rb +0 -44
  25. data/examples/millions/server.rb +0 -41
  26. data/examples/udp/client.rb +0 -14
  27. data/examples/udp/server.rb +0 -16
  28. data/gems/nio4r-2.3.gemfile +0 -3
  29. data/spec/addrinfo.rb +0 -16
  30. data/spec/async/io/buffer_spec.rb +0 -48
  31. data/spec/async/io/c10k_spec.rb +0 -138
  32. data/spec/async/io/echo_spec.rb +0 -75
  33. data/spec/async/io/endpoint_spec.rb +0 -105
  34. data/spec/async/io/generic_examples.rb +0 -73
  35. data/spec/async/io/generic_spec.rb +0 -107
  36. data/spec/async/io/notification_spec.rb +0 -46
  37. data/spec/async/io/protocol/line_spec.rb +0 -81
  38. data/spec/async/io/shared_endpoint/server_spec.rb +0 -72
  39. data/spec/async/io/shared_endpoint_spec.rb +0 -65
  40. data/spec/async/io/socket/tcp_spec.rb +0 -101
  41. data/spec/async/io/socket/udp_spec.rb +0 -65
  42. data/spec/async/io/socket_spec.rb +0 -149
  43. data/spec/async/io/ssl_server_spec.rb +0 -133
  44. data/spec/async/io/ssl_socket_spec.rb +0 -96
  45. data/spec/async/io/standard_spec.rb +0 -47
  46. data/spec/async/io/stream_context.rb +0 -30
  47. data/spec/async/io/stream_spec.rb +0 -337
  48. data/spec/async/io/tcp_socket_spec.rb +0 -84
  49. data/spec/async/io/threads_spec.rb +0 -59
  50. data/spec/async/io/trap_spec.rb +0 -52
  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,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
@@ -1,75 +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
-
25
- RSpec.describe "echo client/server" do
26
- include_context Async::RSpec::Reactor
27
-
28
- let(:server_address) {Async::IO::Address.tcp('0.0.0.0', 9002)}
29
-
30
- def echo_server(server_address)
31
- Async do |task|
32
- # This is a synchronous block within the current task:
33
- Async::IO::Socket.accept(server_address) do |client|
34
- # This is an asynchronous block within the current reactor:
35
- data = client.read(512)
36
-
37
- # This produces out-of-order responses.
38
- task.sleep(rand * 0.01)
39
-
40
- client.write(data)
41
- end
42
- end
43
- end
44
-
45
- def echo_client(server_address, data, responses)
46
- Async do |task|
47
- Async::IO::Socket.connect(server_address) do |peer|
48
- result = peer.write(data)
49
- peer.close_write
50
-
51
- message = peer.read(data.bytesize)
52
-
53
- responses << message
54
- end
55
- end
56
- end
57
-
58
- let(:repeats) {10}
59
-
60
- it "should echo several messages" do
61
- server = echo_server(server_address)
62
- responses = []
63
-
64
- tasks = repeats.times.collect do |i|
65
- echo_client(server_address, "Hello World #{i}", responses)
66
- end
67
-
68
- # task.reactor.print_hierarchy
69
-
70
- tasks.each(&:wait)
71
- server.stop
72
-
73
- expect(responses.size).to be repeats
74
- end
75
- end
@@ -1,105 +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/endpoint'
24
-
25
- require 'async/io/tcp_socket'
26
- require 'async/io/socket_endpoint'
27
- require 'async/io/ssl_endpoint'
28
-
29
- RSpec.describe Async::IO::Endpoint do
30
- include_context Async::RSpec::Reactor
31
-
32
- describe Async::IO::Endpoint.ssl('0.0.0.0', 5234, hostname: "lolcathost") do
33
- it "should have hostname" do
34
- expect(subject.hostname).to be == "lolcathost"
35
- end
36
-
37
- it "shouldn't have a timeout duration" do
38
- expect(subject.timeout).to be_nil
39
- end
40
- end
41
-
42
- describe Async::IO::Endpoint.tcp('0.0.0.0', 5234, reuse_port: true, timeout: 10) do
43
- it "should be a tcp binding" do
44
- subject.bind do |server|
45
- expect(server.local_address.socktype).to be == ::Socket::SOCK_STREAM
46
- end
47
- end
48
-
49
- it "should have a timeout duration" do
50
- expect(subject.timeout).to be 10
51
- end
52
-
53
- it "should print nicely" do
54
- expect(subject.to_s).to include('0.0.0.0', '5234')
55
- end
56
-
57
- it "has options" do
58
- expect(subject.options[:reuse_port]).to be true
59
- end
60
-
61
- it "has hostname" do
62
- expect(subject.hostname).to be == '0.0.0.0'
63
- end
64
-
65
- it "has local address" do
66
- address = Async::IO::Address.tcp('127.0.0.1', 8080)
67
- expect(subject.with(local_address: address).local_address).to be == address
68
- end
69
-
70
- let(:message) {"Hello World!"}
71
-
72
- it "can connect to bound server" do
73
- server_task = reactor.async do
74
- subject.accept do |io|
75
- expect(io.timeout).to be == 10
76
- io.write message
77
- io.close
78
- end
79
- end
80
-
81
- io = subject.connect
82
- expect(io.timeout).to be == 10
83
- expect(io.read(message.bytesize)).to be == message
84
- io.close
85
-
86
- server_task.stop
87
- end
88
- end
89
-
90
- describe Async::IO::Endpoint.tcp('0.0.0.0', 0) do
91
- it "should be a tcp binding" do
92
- subject.bind do |server|
93
- expect(server.local_address.ip_port).to be > 10000
94
- end
95
- end
96
- end
97
-
98
- describe Async::IO::SocketEndpoint.new(TCPServer.new('0.0.0.0', 1234)) do
99
- it "should bind to given socket" do
100
- subject.bind do |server|
101
- expect(server).to be == subject.socket
102
- end
103
- end
104
- end
105
- end