async-io 1.29.0 → 1.30.0

Sign up to get free protection for your applications and to get access to all the features.
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