async-await 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 982110e1afe4ee24f5931671df9df8036170b4b2b3cb4dcc8bc1e924739c2099
4
- data.tar.gz: d6fd5e852edadf8a2b48090847225ac1df2e372ac37c4fbd126b0dc6970c9637
3
+ metadata.gz: 60b68ca501e24b540ab2868d13331718fedce992928ed6ac3e29ae00caa3ef82
4
+ data.tar.gz: 1e56657845f348d4c5657974a35c417176ddf5e63c595a8084e3fe0f7ff2f291
5
5
  SHA512:
6
- metadata.gz: f05e45a97e6cac339a4f6a1bba1e59d2a78ebe7f8f0741adb95525f9c376b5c358685d7a3b68ef3df98ece474f269903fd205bc74d7002b0c6a77183f0cd943f
7
- data.tar.gz: 0c43a301fb491a90611d14717885913c6934c943f2616d744e23e360bc86b43cb33cd6752dddd7edbcbff370220bbd916f23fa994d302d938f9b9f7719921e89
6
+ metadata.gz: 502521efb2e174c861cc324fbdb8c141e37c16ddd2c91664fd54e3b90d9e4a3bc103ef12a01b41deb4fed4d3997a2bce4820b14d9d10f3ea38f50b4b0b505810
7
+ data.tar.gz: 231a2b125fa5f63260ea6cfb83f06c7beab995e35c868b7d87932b4105d43b31491287081d431ecdee9ef9a906d4b051dcf3c79a49d90826511fef2d22561b15
@@ -22,17 +22,17 @@ module Async
22
22
  module Await
23
23
  module Enumerable
24
24
  def async_map(parent: Task.current, &block)
25
- self.map do |*args|
25
+ self.map do |*arguments|
26
26
  parent.async do
27
- yield *args
27
+ yield(*arguments)
28
28
  end
29
29
  end.map(&:wait)
30
30
  end
31
31
 
32
32
  def async_each(parent: Task.current, &block)
33
- self.each do |*args|
33
+ self.each do |*arguments|
34
34
  parent.async do
35
- yield *args
35
+ yield(*arguments)
36
36
  end
37
37
  end
38
38
 
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module Await
23
- VERSION = "0.5.0"
23
+ VERSION = "0.6.0"
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,43 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-await
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-09 00:00:00.000000000 Z
11
+ date: 2021-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.3'
27
- - !ruby/object:Gem::Dependency
28
- name: async-rspec
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.1'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
24
+ - - ">="
39
25
  - !ruby/object:Gem::Version
40
- version: '1.1'
26
+ version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: ruby2_keywords
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,21 +39,21 @@ dependencies:
53
39
  - !ruby/object:Gem::Version
54
40
  version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
- name: covered
42
+ name: async-rspec
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
- - - ">="
45
+ - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '0'
47
+ version: '1.1'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
- - - ">="
52
+ - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '0'
54
+ version: '1.1'
69
55
  - !ruby/object:Gem::Dependency
70
- name: bundler
56
+ name: covered
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - ">="
@@ -80,20 +66,6 @@ dependencies:
80
66
  - - ">="
81
67
  - !ruby/object:Gem::Version
82
68
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '10.0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '10.0'
97
69
  - !ruby/object:Gem::Dependency
98
70
  name: rspec
99
71
  requirement: !ruby/object:Gem::Requirement
@@ -108,36 +80,21 @@ dependencies:
108
80
  - - "~>"
109
81
  - !ruby/object:Gem::Version
110
82
  version: '3.0'
111
- description:
83
+ description:
112
84
  email:
113
- - samuel.williams@oriontransfer.co.nz
114
85
  executables: []
115
86
  extensions: []
116
87
  extra_rdoc_files: []
117
88
  files:
118
- - ".editorconfig"
119
- - ".gitignore"
120
- - ".rspec"
121
- - ".travis.yml"
122
- - Gemfile
123
- - README.md
124
- - Rakefile
125
- - async-await.gemspec
126
- - examples/chickens.rb
127
- - examples/echo.rb
128
- - examples/port_scanner/README.md
129
- - examples/port_scanner/port_scanner.go
130
- - examples/port_scanner/port_scanner.py
131
- - examples/port_scanner/port_scanner.rb
132
- - examples/sleep_sort.rb
133
89
  - lib/async/await.rb
134
90
  - lib/async/await/enumerable.rb
135
91
  - lib/async/await/methods.rb
136
92
  - lib/async/await/version.rb
137
93
  homepage: https://github.com/socketry/async-await
138
- licenses: []
94
+ licenses:
95
+ - MIT
139
96
  metadata: {}
140
- post_install_message:
97
+ post_install_message:
141
98
  rdoc_options: []
142
99
  require_paths:
143
100
  - lib
@@ -152,8 +109,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
109
  - !ruby/object:Gem::Version
153
110
  version: '0'
154
111
  requirements: []
155
- rubygems_version: 3.1.2
156
- signing_key:
112
+ rubygems_version: 3.3.0
113
+ signing_key:
157
114
  specification_version: 4
158
115
  summary: Implements the async/await pattern on top of async :)
159
116
  test_files: []
data/.editorconfig DELETED
@@ -1,6 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_style = tab
5
- indent_size = 2
6
-
data/.gitignore DELETED
@@ -1,12 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
-
11
- # rspec failure tracking
12
- .rspec_status
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --warnings
3
- --require spec_helper
data/.travis.yml DELETED
@@ -1,19 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
-
4
- matrix:
5
- include:
6
- - rvm: 2.3
7
- - rvm: 2.4
8
- - rvm: 2.5
9
- - rvm: 2.6
10
- - rvm: 2.7
11
- - rvm: 2.6
12
- env: COVERAGE=BriefSummary,Coveralls
13
- - rvm: ruby-head
14
- - rvm: jruby-head
15
- - rvm: truffleruby
16
- allow_failures:
17
- - rvm: ruby-head
18
- - rvm: jruby-head
19
- - rvm: truffleruby
data/Gemfile DELETED
@@ -1,13 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :development do
6
- gem 'pry'
7
- gem 'async-io', '~> 1.4'
8
- end
9
-
10
- group :test do
11
- gem 'benchmark-ips'
12
- gem 'ruby-prof', platforms: :mri
13
- end
data/README.md DELETED
@@ -1,95 +0,0 @@
1
- # Async::Await
2
-
3
- Implements the async/await pattern for Ruby using [async].
4
-
5
- [![Build Status](https://secure.travis-ci.org/socketry/async-await.svg)](http://travis-ci.org/socketry/async-await)
6
- [![Code Climate](https://codeclimate.com/github/socketry/async-await.svg)](https://codeclimate.com/github/socketry/async-await)
7
- [![Coverage Status](https://coveralls.io/repos/socketry/async-await/badge.svg)](https://coveralls.io/r/socketry/async-await)
8
-
9
- [async]: https://github.com/socketry/async
10
-
11
- ## Installation
12
-
13
- Add this line to your application's Gemfile:
14
-
15
- ```ruby
16
- gem 'async-await'
17
- ```
18
-
19
- And then execute:
20
-
21
- $ bundle
22
-
23
- Or install it yourself as:
24
-
25
- $ gem install async-await
26
-
27
- ## Usage
28
-
29
- In any asynchronous context (e.g. a reactor), simply use the `await` function like so:
30
-
31
- ```ruby
32
- require 'async/await'
33
-
34
- class Coop
35
- include Async::Await
36
-
37
- async def count_chickens(area_name)
38
- 3.times do |i|
39
- sleep rand
40
-
41
- puts "Found a chicken in the #{area_name}!"
42
- end
43
- end
44
-
45
- async def count_all_chickens
46
- # These methods all run at the same time.
47
- count_chickens("garden")
48
- count_chickens("house")
49
-
50
- # We wait for the result
51
- count_chickens("tree").wait
52
- end
53
- end
54
-
55
- coop = Coop.new
56
- coop.count_all_chickens
57
- ```
58
-
59
- ## Contributing
60
-
61
- 1. Fork it
62
- 2. Create your feature branch (`git checkout -b my-new-feature`)
63
- 3. Commit your changes (`git commit -am 'Add some feature'`)
64
- 4. Push to the branch (`git push origin my-new-feature`)
65
- 5. Create new Pull Request
66
-
67
- ## See Also
68
-
69
- - [async-io](https://github.com/socketry/async-io) — Asynchronous networking and sockets.
70
- - [async-dns](https://github.com/socketry/async-dns) — Asynchronous DNS resolver and server.
71
- - [async-rspec](https://github.com/socketry/async-rspec) — Shared contexts for running async specs.
72
-
73
- ## License
74
-
75
- Released under the MIT license.
76
-
77
- Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
78
-
79
- Permission is hereby granted, free of charge, to any person obtaining a copy
80
- of this software and associated documentation files (the "Software"), to deal
81
- in the Software without restriction, including without limitation the rights
82
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
83
- copies of the Software, and to permit persons to whom the Software is
84
- furnished to do so, subject to the following conditions:
85
-
86
- The above copyright notice and this permission notice shall be included in
87
- all copies or substantial portions of the Software.
88
-
89
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
91
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
92
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
94
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
95
- THE SOFTWARE.
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
data/async-await.gemspec DELETED
@@ -1,28 +0,0 @@
1
- # coding: utf-8
2
- require_relative "lib/async/await/version"
3
-
4
- Gem::Specification.new do |spec|
5
- spec.name = "async-await"
6
- spec.version = Async::Await::VERSION
7
- spec.authors = ["Samuel Williams"]
8
- spec.email = ["samuel.williams@oriontransfer.co.nz"]
9
-
10
- spec.summary = "Implements the async/await pattern on top of async :)"
11
- spec.homepage = "https://github.com/socketry/async-await"
12
-
13
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
14
- f.match(%r{^(test|spec|features)/})
15
- end
16
-
17
- spec.require_paths = ["lib"]
18
-
19
- spec.add_dependency "async", "~> 1.3"
20
- spec.add_development_dependency "async-rspec", "~> 1.1"
21
-
22
- spec.add_dependency "ruby2_keywords"
23
-
24
- spec.add_development_dependency "covered"
25
- spec.add_development_dependency "bundler"
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- spec.add_development_dependency "rspec", "~> 3.0"
28
- end
data/examples/chickens.rb DELETED
@@ -1,37 +0,0 @@
1
-
2
- require_relative '../lib/async/await'
3
-
4
- class Coop
5
- include Async::Await
6
-
7
- async def count_chickens(area_name)
8
- 3.times do |i|
9
- sleep rand
10
-
11
- puts "Found a chicken in the #{area_name}!"
12
- end
13
- end
14
-
15
- async def find_chicken(areas)
16
- puts "Searching for chicken..."
17
-
18
- sleep rand * 5
19
-
20
- return areas.sample
21
- end
22
-
23
- async def count_all_chickens
24
- # These methods all run at the same time.
25
- count_chickens("garden")
26
- count_chickens("house")
27
- count_chickens("tree")
28
-
29
- # Wait for all previous async work to complete...
30
- barrier!
31
-
32
- puts "There was a chicken in the #{find_chicken(["garden", "house", "tree"]).wait}"
33
- end
34
- end
35
-
36
- coop = Coop.new
37
- coop.count_all_chickens
data/examples/echo.rb DELETED
@@ -1,55 +0,0 @@
1
-
2
- require_relative '../lib/async/await'
3
-
4
- require 'async/io'
5
- require 'async/io/tcp_socket'
6
-
7
- require 'pry'
8
-
9
- class Echo
10
- include Async::Await
11
- include Async::IO
12
-
13
- async def handle(peer, address)
14
- data = peer.gets
15
- peer.puts("#{data} #{Time.now}")
16
- ensure
17
- peer.close
18
- end
19
-
20
- async def server
21
- puts "Binding server..."
22
- server = TCPServer.new("127.0.0.1", 9009)
23
-
24
- handle(*server.accept)
25
- ensure
26
- server.close rescue nil
27
- end
28
-
29
- async def client
30
- puts "Client connecting..."
31
- client = TCPSocket.new("127.0.0.1", 9009)
32
-
33
- client.puts("Hello World!")
34
- response = client.gets
35
-
36
- puts "Server said: #{response}"
37
- ensure
38
- client.close rescue nil
39
- end
40
-
41
- async def run
42
- puts "Creating server..."
43
- server
44
-
45
- puts "Creating client..."
46
- client
47
-
48
- puts "Run returning..."
49
- end
50
- end
51
-
52
- puts "Starting echo..."
53
- echo = Echo.new
54
- echo.run
55
- puts "Echo finished :)"
@@ -1,90 +0,0 @@
1
- # Port Scanner
2
-
3
- A simple `connect`-based port scanner. It scans locahost for all open ports.
4
-
5
- ## Usage
6
-
7
- ### Go
8
-
9
- Go is pretty awesome, because when the operation would not block, it runs sequentially in the same thread. Go spins up threads and delegates work across available CPU cores.
10
-
11
- $ go get golang.org/x/sync/semaphore
12
- $ go build port_scanner.go
13
- $ time ./port_scanner
14
- 22 open
15
- 139 open
16
- 445 open
17
- 3306 open
18
- 5355 open
19
- 5432 open
20
- 6379 open
21
- 9293 open
22
- 9292 open
23
- 9516 open
24
- 9515 open
25
- 12046 open
26
- 12813 open
27
- ./port_scanner 1.70s user 1.18s system 503% cpu 0.572 total
28
-
29
- ### Python
30
-
31
- Python was the slowest. This is possibly due to the implementation of semaphore. It creates all 65,535 tasks, and then most of them block on the semaphore.
32
-
33
- $ ./port_scanner.py
34
- 5355 open
35
- 5432 open
36
- 3306 open
37
- 39610 open
38
- 58260 open
39
- 12813 open
40
- 139 open
41
- 445 open
42
- 12046 open
43
- 22 open
44
- 9292 open
45
- 9293 open
46
- 9515 open
47
- 9516 open
48
- 6379 open
49
- ./port_scanner.py 11.41s user 0.88s system 98% cpu 12.485 total
50
-
51
- ### Ruby
52
-
53
- Ruby performance isn't that bad. It's only about half as fast as Go, considering that Go runs across all cores, while the Ruby implementation is limited to one core.
54
-
55
- $ ./port_scanner.rb
56
- 22 open
57
- 139 open
58
- 445 open
59
- 3306 open
60
- 5432 open
61
- 5355 open
62
- 6379 open
63
- 9516 open
64
- 9515 open
65
- 9293 open
66
- 9292 open
67
- 12046 open
68
- 12813 open
69
- ./port_scanner.rb 5.99s user 1.18s system 95% cpu 7.543 total
70
-
71
- ## Notes
72
-
73
- ### Why do I sometimes see high ports?
74
-
75
- Believe it or not, you can connect to your own sockets.
76
-
77
- ```ruby
78
- require 'socket'
79
- a = Addrinfo.tcp("127.0.0.1", 50000)
80
- s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
81
- s.bind(a)
82
- s.connect(a)
83
-
84
- s.write("Hello World")
85
- => 11
86
- [8] pry(main)> s.read(11)
87
- => "Hello World"
88
- ```
89
-
90
- What's happening is that your socket is implicitly binding to a high port, and at the same time it's trying to connect to it.
@@ -1,107 +0,0 @@
1
- package main
2
-
3
- import (
4
- "context"
5
- "fmt"
6
- "golang.org/x/sync/semaphore"
7
- "net"
8
- "syscall"
9
- "strings"
10
- "sync"
11
- "time"
12
- )
13
-
14
- // The star of the show, of modest means,
15
- // used to manage the port scan for a single host.
16
- type PortScanner struct {
17
- ip string
18
- lock *semaphore.Weighted
19
- }
20
-
21
- // Provides a simple wrapper to initializing a PortScanner.
22
- func NewPortScanner(ip string, limit uint64) *PortScanner {
23
- return &PortScanner{
24
- ip: ip,
25
- lock: semaphore.NewWeighted(int64(limit)),
26
- }
27
- }
28
-
29
- // Compute the maximum number of files we can open.
30
- func FileLimit(max uint64) uint64 {
31
- var rlimit syscall.Rlimit
32
- err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
33
- if err != nil {
34
- panic(err)
35
- }
36
-
37
- if (max < rlimit.Cur) {
38
- return max
39
- }
40
-
41
- return rlimit.Cur
42
- }
43
-
44
- // As the name might suggest, this function checks if a given port
45
- // is open to TCP communication. Used in conjunction with the Start function
46
- // to sweep over a range of ports concurrently.
47
- func checkPortOpen(ip string, port int, timeout time.Duration) {
48
- conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), timeout)
49
-
50
- if err != nil {
51
- if strings.Contains(err.Error(), "timeout") {
52
- fmt.Println(port, "timeout", err.Error())
53
- } else if strings.Contains(err.Error(), "deadline exceeded") {
54
- fmt.Println(port, "timeout", err.Error())
55
- } else if strings.Contains(err.Error(), "refused") {
56
- // fmt.Println(port, "closed", err.Error())
57
- } else {
58
- panic(err)
59
- }
60
- return
61
- }
62
-
63
- fmt.Println(port, "open")
64
- conn.Close()
65
- }
66
-
67
- // This function is the bread and butter of this script. It manages the
68
- // port scanning for a given range of ports with the given timeout value
69
- // to deal with filtered ports by a firewall typically.
70
- func (ps *PortScanner) Start(start, stop int, timeout time.Duration) {
71
- wg := sync.WaitGroup{}
72
- defer wg.Wait()
73
-
74
- for port := start; port <= stop; port++ {
75
-
76
- ctx := context.TODO()
77
-
78
- for {
79
- err := ps.lock.Acquire(ctx, 1)
80
- if err == nil {
81
- break
82
- }
83
- }
84
-
85
- wg.Add(1)
86
-
87
- go func(ip string, port int) {
88
- defer ps.lock.Release(1)
89
- defer wg.Done()
90
-
91
- checkPortOpen(ps.ip, port, timeout)
92
- }(ps.ip, port)
93
-
94
- }
95
- }
96
-
97
- // This function kicks off the whole shindig' and provides a
98
- // basic example of the internal API usage.
99
- func main() {
100
- batch_size := FileLimit(512)
101
-
102
- // Create a new PortScanner for localhost.
103
- ps := NewPortScanner("127.0.0.1", batch_size)
104
-
105
- // Start scanning all the ports on localhost.
106
- ps.Start(1, 65535, 1000*time.Millisecond)
107
- }
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- import os, resource
4
- import asyncio
5
-
6
- class PortScanner:
7
- def __init__(self, host="0.0.0.0", ports=range(1, 1024+1), batch_size=1024):
8
- self.host = host
9
- self.ports = ports
10
- self.semaphore = asyncio.Semaphore(value=batch_size)
11
- self.loop = asyncio.get_event_loop()
12
-
13
- async def scan_port(self, port, timeout):
14
- async with self.semaphore:
15
- try:
16
- future = asyncio.open_connection(self.host, port, loop=self.loop)
17
- reader, writer = await asyncio.wait_for(future, timeout=timeout)
18
- print("{} open".format(port))
19
- writer.close()
20
- except ConnectionRefusedError:
21
- pass
22
- # print("{} closed".format(port))
23
- except asyncio.TimeoutError:
24
- print("{} timeout".format(port))
25
-
26
- def start(self, timeout=1.0):
27
- self.loop.run_until_complete(asyncio.gather(
28
- *[self.scan_port(port, timeout) for port in self.ports]
29
- ))
30
-
31
- limits = resource.getrlimit(resource.RLIMIT_NOFILE)
32
- batch_size = min(512, limits[0])
33
-
34
- scanner = PortScanner(host="127.0.0.1", ports=range(1, 65535+1), batch_size=batch_size)
35
-
36
- scanner.start()
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async/io'
4
- require 'async/semaphore'
5
- require_relative '../../lib/async/await'
6
-
7
- class PortScanner
8
- include Async::Await
9
- include Async::IO
10
-
11
- def initialize(host: '0.0.0.0', ports:, batch_size: 1024)
12
- @host = host
13
- @ports = ports
14
- @semaphore = Async::Semaphore.new(batch_size)
15
- end
16
-
17
- def scan_port(port, timeout)
18
- with_timeout(timeout) do
19
- address = Async::IO::Address.tcp(@host, port)
20
- peer = Socket.connect(address)
21
- puts "#{port} open"
22
- peer.close
23
- end
24
- rescue Errno::ECONNREFUSED
25
- # puts "#{port} closed"
26
- rescue Async::TimeoutError
27
- puts "#{port} timeout"
28
- end
29
-
30
- async def start(timeout = 1.0)
31
- @ports.map do |port|
32
- @semaphore.async do
33
- scan_port(port, timeout)
34
- end
35
- end.collect(&:result)
36
- end
37
- end
38
-
39
- limits = Process.getrlimit(Process::RLIMIT_NOFILE)
40
- batch_size = [512, (limits.first * 0.9).ceil].min
41
-
42
- scanner = PortScanner.new(host: "127.0.0.1", ports: Range.new(1, 65535), batch_size: batch_size)
43
-
44
- scanner.start
@@ -1,29 +0,0 @@
1
-
2
- require_relative '../lib/async/await'
3
-
4
- class << self
5
- include Async::Await
6
-
7
- async def sort_one(item, into)
8
- sleep(item.to_f)
9
- into << item
10
-
11
- puts "I've sorted #{item} for you."
12
- end
13
-
14
- async def sort(items)
15
- result = []
16
-
17
- items.each do |item|
18
- sort_one(item, result)
19
- end
20
-
21
- # Wait until all previous async method calls have finished executing.
22
- barrier!
23
-
24
- return result
25
- end
26
- end
27
-
28
- puts "Hold on, sorting..."
29
- puts sort([5, 2, 3, 4, 9, 2, 5, 7, 8]).result.inspect