polyphony 0.43.5 → 0.43.6
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -0
- data/docs/_includes/head.html +40 -0
- data/docs/_includes/title.html +1 -0
- data/docs/_user-guide/web-server.md +11 -11
- data/docs/index.md +3 -1
- data/docs/polyphony-logo.png +0 -0
- data/examples/io/xx-happy-eyeballs.rb +21 -22
- data/examples/io/xx-zip.rb +19 -0
- data/examples/xx-spin.rb +32 -0
- data/ext/polyphony/libev_agent.c +94 -27
- data/lib/polyphony.rb +4 -1
- data/lib/polyphony/extensions/fiber.rb +8 -8
- data/lib/polyphony/extensions/openssl.rb +8 -0
- data/lib/polyphony/extensions/socket.rb +2 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/test_socket.rb +43 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b048cfa1e0d7cd542840ab9f2198349b2474d40a6d943b584d1bcb57593ca41d
|
4
|
+
data.tar.gz: 0d9ed9fc45ec2165018e61f8befbdefb5668cfcf4b7628a648a055f5b6052e4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a962cb0db032fd58a8db4024d9a6ad2d1be5307caff72d9508bdf879bafbd6c55a5c79e9bc69a9d3bda96d2f72fda51ed2f978e96fa0ca636458284e9e9dbbaf
|
7
|
+
data.tar.gz: 2b419313309e898003399f780abcf7641de34c3350ae5d7c10c785209e3e6c12e4d741b01676a49ec1ec2f3f15ea8f9001636ec44880e13583d68168f82c9cb7
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 0.43.6 2020-07-18
|
2
|
+
|
3
|
+
* Allow brute-force interrupting with second Ctrl-C
|
4
|
+
* Fix outgoing SSL connections (#28)
|
5
|
+
* Improve Fiber#await_all_children with many children
|
6
|
+
* Use `writev` for writing multiple strings
|
7
|
+
* Add logo (thanks [Gerald](https://webocube.com/)!)
|
8
|
+
|
1
9
|
## 0.43.5 2020-07-13
|
2
10
|
|
3
11
|
* Fix `#read_nonblock`, `#write_nonblock` for `IO` and `Socket` (#27)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
<head>
|
2
|
+
<meta charset="UTF-8">
|
3
|
+
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
4
|
+
|
5
|
+
{% unless site.plugins contains "jekyll-seo-tag" %}
|
6
|
+
<title>{{ page.title }} - {{ site.title }}</title>
|
7
|
+
|
8
|
+
{% if page.description %}
|
9
|
+
<meta name="Description" content="{{ page.description }}">
|
10
|
+
{% endif %}
|
11
|
+
{% endunless %}
|
12
|
+
|
13
|
+
<link rel="shortcut icon" href="{{ 'polyphony-logo.png' | absolute_url }}" type="image/png">
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="{{ '/assets/css/just-the-docs-default.css' | absolute_url }}">
|
16
|
+
|
17
|
+
{% if site.ga_tracking != nil %}
|
18
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id={{ site.ga_tracking }}"></script>
|
19
|
+
<script>
|
20
|
+
window.dataLayer = window.dataLayer || [];
|
21
|
+
function gtag(){dataLayer.push(arguments);}
|
22
|
+
gtag('js', new Date());
|
23
|
+
|
24
|
+
gtag('config', '{{ site.ga_tracking }}'{% unless site.ga_tracking_anonymize_ip == nil %}, { 'anonymize_ip': true }{% endunless %});
|
25
|
+
</script>
|
26
|
+
|
27
|
+
{% endif %}
|
28
|
+
|
29
|
+
{% if site.search_enabled != false %}
|
30
|
+
<script type="text/javascript" src="{{ '/assets/js/vendor/lunr.min.js' | absolute_url }}"></script>
|
31
|
+
{% endif %}
|
32
|
+
<script type="text/javascript" src="{{ '/assets/js/just-the-docs.js' | absolute_url }}"></script>
|
33
|
+
|
34
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
35
|
+
|
36
|
+
{% seo %}
|
37
|
+
|
38
|
+
{% include head_custom.html %}
|
39
|
+
|
40
|
+
</head>
|
@@ -0,0 +1 @@
|
|
1
|
+
<img src="{{ 'polyphony-logo.png' | absolute_url }}" style="height: 1.5em; margin-right: 0.5em">Polyphony
|
@@ -26,9 +26,9 @@ the entire request body.
|
|
26
26
|
## A basic web server
|
27
27
|
|
28
28
|
```ruby
|
29
|
-
require '
|
29
|
+
require 'tipi'
|
30
30
|
|
31
|
-
|
31
|
+
Tipi.serve('0.0.0.0', 1234) do |request|
|
32
32
|
request.respond("Hello world!\n")
|
33
33
|
end
|
34
34
|
```
|
@@ -55,13 +55,13 @@ TLS termination can be handled by passing a `secure_context` option to the
|
|
55
55
|
server:
|
56
56
|
|
57
57
|
```ruby
|
58
|
-
require '
|
58
|
+
require 'tipi'
|
59
59
|
require 'localhost/authority'
|
60
60
|
|
61
61
|
authority = Localhost::Authority.fetch
|
62
62
|
opts = { secure_context: authority.server_context }
|
63
63
|
|
64
|
-
|
64
|
+
Tipi.serve('0.0.0.0', 1234, opts) do |request|
|
65
65
|
request.respond("Hello world!\n")
|
66
66
|
end
|
67
67
|
```
|
@@ -72,8 +72,8 @@ Polyphony's web server makes it really easy to integrate websocket communication
|
|
72
72
|
with normal HTTP processing:
|
73
73
|
|
74
74
|
```ruby
|
75
|
-
require '
|
76
|
-
require '
|
75
|
+
require 'tipi'
|
76
|
+
require 'tipi/websocket'
|
77
77
|
|
78
78
|
ws_handler = Polyphony::Websocket.handler do |ws|
|
79
79
|
while (msg = ws.recv)
|
@@ -85,7 +85,7 @@ opts = {
|
|
85
85
|
upgrade: { websocket: ws_handler }
|
86
86
|
}
|
87
87
|
|
88
|
-
|
88
|
+
Tipi.serve('0.0.0.0', 1234, opts) do |request|
|
89
89
|
request.respond("Hello world!\n")
|
90
90
|
end
|
91
91
|
```
|
@@ -93,7 +93,7 @@ end
|
|
93
93
|
Polyphony also supports general-purpose HTTP upgrades using the same mechanism:
|
94
94
|
|
95
95
|
```ruby
|
96
|
-
require '
|
96
|
+
require 'tipi'
|
97
97
|
|
98
98
|
opts = {
|
99
99
|
upgrade: {
|
@@ -105,7 +105,7 @@ opts = {
|
|
105
105
|
}
|
106
106
|
}
|
107
107
|
|
108
|
-
|
108
|
+
Tipi.serve('0.0.0.0', 1234, opts) do |request|
|
109
109
|
request.respond("Hello world!\n")
|
110
110
|
end
|
111
111
|
```
|
@@ -117,7 +117,7 @@ and enables streaming (using chunked encoding for HTTP/1.1 connections). Here's
|
|
117
117
|
an example of an SSE response:
|
118
118
|
|
119
119
|
```ruby
|
120
|
-
require '
|
120
|
+
require 'tipi'
|
121
121
|
|
122
122
|
def sse_response(request)
|
123
123
|
request.send_headers('Content-Type': 'text/event-stream')
|
@@ -131,6 +131,6 @@ ensure
|
|
131
131
|
request.send_chunk("retry: 0\n\n", done: true)
|
132
132
|
end
|
133
133
|
|
134
|
-
|
134
|
+
Tipi.serve('0.0.0.0', 1234, &method(:sse_response))
|
135
135
|
```
|
136
136
|
|
data/docs/index.md
CHANGED
@@ -6,6 +6,8 @@ permalink: /
|
|
6
6
|
next_title: Installing Polyphony
|
7
7
|
---
|
8
8
|
|
9
|
+
<p align="center"><img src="{{ 'polyphony-logo.png' | absolute_url }}" /></p>
|
10
|
+
|
9
11
|
# Polyphony
|
10
12
|
{:.text-center .logo-title}
|
11
13
|
|
@@ -21,7 +23,7 @@ for I/O, timers, and other asynchronous events.
|
|
21
23
|
[Overview](getting-started/overview){: .btn .btn-green .text-gamma }
|
22
24
|
[Take the tutorial](getting-started/tutorial){: .btn .btn-blue .text-gamma }
|
23
25
|
[Source code](https://github.com/digital-fabric/polyphony){: .btn .btn-purple .text-gamma target="_blank" }
|
24
|
-
{
|
26
|
+
{:.text-center .mt-6 .h-align-center }
|
25
27
|
|
26
28
|
## Focused on Developer Happiness
|
27
29
|
|
data/docs/polyphony-logo.png
CHANGED
Binary file
|
@@ -1,37 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
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
3
|
require 'polyphony'
|
8
4
|
|
9
|
-
def try_connect(
|
10
|
-
puts "trying #{
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
def try_connect(ip_address, port, supervisor)
|
6
|
+
puts "trying #{ip_address}"
|
7
|
+
sleep rand * 0.2
|
8
|
+
socket = TCPSocket.new(ip_address, port)
|
9
|
+
puts "connected to #{ip_address}"
|
10
|
+
supervisor.schedule [ip_address, socket]
|
14
11
|
rescue IOError, SystemCallError
|
15
12
|
# ignore error
|
16
13
|
end
|
17
14
|
|
18
|
-
def happy_eyeballs(hostname, port, max_wait_time: 0.
|
15
|
+
def happy_eyeballs(hostname, port, max_wait_time: 0.010)
|
19
16
|
targets = Socket.getaddrinfo(hostname, port, :INET, :STREAM)
|
20
17
|
t0 = Time.now
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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)"
|
18
|
+
fibers = []
|
19
|
+
supervisor = Fiber.current
|
20
|
+
spin do
|
21
|
+
targets.each do |t|
|
22
|
+
spin { try_connect(t[2], t[1], supervisor) }
|
23
|
+
sleep(max_wait_time)
|
32
24
|
end
|
25
|
+
suspend
|
26
|
+
end
|
27
|
+
target, socket = move_on_after(5) { suspend }
|
28
|
+
supervisor.shutdown_all_children
|
29
|
+
if target
|
30
|
+
puts format('success: %s (%.3fs)', target, Time.now - t0)
|
31
|
+
else
|
32
|
+
puts 'timed out'
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
# Let's try it out:
|
37
36
|
happy_eyeballs('debian.org', 'https')
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require 'zlib'
|
6
|
+
|
7
|
+
i, o = IO.pipe
|
8
|
+
|
9
|
+
w = Zlib::GzipWriter.new(o)
|
10
|
+
|
11
|
+
s = (1..1000).map { (65 + rand(26)).chr }.join
|
12
|
+
puts "full length: #{s.bytesize}"
|
13
|
+
w << s
|
14
|
+
w.close
|
15
|
+
o.close
|
16
|
+
|
17
|
+
|
18
|
+
z = i.read
|
19
|
+
puts "zipped length: #{z.bytesize}"
|
data/examples/xx-spin.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
puts "pid: #{Process.pid}"
|
7
|
+
GC.disable
|
8
|
+
|
9
|
+
def mem_usage
|
10
|
+
# orig_backtick('ps -o rss #{$$}').split.last.to_i
|
11
|
+
`ps -o rss #{$$}`.split.last.to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
f = File.open('spin.log', 'w+')
|
15
|
+
|
16
|
+
m0 = mem_usage
|
17
|
+
|
18
|
+
X = ARGV[0] ? ARGV[0].to_i : 10
|
19
|
+
STDOUT.orig_write "Starting #{X} fibers...\n"
|
20
|
+
t0 = Time.now
|
21
|
+
x = nil
|
22
|
+
X.times do |i|
|
23
|
+
spin { p i; suspend }
|
24
|
+
end
|
25
|
+
|
26
|
+
suspend
|
27
|
+
f.close
|
28
|
+
t1 = Time.now
|
29
|
+
m1 = mem_usage
|
30
|
+
rate = X / (t1 - t0)
|
31
|
+
mem_cost = (m1 - m0) / X.to_f
|
32
|
+
STDOUT.orig_write("#{ { time: t1 - t0, spin_rate: rate, fiber_mem_cost: mem_cost }.inspect }\n")
|
data/ext/polyphony/libev_agent.c
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#include <netdb.h>
|
2
2
|
#include <sys/socket.h>
|
3
|
+
#include <sys/uio.h>
|
3
4
|
|
4
5
|
#include "polyphony.h"
|
5
6
|
#include "../libev/ev.h"
|
@@ -413,20 +414,62 @@ error:
|
|
413
414
|
return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
|
414
415
|
}
|
415
416
|
|
416
|
-
VALUE LibevAgent_write(
|
417
|
+
VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
417
418
|
struct LibevAgent_t *agent;
|
418
419
|
struct libev_io watcher;
|
419
420
|
rb_io_t *fptr;
|
420
421
|
VALUE switchpoint_result = Qnil;
|
421
|
-
VALUE io;
|
422
422
|
VALUE underlying_io;
|
423
|
+
char *buf = StringValuePtr(str);
|
424
|
+
long len = RSTRING_LEN(str);
|
425
|
+
long left = len;
|
426
|
+
|
427
|
+
underlying_io = rb_iv_get(io, "@io");
|
428
|
+
if (underlying_io != Qnil) io = underlying_io;
|
429
|
+
GetLibevAgent(self, agent);
|
430
|
+
io = rb_io_get_write_io(io);
|
431
|
+
GetOpenFile(io, fptr);
|
432
|
+
watcher.fiber = Qnil;
|
433
|
+
|
434
|
+
while (left > 0) {
|
435
|
+
ssize_t n = write(fptr->fd, buf, left);
|
436
|
+
if (n < 0) {
|
437
|
+
int e = errno;
|
438
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
439
|
+
switchpoint_result = libev_io_wait(agent, &watcher, fptr, EV_WRITE);
|
440
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
441
|
+
}
|
442
|
+
else {
|
443
|
+
buf += n;
|
444
|
+
left -= n;
|
445
|
+
}
|
446
|
+
}
|
447
|
+
|
448
|
+
if (watcher.fiber == Qnil) {
|
449
|
+
switchpoint_result = libev_snooze();
|
450
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
451
|
+
}
|
452
|
+
|
453
|
+
RB_GC_GUARD(watcher.fiber);
|
454
|
+
RB_GC_GUARD(switchpoint_result);
|
455
|
+
|
456
|
+
return INT2NUM(len);
|
457
|
+
error:
|
458
|
+
return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
|
459
|
+
}
|
460
|
+
|
461
|
+
VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
462
|
+
struct LibevAgent_t *agent;
|
463
|
+
struct libev_io watcher;
|
464
|
+
rb_io_t *fptr;
|
465
|
+
VALUE switchpoint_result = Qnil;
|
466
|
+
VALUE underlying_io;
|
467
|
+
long total_length = 0;
|
423
468
|
long total_written = 0;
|
424
|
-
|
469
|
+
struct iovec *iov = 0;
|
470
|
+
struct iovec *iov_ptr = 0;
|
471
|
+
int iov_count = argc;
|
425
472
|
|
426
|
-
if (argc < 2)
|
427
|
-
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
428
|
-
|
429
|
-
io = argv[0];
|
430
473
|
underlying_io = rb_iv_get(io, "@io");
|
431
474
|
if (underlying_io != Qnil) io = underlying_io;
|
432
475
|
GetLibevAgent(self, agent);
|
@@ -434,30 +477,42 @@ VALUE LibevAgent_write(int argc, VALUE *argv, VALUE self) {
|
|
434
477
|
GetOpenFile(io, fptr);
|
435
478
|
watcher.fiber = Qnil;
|
436
479
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
480
|
+
iov = malloc(iov_count * sizeof(struct iovec));
|
481
|
+
for (int i = 0; i < argc; i++) {
|
482
|
+
VALUE str = argv[i];
|
483
|
+
iov[i].iov_base = StringValuePtr(str);
|
484
|
+
iov[i].iov_len = RSTRING_LEN(str);
|
485
|
+
total_length += iov[i].iov_len;
|
486
|
+
}
|
487
|
+
iov_ptr = iov;
|
442
488
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
489
|
+
while (1) {
|
490
|
+
ssize_t n = writev(fptr->fd, iov_ptr, iov_count);
|
491
|
+
if (n < 0) {
|
492
|
+
int e = errno;
|
493
|
+
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
448
494
|
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
495
|
+
switchpoint_result = libev_io_wait(agent, &watcher, fptr, EV_WRITE);
|
496
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
497
|
+
}
|
498
|
+
else {
|
499
|
+
total_written += n;
|
500
|
+
if (total_written == total_length) break;
|
501
|
+
|
502
|
+
while (n > 0) {
|
503
|
+
if ((size_t) n < iov_ptr[0].iov_len) {
|
504
|
+
iov_ptr[0].iov_base = (char *) iov_ptr[0].iov_base + n;
|
505
|
+
iov_ptr[0].iov_len -= n;
|
506
|
+
n = 0;
|
507
|
+
}
|
508
|
+
else {
|
509
|
+
n -= iov_ptr[0].iov_len;
|
510
|
+
iov_ptr += 1;
|
511
|
+
iov_count -= 1;
|
512
|
+
}
|
455
513
|
}
|
456
514
|
}
|
457
|
-
total_written += len;
|
458
|
-
arg_idx++;
|
459
515
|
}
|
460
|
-
|
461
516
|
if (watcher.fiber == Qnil) {
|
462
517
|
switchpoint_result = libev_snooze();
|
463
518
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
@@ -466,11 +521,23 @@ VALUE LibevAgent_write(int argc, VALUE *argv, VALUE self) {
|
|
466
521
|
RB_GC_GUARD(watcher.fiber);
|
467
522
|
RB_GC_GUARD(switchpoint_result);
|
468
523
|
|
524
|
+
free(iov);
|
469
525
|
return INT2NUM(total_written);
|
470
526
|
error:
|
527
|
+
free(iov);
|
471
528
|
return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
|
472
529
|
}
|
473
530
|
|
531
|
+
VALUE LibevAgent_write_m(int argc, VALUE *argv, VALUE self) {
|
532
|
+
if (argc < 2)
|
533
|
+
// TODO: raise ArgumentError
|
534
|
+
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
535
|
+
|
536
|
+
return (argc == 2) ?
|
537
|
+
LibevAgent_write(self, argv[0], argv[1]) :
|
538
|
+
LibevAgent_writev(self, argv[0], argc - 1, argv + 1);
|
539
|
+
}
|
540
|
+
|
474
541
|
///////////////////////////////////////////////////////////////////////////
|
475
542
|
|
476
543
|
VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
@@ -738,7 +805,7 @@ void Init_LibevAgent() {
|
|
738
805
|
|
739
806
|
rb_define_method(cLibevAgent, "read", LibevAgent_read, 4);
|
740
807
|
rb_define_method(cLibevAgent, "read_loop", LibevAgent_read_loop, 1);
|
741
|
-
rb_define_method(cLibevAgent, "write",
|
808
|
+
rb_define_method(cLibevAgent, "write", LibevAgent_write_m, -1);
|
742
809
|
rb_define_method(cLibevAgent, "accept", LibevAgent_accept, 1);
|
743
810
|
rb_define_method(cLibevAgent, "accept_loop", LibevAgent_accept_loop, 1);
|
744
811
|
// rb_define_method(cLibevAgent, "connect", LibevAgent_accept, 3);
|
data/lib/polyphony.rb
CHANGED
@@ -102,7 +102,10 @@ module Polyphony
|
|
102
102
|
|
103
103
|
def install_terminating_signal_handlers
|
104
104
|
trap('SIGTERM', SystemExit)
|
105
|
-
|
105
|
+
orig_trap('SIGINT') do
|
106
|
+
orig_trap('SIGINT') { exit! }
|
107
|
+
Thread.current.break_out_of_ev_loop(Thread.main.main_fiber, Interrupt.new)
|
108
|
+
end
|
106
109
|
end
|
107
110
|
|
108
111
|
def terminate_threads
|
@@ -221,14 +221,14 @@ module Polyphony
|
|
221
221
|
def await_all_children
|
222
222
|
return unless @children && !@children.empty?
|
223
223
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
224
|
+
@results = @children.dup
|
225
|
+
@on_child_done = proc do |c, r|
|
226
|
+
@results[c] = r
|
227
|
+
self.schedule if @children.empty?
|
228
|
+
end
|
229
|
+
suspend
|
230
|
+
@on_child_done = nil
|
231
|
+
@results.values
|
232
232
|
end
|
233
233
|
|
234
234
|
def shutdown_all_children
|
@@ -5,6 +5,12 @@ require_relative './socket'
|
|
5
5
|
|
6
6
|
# Open ssl socket helper methods (to make it compatible with Socket API)
|
7
7
|
class ::OpenSSL::SSL::SSLSocket
|
8
|
+
alias_method :orig_initialize, :initialize
|
9
|
+
def initialize(socket, context = nil)
|
10
|
+
socket = socket.respond_to?(:io) ? socket.io || socket : socket
|
11
|
+
context ? orig_initialize(socket, context) : orig_initialize(socket)
|
12
|
+
end
|
13
|
+
|
8
14
|
def dont_linger
|
9
15
|
io.dont_linger
|
10
16
|
end
|
@@ -35,6 +41,7 @@ class ::OpenSSL::SSL::SSLSocket
|
|
35
41
|
loop do
|
36
42
|
case (result = read_nonblock(maxlen, buf, exception: false))
|
37
43
|
when :wait_readable then Thread.current.agent.wait_io(io, false)
|
44
|
+
when :wait_writable then Thread.current.agent.wait_io(io, true)
|
38
45
|
else return result
|
39
46
|
end
|
40
47
|
end
|
@@ -44,6 +51,7 @@ class ::OpenSSL::SSL::SSLSocket
|
|
44
51
|
def syswrite(buf)
|
45
52
|
loop do
|
46
53
|
case (result = write_nonblock(buf, exception: false))
|
54
|
+
when :wait_readable then Thread.current.agent.wait_io(io, false)
|
47
55
|
when :wait_writable then Thread.current.agent.wait_io(io, true)
|
48
56
|
else
|
49
57
|
return result
|
@@ -87,6 +87,8 @@ end
|
|
87
87
|
class ::TCPSocket
|
88
88
|
NO_EXCEPTION = { exception: false }.freeze
|
89
89
|
|
90
|
+
attr_reader :io
|
91
|
+
|
90
92
|
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
91
93
|
@io = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
|
92
94
|
if local_host && local_port
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_socket.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
|
+
require 'localhost/authority'
|
4
5
|
|
5
6
|
class SocketTest < MiniTest::Test
|
6
7
|
def setup
|
@@ -31,4 +32,46 @@ class SocketTest < MiniTest::Test
|
|
31
32
|
server_fiber&.await
|
32
33
|
server&.close
|
33
34
|
end
|
35
|
+
|
36
|
+
def test_openssl
|
37
|
+
authority = Localhost::Authority.fetch
|
38
|
+
context = authority.server_context
|
39
|
+
port = rand(1234..5678)
|
40
|
+
sock = TCPServer.new('127.0.0.1', port)
|
41
|
+
server = OpenSSL::SSL::SSLServer.new(sock, context)
|
42
|
+
|
43
|
+
server_fiber = spin do
|
44
|
+
while (socket = server.accept)
|
45
|
+
puts "accepted: #{socket.inspect}"
|
46
|
+
spin do
|
47
|
+
while (data = socket.gets(8192))
|
48
|
+
socket << data
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
snooze
|
55
|
+
p 1
|
56
|
+
sock = TCPSocket.new('127.0.0.1', port)
|
57
|
+
p 2
|
58
|
+
sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
59
|
+
context = OpenSSL::SSL::SSLContext.new
|
60
|
+
context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
61
|
+
client = OpenSSL::SSL::SSLSocket.new(sock, context)
|
62
|
+
client.sync_close = true
|
63
|
+
client.hostname = 'localhost'
|
64
|
+
p 3
|
65
|
+
client.connect
|
66
|
+
p 4
|
67
|
+
client.write("GET / HTTP/1.0\r\nHost: realiteq.net\r\n\r\n")#("1234\n")
|
68
|
+
p 5
|
69
|
+
assert_equal "1234\n", client.readpartial(8192)
|
70
|
+
p 6
|
71
|
+
client.close
|
72
|
+
ensure
|
73
|
+
server_fiber&.stop
|
74
|
+
server_fiber&.await
|
75
|
+
server&.close
|
76
|
+
end
|
34
77
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.43.
|
4
|
+
version: 0.43.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -242,6 +242,8 @@ files:
|
|
242
242
|
- TODO.md
|
243
243
|
- bin/polyphony-debug
|
244
244
|
- docs/_config.yml
|
245
|
+
- docs/_includes/head.html
|
246
|
+
- docs/_includes/title.html
|
245
247
|
- docs/_sass/custom/custom.scss
|
246
248
|
- docs/_sass/overrides.scss
|
247
249
|
- docs/_user-guide/all-about-timers.md
|
@@ -351,6 +353,7 @@ files:
|
|
351
353
|
- examples/io/xx-system.rb
|
352
354
|
- examples/io/xx-tcpserver.rb
|
353
355
|
- examples/io/xx-tcpsocket.rb
|
356
|
+
- examples/io/xx-zip.rb
|
354
357
|
- examples/performance/fs_read.rb
|
355
358
|
- examples/performance/mem-usage.rb
|
356
359
|
- examples/performance/messaging.rb
|
@@ -367,6 +370,7 @@ files:
|
|
367
370
|
- examples/performance/xx-array.rb
|
368
371
|
- examples/performance/xx-fiber-switch.rb
|
369
372
|
- examples/performance/xx-snooze.rb
|
373
|
+
- examples/xx-spin.rb
|
370
374
|
- ext/libev/Changes
|
371
375
|
- ext/libev/LICENSE
|
372
376
|
- ext/libev/README
|