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