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,30 +0,0 @@
1
-
2
- require_relative 'lib/async/io/version'
3
-
4
- Gem::Specification.new do |spec|
5
- spec.name = "async-io"
6
- spec.version = Async::IO::VERSION
7
- spec.licenses = ["MIT"]
8
- spec.authors = ["Samuel Williams"]
9
- spec.email = ["samuel.williams@oriontransfer.co.nz"]
10
-
11
- spec.summary = "Provides support for asynchonous TCP, UDP, UNIX and SSL sockets."
12
- spec.homepage = "https://github.com/socketry/async-io"
13
-
14
- spec.files = `git ls-files`.split($/)
15
- spec.executables = spec.files.grep(%r{^bin/}).map{|f| File.basename(f)}
16
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
- spec.require_paths = ["lib"]
18
-
19
- spec.add_dependency "async", "~> 1.14"
20
- spec.add_development_dependency "async-rspec", "~> 1.10"
21
-
22
- spec.required_ruby_version = '~> 2.5'
23
-
24
- spec.add_development_dependency "async-container", "~> 0.15"
25
-
26
- spec.add_development_dependency "covered"
27
- spec.add_development_dependency "bundler"
28
- spec.add_development_dependency "bake-bundler"
29
- spec.add_development_dependency "rspec", "~> 3.0"
30
- end
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require_relative 'memory'
5
-
6
- string = nil
7
-
8
- measure_memory("Initial allocation") do
9
- string = "a" * 5*1024*1024
10
- string.freeze
11
- end # => 5.0 MB
12
-
13
- measure_memory("Byteslice from start to middle") do
14
- # Why does this need to allocate memory? Surely it can share the original allocation?
15
- x = string.byteslice(0, string.bytesize / 2)
16
- end # => 2.5 MB
17
-
18
- measure_memory("Byteslice from middle to end") do
19
- string.byteslice(string.bytesize / 2, string.bytesize)
20
- end # => 0.0 MB
21
-
22
- measure_memory("Slice! from start to middle") do
23
- string.dup.slice!(0, string.bytesize / 2)
24
- end # => 7.5 MB
25
-
26
- measure_memory("Byte slice into two halves") do
27
- head = string.byteslice(0, string.bytesize / 2) # 2.5 MB
28
- remainder = string.byteslice(string.bytesize / 2, string.bytesize) # Shared
29
- end # 2.5 MB
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- def measure_memory(annotation = "Memory allocated")
4
- GC.disable
5
-
6
- start_memory = `ps -p #{Process::pid} -o rss`.split("\n")[1].chomp.to_i
7
-
8
- yield
9
-
10
- ensure
11
- end_memory = `ps -p #{Process::pid} -o rss`.split("\n")[1].chomp.to_i
12
- memory_usage = (end_memory - start_memory).to_f / 1024
13
-
14
- puts "#{memory_usage.round(1)} MB: #{annotation}"
15
- GC.enable
16
- end
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require_relative 'memory'
5
-
6
- require_relative "../../lib/async/io/stream"
7
- require "stringio"
8
-
9
- measure_memory("Stream setup") do
10
- @io = StringIO.new("a" * (50*1024*1024))
11
- @stream = Async::IO::Stream.new(@io)
12
- end # 50.0 MB
13
-
14
- measure_memory("Read all chunks") do
15
- while chunk = @stream.read_partial
16
- chunk.clear
17
- end
18
- end # 0.5 MB
@@ -1,58 +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'
7
- require 'async/notification'
8
- require 'async/io/stream'
9
- require 'async/io/host_endpoint'
10
- require 'async/io/protocol/line'
11
-
12
- class User < Async::IO::Protocol::Line
13
- end
14
-
15
- endpoint = Async::IO::Endpoint.parse(ARGV.pop || "tcp://localhost:7138")
16
-
17
- input = Async::IO::Protocol::Line.new(
18
- Async::IO::Stream.new(
19
- Async::IO::Generic.new($stdin)
20
- )
21
- )
22
-
23
- Async do |task|
24
- socket = endpoint.connect
25
- stream = Async::IO::Stream.new(socket)
26
- user = User.new(stream)
27
-
28
- # This is used to track whether either reading from stdin failed or reading from network failed.
29
- finished = Async::Notification.new
30
-
31
- # Read lines from stdin and write to network.
32
- terminal = task.async do
33
- while line = input.read_line
34
- user.write_lines line
35
- end
36
- rescue EOFError
37
- # It's okay, we are disconnecting, because stdin has closed.
38
- ensure
39
- finished.signal
40
- end
41
-
42
- # Read lines from network and write to stdout.
43
- network = task.async do
44
- while line = user.read_line
45
- puts line
46
- end
47
- ensure
48
- finished.signal
49
- end
50
-
51
- # Wait for any of the above processes to finish:
52
- finished.wait
53
- ensure
54
- # Stop all the nested tasks if we are exiting:
55
- network.stop if network
56
- terminal.stop if terminal
57
- user.close if user
58
- end
@@ -1,83 +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'
9
- require 'async/io/host_endpoint'
10
- require 'async/io/protocol/line'
11
-
12
- class User < Async::IO::Protocol::Line
13
- attr_accessor :name
14
-
15
- def login!
16
- self.write_lines "Tell me your name, traveller:"
17
- self.name = self.read_line
18
- end
19
-
20
- def to_s
21
- @name || "unknown"
22
- end
23
- end
24
-
25
- class Server
26
- def initialize
27
- @users = Set.new
28
- end
29
-
30
- def broadcast(*message)
31
- puts *message
32
-
33
- @users.each do |user|
34
- begin
35
- user.write_lines(*message)
36
- rescue EOFError
37
- # In theory, it's possible this will fail if the remote end has disconnected. Each user has it's own task running `#connected`, and eventually `user.read_line` will fail. When it does, the disconnection logic will be invoked. A better way to do this would be to have a message queue, but for the sake of keeping this example simple, this is by far the better option.
38
- end
39
- end
40
- end
41
-
42
- def connected(user)
43
- user.login!
44
-
45
- broadcast("#{user} has joined")
46
-
47
- user.write_lines("currently connected: #{@users.map(&:to_s).join(', ')}")
48
-
49
- while message = user.read_line
50
- broadcast("#{user.name}: #{message}")
51
- end
52
- rescue EOFError
53
- # It's okay, client has disconnected.
54
- ensure
55
- disconnected(user)
56
- end
57
-
58
- def disconnected(user, reason = "quit")
59
- @users.delete(user)
60
-
61
- broadcast("#{user} has disconnected: #{reason}")
62
- end
63
-
64
- def run(endpoint)
65
- Async do |task|
66
- endpoint.accept do |peer|
67
- stream = Async::IO::Stream.new(peer)
68
- user = User.new(stream)
69
-
70
- @users << user
71
-
72
- connected(user)
73
- end
74
- end
75
- end
76
- end
77
-
78
- Async.logger.level = Logger::INFO
79
- Async.logger.info("Starting server...")
80
- server = Server.new
81
-
82
- endpoint = Async::IO::Endpoint.parse(ARGV.pop || "tcp://localhost:7138")
83
- server.run(endpoint)
@@ -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