polyphony-http 0.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +56 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +21 -0
- data/README.md +47 -0
- data/Rakefile +20 -0
- data/TODO.md +59 -0
- data/bin/poly +11 -0
- data/docs/README.md +38 -0
- data/docs/summary.md +60 -0
- data/examples/cuba.ru +22 -0
- data/examples/happy_eyeballs.rb +37 -0
- data/examples/http2_raw.rb +135 -0
- data/examples/http_client.rb +28 -0
- data/examples/http_get.rb +33 -0
- data/examples/http_parse_experiment.rb +123 -0
- data/examples/http_proxy.rb +83 -0
- data/examples/http_server.js +24 -0
- data/examples/http_server.rb +21 -0
- data/examples/http_server_forked.rb +29 -0
- data/examples/http_server_graceful.rb +27 -0
- data/examples/http_server_simple.rb +11 -0
- data/examples/http_server_throttled.rb +15 -0
- data/examples/http_server_timeout.rb +35 -0
- data/examples/http_ws_server.rb +37 -0
- data/examples/https_raw_client.rb +12 -0
- data/examples/https_server.rb +22 -0
- data/examples/https_wss_server.rb +39 -0
- data/examples/rack_server.rb +12 -0
- data/examples/rack_server_https.rb +19 -0
- data/examples/rack_server_https_forked.rb +27 -0
- data/examples/websocket_secure_server.rb +27 -0
- data/examples/websocket_server.rb +24 -0
- data/examples/ws_page.html +34 -0
- data/examples/wss_page.html +34 -0
- data/lib/polyphony/http.rb +16 -0
- data/lib/polyphony/http/client/agent.rb +131 -0
- data/lib/polyphony/http/client/http1.rb +129 -0
- data/lib/polyphony/http/client/http2.rb +180 -0
- data/lib/polyphony/http/client/response.rb +32 -0
- data/lib/polyphony/http/client/site_connection_manager.rb +109 -0
- data/lib/polyphony/http/server.rb +49 -0
- data/lib/polyphony/http/server/http1.rb +267 -0
- data/lib/polyphony/http/server/http2.rb +78 -0
- data/lib/polyphony/http/server/http2_stream.rb +135 -0
- data/lib/polyphony/http/server/rack.rb +64 -0
- data/lib/polyphony/http/server/request.rb +118 -0
- data/lib/polyphony/http/version.rb +7 -0
- data/lib/polyphony/websocket.rb +59 -0
- data/polyphony-http.gemspec +34 -0
- data/test/coverage.rb +45 -0
- data/test/eg.rb +27 -0
- data/test/helper.rb +35 -0
- data/test/run.rb +5 -0
- data/test/test_http_server.rb +313 -0
- metadata +245 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7ca781bfd155cadb774a4b9578c947aed555ad14af76d282d17be7a8f765faae
|
4
|
+
data.tar.gz: 4317fb42a26ca09d769d78905a89e6c12c0eb0bbc4b18b7b74ff5132a6ac90ac
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 82d55c481540b596463e18fb9eea87f92e52c53e5fab04cbddeca54b4a5462002f4b58657dc0c5afc3cec763999798e564fed3a82fe234dd98fe565318602f57
|
7
|
+
data.tar.gz: fada33a093f8c9967a0927173c57d03d0e82c27b80de6a113e435810f2bd8d05f894dc467c66883f4196ed72702bdef0e207892ac1b233501fc96cfd8ca749d6
|
data/.gitignore
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
# Ignore Byebug command history file.
|
17
|
+
.byebug_history
|
18
|
+
|
19
|
+
## Specific to RubyMotion:
|
20
|
+
.dat*
|
21
|
+
.repl_history
|
22
|
+
build/
|
23
|
+
*.bridgesupport
|
24
|
+
build-iPhoneOS/
|
25
|
+
build-iPhoneSimulator/
|
26
|
+
|
27
|
+
## Specific to RubyMotion (use of CocoaPods):
|
28
|
+
#
|
29
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
30
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
31
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
32
|
+
#
|
33
|
+
# vendor/Pods/
|
34
|
+
|
35
|
+
## Documentation cache and generated files:
|
36
|
+
/.yardoc/
|
37
|
+
/_yardoc/
|
38
|
+
/doc/
|
39
|
+
/rdoc/
|
40
|
+
|
41
|
+
## Environment normalization:
|
42
|
+
/.bundle/
|
43
|
+
/vendor/bundle
|
44
|
+
/lib/bundler/man/
|
45
|
+
|
46
|
+
# for a library or gem, you might want to ignore these files since the code is
|
47
|
+
# intended to run in multiple environments; otherwise, check them in:
|
48
|
+
# Gemfile.lock
|
49
|
+
# .ruby-version
|
50
|
+
# .ruby-gemset
|
51
|
+
|
52
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
53
|
+
.rvmrc
|
54
|
+
|
55
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
56
|
+
# .rubocop-https?--*
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
polyphony-http (0.24)
|
5
|
+
http-2 (~> 0.10.0)
|
6
|
+
http_parser.rb (~> 0.6.0)
|
7
|
+
modulation (~> 1.0)
|
8
|
+
polyphony (~> 0.30)
|
9
|
+
rack (~> 2.0.8)
|
10
|
+
websocket (~> 1.2.8)
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
ansi (1.5.0)
|
16
|
+
builder (3.2.4)
|
17
|
+
docile (1.3.2)
|
18
|
+
http-2 (0.10.1)
|
19
|
+
http_parser.rb (0.6.0)
|
20
|
+
json (2.1.0)
|
21
|
+
localhost (1.1.4)
|
22
|
+
minitest (5.11.3)
|
23
|
+
minitest-reporters (1.4.2)
|
24
|
+
ansi
|
25
|
+
builder
|
26
|
+
minitest (>= 5.0)
|
27
|
+
ruby-progressbar
|
28
|
+
modulation (1.0)
|
29
|
+
polyphony (0.30)
|
30
|
+
modulation (~> 1.0)
|
31
|
+
rack (2.0.9)
|
32
|
+
ruby-progressbar (1.10.1)
|
33
|
+
simplecov (0.17.1)
|
34
|
+
docile (~> 1.1)
|
35
|
+
json (>= 1.8, < 3)
|
36
|
+
simplecov-html (~> 0.10.0)
|
37
|
+
simplecov-html (0.10.2)
|
38
|
+
websocket (1.2.8)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
localhost (~> 1.1.4)
|
45
|
+
minitest (~> 5.11.3)
|
46
|
+
minitest-reporters (~> 1.4.2)
|
47
|
+
polyphony-http!
|
48
|
+
simplecov (~> 0.17.1)
|
49
|
+
|
50
|
+
BUNDLED WITH
|
51
|
+
2.1.3
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 Sharon Rosner
|
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 all
|
13
|
+
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 THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Polyphony - Easy Concurrency for Ruby
|
2
|
+
|
3
|
+
[DOCS](https://dfab.gitbook.io/polyphony) |
|
4
|
+
[EXAMPLES](examples)
|
5
|
+
|
6
|
+
> Polyphony \| pəˈlɪf\(ə\)ni \| _Music_ - the style of simultaneously combining a number of parts, each forming an individual melody and harmonizing with each other.
|
7
|
+
|
8
|
+
## What is Polyphony
|
9
|
+
|
10
|
+
Polyphony is a library for building concurrent applications in Ruby. Polyphony harnesses the power of [Ruby fibers](https://ruby-doc.org/core-2.5.1/Fiber.html) to provide a cooperative, sequential coprocess-based concurrency model. Under the hood, Polyphony uses [libev](https://github.com/enki/libev) as a high-performance event reactor that provides timers, I/O watchers and other asynchronous event primitives.
|
11
|
+
|
12
|
+
Polyphony makes it possible to use normal Ruby built-in classes like `IO`, and `Socket` in a concurrent fashion without having to resort to threads. Polyphony takes care of context-switching automatically whenever a blocking call like `Socket#accept` or `IO#read` is issued.
|
13
|
+
|
14
|
+
## Features
|
15
|
+
|
16
|
+
* **Full-blown, integrated, high-performance HTTP 1 / HTTP 2 / WebSocket server
|
17
|
+
with TLS/SSL termination, automatic ALPN protocol selection, and body
|
18
|
+
streaming**.
|
19
|
+
* Co-operative scheduling of concurrent tasks using Ruby fibers.
|
20
|
+
* High-performance event reactor for handling I/O events and timers.
|
21
|
+
* Natural, sequential programming style that makes it easy to reason about
|
22
|
+
concurrent code.
|
23
|
+
* Abstractions and constructs for controlling the execution of concurrent code:
|
24
|
+
coprocesses, supervisors, cancel scopes, throttling, resource pools etc.
|
25
|
+
* Code can use native networking classes and libraries, growing support for
|
26
|
+
third-party gems such as `pg` and `redis`.
|
27
|
+
* Use stdlib classes such as `TCPServer`, `TCPSocket` and
|
28
|
+
* HTTP 1 / HTTP 2 client agent with persistent connections.
|
29
|
+
* Competitive performance and scalability characteristics, in terms of both
|
30
|
+
throughput and memory consumption.
|
31
|
+
|
32
|
+
## Prior Art
|
33
|
+
|
34
|
+
Polyphony draws inspiration from the following, in no particular order:
|
35
|
+
|
36
|
+
* [nio4r](https://github.com/socketry/nio4r/) and [async](https://github.com/socketry/async)
|
37
|
+
(Polyphony's C-extension code is largely a spinoff of
|
38
|
+
[nio4r's](https://github.com/socketry/nio4r/tree/master/ext))
|
39
|
+
* [EventMachine](https://github.com/eventmachine/eventmachine)
|
40
|
+
* [Trio](https://trio.readthedocs.io/)
|
41
|
+
* [Erlang supervisors](http://erlang.org/doc/man/supervisor.html) (and actually,
|
42
|
+
Erlang in general)
|
43
|
+
|
44
|
+
## Documentation
|
45
|
+
|
46
|
+
The complete documentation for Polyphony could be found on the
|
47
|
+
[Polyphony website](https://dfab.gitbook.io/polyphony).
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/clean"
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
require "rake/extensiontask"
|
9
|
+
Rake::ExtensionTask.new("gyro_ext") do |ext|
|
10
|
+
ext.ext_dir = "ext/gyro"
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => [:compile, :test]
|
14
|
+
task :test do
|
15
|
+
exec 'ruby test/run.rb'
|
16
|
+
end
|
17
|
+
|
18
|
+
task default: %w[compile]
|
19
|
+
|
20
|
+
CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
|
data/TODO.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# HTTP Client Agent
|
2
|
+
|
3
|
+
The concurrency model and the fact that we want to serve the response object on
|
4
|
+
receiving headers and let the user lazily read the response body, means we'll
|
5
|
+
need to change the API to accept a block:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
# current API
|
9
|
+
resp = Agent.get('http://acme.org')
|
10
|
+
puts resp.body
|
11
|
+
|
12
|
+
# proposed API
|
13
|
+
Agent.get('http://acme.org') do |resp|
|
14
|
+
puts resp.body
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
While the block is running, the connection adapter is acquired. Once the block
|
19
|
+
is done running, the request (and response) can be discarded. The problem with
|
20
|
+
that if we spin up a coprocess from that block we risk all kinds of race
|
21
|
+
conditions and weird behaviours.
|
22
|
+
|
23
|
+
A compromise might be to allow the two: doing a `get` without providing a block
|
24
|
+
will return a response object that already has the body (i.e. the entire
|
25
|
+
response has already been received). Doing a `get` with a block will invoke the
|
26
|
+
block once headers are received, letting the user's code stream the body:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
def request(ctx, &block)
|
30
|
+
...
|
31
|
+
connection_manager.acquire do |adapter|
|
32
|
+
response = adapter.request(ctx)
|
33
|
+
if block
|
34
|
+
block.(response)
|
35
|
+
else
|
36
|
+
# wait for body
|
37
|
+
response.body
|
38
|
+
end
|
39
|
+
response
|
40
|
+
end
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
# Roadmap:
|
45
|
+
|
46
|
+
## 0.25 Full Rack adapter implementation
|
47
|
+
|
48
|
+
- Work better mechanism supervising multiple coprocesses (`when_done` feels a
|
49
|
+
bit hacky)
|
50
|
+
- Add supervisor test
|
51
|
+
- Homogenize HTTP 1 and HTTP 2 headers - upcase ? downcase ?
|
52
|
+
- find some demo Rack apps and test with Polyphony
|
53
|
+
|
54
|
+
## 0.26 Working Sinatra application
|
55
|
+
|
56
|
+
- app with database access (postgresql)
|
57
|
+
- benchmarks!
|
58
|
+
|
59
|
+
## 0.27 Testing & docs
|
data/bin/poly
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative('../lib/polyphony/http')
|
4
|
+
|
5
|
+
app_path = ARGV.first || './config.ru'
|
6
|
+
app = Polyphony::HTTP::Rack.load(app_path)
|
7
|
+
opts = { reuse_addr: true, dont_linger: true }
|
8
|
+
|
9
|
+
puts "listening on port 1234"
|
10
|
+
puts "pid: #{Process.pid}"
|
11
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts, &app)
|
data/docs/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Polyphony - Easy Concurrency for Ruby
|
2
|
+
|
3
|
+
> Polyphony \| pəˈlɪf\(ə\)ni \|
|
4
|
+
> 1. _Music_ the style of simultaneously combining a number of parts, each forming an individual melody and harmonizing with each other.
|
5
|
+
> 2. _Programming_ a Ruby gem for concurrent programming focusing on performance and developer happiness.
|
6
|
+
|
7
|
+
Polyphony is a library for building concurrent applications in Ruby. Polyphony harnesses the power of [Ruby fibers](https://ruby-doc.org/core-2.5.1/Fiber.html) to provide a cooperative, sequential coprocess-based concurrency model. Under the hood, Polyphony uses [libev](https://github.com/enki/libev) as a high-performance event reactor that provides timers, I/O watchers and other asynchronous event primitives.
|
8
|
+
|
9
|
+
Polyphony makes it possible to use normal Ruby built-in classes like `IO`, and `Socket` in a concurrent fashion without having to resort to threads. Polyphony takes care of context-switching automatically whenever a blocking call like `Socket#accept` or `IO#read` is issued.
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
* **Full-blown, integrated, high-performance HTTP 1 / HTTP 2 / WebSocket server with TLS/SSL termination, automatic ALPN protocol selection, and body streaming**.
|
14
|
+
* Co-operative scheduling of concurrent tasks using Ruby fibers.
|
15
|
+
* High-performance event reactor for handling I/O events and timers.
|
16
|
+
* Natural, sequential programming style that makes it easy to reason about concurrent code.
|
17
|
+
* Abstractions and constructs for controlling the execution of concurrent code: coprocesses, supervisors, cancel scopes, throttling, resource pools etc.
|
18
|
+
* Code can use native networking classes and libraries, growing support for third-party gems such as `pg` and `redis`.
|
19
|
+
* Use stdlib classes such as `TCPServer` and `TCPSocket` and `Net::HTTP`.
|
20
|
+
* HTTP 1 / HTTP 2 client agent with persistent connections.
|
21
|
+
* Competitive performance and scalability characteristics, in terms of both throughput and memory consumption.
|
22
|
+
|
23
|
+
## Prior Art
|
24
|
+
|
25
|
+
Polyphony draws inspiration from the following, in no particular order:
|
26
|
+
|
27
|
+
* [nio4r](https://github.com/socketry/nio4r/) and [async](https://github.com/socketry/async) (Polyphony's C-extension code is largely a spinoff of [nio4r's](https://github.com/socketry/nio4r/tree/master/ext))
|
28
|
+
* [EventMachine](https://github.com/eventmachine/eventmachine)
|
29
|
+
* [Trio](https://trio.readthedocs.io/)
|
30
|
+
* [Erlang supervisors](http://erlang.org/doc/man/supervisor.html) (and actually, Erlang in general)
|
31
|
+
|
32
|
+
## Going further
|
33
|
+
|
34
|
+
To learn more about using Polyphony to build concurrent applications, read the technical overview below, or look at the [included examples](https://github.com/digital-fabric/polyphony/tree/9e0f3b09213156bdf376ef33684ef267517f06e8/examples/README.md). A thorough reference is forthcoming.
|
35
|
+
|
36
|
+
## Contributing to Polyphony
|
37
|
+
|
38
|
+
Issues and pull requests will be gladly accepted. Please use the git repository at https://github.com/digital-fabric/polyphony as your primary point of departure for contributing.
|
data/docs/summary.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Table of contents
|
2
|
+
|
3
|
+
* [Polyphony - Easy Concurrency for Ruby](../README.md)
|
4
|
+
|
5
|
+
## Getting Started
|
6
|
+
|
7
|
+
* [Installing](getting-started/installing.md)
|
8
|
+
* [Tutorial](getting-started/tutorial.md)
|
9
|
+
|
10
|
+
## Technical overview
|
11
|
+
|
12
|
+
* [Design Principles](technical-overview/design-principles.md)
|
13
|
+
* [Concurrency the Easy Way](technical-overview/concurrency.md)
|
14
|
+
* [How Fibers are Scheduled](technical-overview/fiber-scheduling.md)
|
15
|
+
* [Exception Handling](technical-overview/exception-handling.md)
|
16
|
+
* [Frequently Asked Questions](technical-overview/faq.md)
|
17
|
+
|
18
|
+
## How To
|
19
|
+
|
20
|
+
* [Make an echo server](howto/echo-server.md)
|
21
|
+
* [Make an HTTP server](howto/http-server.md)
|
22
|
+
* [Make a Websocket server](howto/websocket-server.md)
|
23
|
+
* [Use timers](howto/timers.md)
|
24
|
+
* [Throttle recurrent operations](howto/throttle.md)
|
25
|
+
* [Cancel ongoing operations](howto/cancel.md)
|
26
|
+
* [Control coprocesses](howto/coprocesses.md)
|
27
|
+
* [Synchronize concurrent operations](howto/synchronize.md)
|
28
|
+
* [Perform CPU-bound operations](howto/cpu-bound.md)
|
29
|
+
* [Control backpressure](howto/backpressure.md)
|
30
|
+
* [Fork worker processes](howto/worker-processes.md)
|
31
|
+
|
32
|
+
## Polyphony extensions
|
33
|
+
|
34
|
+
* [Postgresql](extensions/pg)
|
35
|
+
* [Redis](extensions/redis)
|
36
|
+
* [IRB](extensions/irb)
|
37
|
+
* [Throttlers](#)
|
38
|
+
* [Resource Pools](#)
|
39
|
+
* [Synchronisation](#)
|
40
|
+
* [Web Server](user-guide/web-server.md)
|
41
|
+
* [Websocket Server](#)
|
42
|
+
* [Reactor API](#)
|
43
|
+
|
44
|
+
## API Reference
|
45
|
+
|
46
|
+
* [Polyphony::CancelScope](#)
|
47
|
+
* [Polyphony::Coprocess](#)
|
48
|
+
* [Gyro](#)
|
49
|
+
* [Gyro::Async](#)
|
50
|
+
* [Gyro::Child](#)
|
51
|
+
* [Gyro::IO](#)
|
52
|
+
* [Gyro::Timer](#)
|
53
|
+
* [Kernel](#)
|
54
|
+
* [Polyphony](#)
|
55
|
+
* [Polyphony::Mutex](#)
|
56
|
+
* [Polyphony::Pulser](#)
|
57
|
+
* [Polyphony::ResourcePool](#)
|
58
|
+
* [Polyphony::Throttler](#)
|
59
|
+
|
60
|
+
## [Contributing to Polyphony](contributing.md)
|
data/examples/cuba.ru
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuba'
|
4
|
+
require 'cuba/safe'
|
5
|
+
|
6
|
+
Cuba.use Rack::Session::Cookie, secret: '__a_very_long_string__'
|
7
|
+
|
8
|
+
Cuba.plugin Cuba::Safe
|
9
|
+
|
10
|
+
Cuba.define do
|
11
|
+
on get do
|
12
|
+
on 'hello' do
|
13
|
+
res.write 'Hello world!'
|
14
|
+
end
|
15
|
+
|
16
|
+
on root do
|
17
|
+
res.redirect '/hello'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
run Cuba
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# idea taken from the example given in trio:
|
4
|
+
# https://www.youtube.com/watch?v=oLkfnc_UMcE
|
5
|
+
|
6
|
+
require 'bundler/setup'
|
7
|
+
require 'polyphony/http'
|
8
|
+
|
9
|
+
def try_connect(target, supervisor)
|
10
|
+
puts "trying #{target[2]}"
|
11
|
+
socket = Polyphony::Net.tcp_connect(target[2], 80)
|
12
|
+
# connection successful
|
13
|
+
supervisor.stop!([target[2], socket])
|
14
|
+
rescue IOError, SystemCallError
|
15
|
+
# ignore error
|
16
|
+
end
|
17
|
+
|
18
|
+
def happy_eyeballs(hostname, port, max_wait_time: 0.025)
|
19
|
+
targets = Socket.getaddrinfo(hostname, port, :INET, :STREAM)
|
20
|
+
t0 = Time.now
|
21
|
+
cancel_after(5) do
|
22
|
+
success = supervise do |supervisor|
|
23
|
+
targets.each_with_index do |t, idx|
|
24
|
+
sleep(max_wait_time) if idx > 0
|
25
|
+
supervisor.spin { try_connect(t, supervisor) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
if success
|
29
|
+
puts format('success: %s (%.3fs)', success[0], Time.now - t0)
|
30
|
+
else
|
31
|
+
puts "timed out (#{Time.now - t0}s)"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Let's try it out:
|
37
|
+
happy_eyeballs('debian.org', 'https')
|