polyphony 0.13 → 0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitbook.yaml +5 -0
- data/.gitignore +55 -0
- data/.rubocop.yml +49 -0
- data/CHANGELOG.md +13 -2
- data/Gemfile +3 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +21 -0
- data/README.md +35 -18
- data/Rakefile +20 -0
- data/TODO.md +49 -0
- data/docs/getting-started/getting-started.md +10 -0
- data/docs/getting-started/tutorial.md +2 -0
- data/docs/summary.md +9 -0
- data/examples/core/cancel.rb +10 -0
- data/examples/core/channel_echo.rb +43 -0
- data/examples/core/enumerator.rb +14 -0
- data/examples/core/fork.rb +22 -0
- data/examples/core/genserver.rb +74 -0
- data/examples/core/lock.rb +20 -0
- data/examples/core/move_on.rb +11 -0
- data/examples/core/move_on_twice.rb +17 -0
- data/examples/core/move_on_with_ensure.rb +17 -0
- data/examples/core/multiple_async.rb +17 -0
- data/examples/core/nested_async.rb +18 -0
- data/examples/core/nested_cancel.rb +41 -0
- data/examples/core/nested_multiple_async.rb +19 -0
- data/examples/core/next_tick.rb +13 -0
- data/examples/core/pulse.rb +13 -0
- data/examples/core/resource.rb +29 -0
- data/examples/core/resource_cancel.rb +34 -0
- data/examples/core/resource_delegate.rb +32 -0
- data/examples/core/sleep.rb +9 -0
- data/examples/core/sleep2.rb +13 -0
- data/examples/core/spawn.rb +15 -0
- data/examples/core/spawn_cancel.rb +19 -0
- data/examples/core/spawn_error.rb +28 -0
- data/examples/core/supervisor.rb +22 -0
- data/examples/core/supervisor_with_cancel_scope.rb +24 -0
- data/examples/core/supervisor_with_error.rb +23 -0
- data/examples/core/supervisor_with_manual_move_on.rb +25 -0
- data/examples/core/thread.rb +30 -0
- data/examples/core/thread_cancel.rb +30 -0
- data/examples/core/thread_pool.rb +60 -0
- data/examples/core/throttle.rb +17 -0
- data/examples/fs/read.rb +37 -0
- data/examples/interfaces/pg_client.rb +38 -0
- data/examples/interfaces/pg_pool.rb +37 -0
- data/examples/interfaces/pg_query.rb +32 -0
- data/examples/interfaces/redis_channels.rb +119 -0
- data/examples/interfaces/redis_client.rb +21 -0
- data/examples/interfaces/redis_pubsub.rb +26 -0
- data/examples/interfaces/redis_pubsub_perf.rb +65 -0
- data/examples/io/config.ru +3 -0
- data/examples/io/echo_client.rb +22 -0
- data/examples/io/echo_server.rb +14 -0
- data/examples/io/echo_server_with_timeout.rb +33 -0
- data/examples/io/echo_stdin.rb +15 -0
- data/examples/io/happy_eyeballs.rb +32 -0
- data/examples/io/http_client.rb +19 -0
- data/examples/io/http_server.js +24 -0
- data/examples/io/http_server.rb +16 -0
- data/examples/io/http_server_forked.rb +27 -0
- data/examples/io/http_server_throttled.rb +16 -0
- data/examples/io/http_ws_server.rb +42 -0
- data/examples/io/https_client.rb +17 -0
- data/examples/io/https_server.rb +23 -0
- data/examples/io/https_wss_server.rb +46 -0
- data/examples/io/rack_server.rb +19 -0
- data/examples/io/rack_server_https.rb +24 -0
- data/examples/io/rack_server_https_forked.rb +32 -0
- data/examples/io/websocket_server.rb +33 -0
- data/examples/io/ws_page.html +34 -0
- data/examples/io/wss_page.html +34 -0
- data/examples/performance/perf_multi_snooze.rb +21 -0
- data/examples/performance/perf_snooze.rb +30 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +63 -0
- data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
- data/examples/streams/lines.rb +27 -0
- data/examples/streams/stdio.rb +18 -0
- data/ext/ev/async.c +168 -0
- data/ext/ev/child.c +169 -0
- data/ext/ev/ev.h +32 -0
- data/ext/ev/ev_ext.c +20 -0
- data/ext/ev/ev_module.c +222 -0
- data/ext/ev/io.c +405 -0
- data/ext/ev/libev.h +9 -0
- data/ext/ev/signal.c +119 -0
- data/ext/ev/timer.c +197 -0
- data/ext/libev/Changes +513 -0
- data/ext/libev/LICENSE +37 -0
- data/ext/libev/README +58 -0
- data/ext/libev/README.embed +3 -0
- data/ext/libev/ev.c +5214 -0
- data/ext/libev/ev.h +849 -0
- data/ext/libev/ev_epoll.c +285 -0
- data/ext/libev/ev_kqueue.c +218 -0
- data/ext/libev/ev_poll.c +151 -0
- data/ext/libev/ev_port.c +189 -0
- data/ext/libev/ev_select.c +316 -0
- data/ext/libev/ev_vars.h +204 -0
- data/ext/libev/ev_win32.c +162 -0
- data/ext/libev/ev_wrap.h +200 -0
- data/ext/libev/test_libev_win32.c +123 -0
- data/lib/polyphony.rb +7 -2
- data/lib/polyphony/core.rb +1 -1
- data/lib/polyphony/core/{coroutine.rb → coprocess.rb} +10 -10
- data/lib/polyphony/core/exceptions.rb +5 -5
- data/lib/polyphony/core/supervisor.rb +16 -16
- data/lib/polyphony/core/thread.rb +1 -1
- data/lib/polyphony/extensions/io.rb +43 -42
- data/lib/polyphony/extensions/kernel.rb +10 -34
- data/lib/polyphony/extensions/postgres.rb +3 -2
- data/lib/polyphony/extensions/redis.rb +1 -1
- data/lib/polyphony/extensions/socket.rb +8 -4
- data/lib/polyphony/extensions/ssl.rb +0 -54
- data/lib/polyphony/http/agent.rb +4 -10
- data/lib/polyphony/http/http1.rb +25 -25
- data/lib/polyphony/http/http1_request.rb +38 -26
- data/lib/polyphony/http/http2.rb +4 -5
- data/lib/polyphony/http/http2_request.rb +12 -18
- data/lib/polyphony/http/rack.rb +1 -3
- data/lib/polyphony/http/server.rb +9 -9
- data/lib/polyphony/net.rb +2 -2
- data/lib/polyphony/resource_pool.rb +5 -1
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony/websocket.rb +52 -0
- data/polyphony.gemspec +31 -0
- data/test/test_coprocess.rb +131 -0
- data/test/test_core.rb +274 -0
- data/test/test_ev.rb +117 -0
- data/test/test_io.rb +38 -0
- metadata +113 -7
- data/lib/polyphony/core/async.rb +0 -36
- data/lib/polyphony/net_old.rb +0 -299
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
import('../../lib/polyphony/extensions/redis')
|
7
|
+
|
8
|
+
redis = Redis.new
|
9
|
+
|
10
|
+
X = 10000
|
11
|
+
|
12
|
+
t0 = Time.now
|
13
|
+
X.times { redis.get('abc') }
|
14
|
+
puts "get rate: #{X / (Time.now - t0)} reqs/s"
|
15
|
+
|
16
|
+
puts "abc = #{redis.get('abc')}"
|
17
|
+
|
18
|
+
puts "updating value..."
|
19
|
+
redis.set('abc', Time.now.to_s)
|
20
|
+
|
21
|
+
puts "abc = #{redis.get('abc')}"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
import('../../lib/polyphony/extensions/redis')
|
7
|
+
|
8
|
+
spawn do
|
9
|
+
redis = Redis.new
|
10
|
+
redis.subscribe('redis-channel') do |on|
|
11
|
+
on.message do |channel, message|
|
12
|
+
puts "##{channel}: #{message}"
|
13
|
+
redis.unsubscribe if message == "exit"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
spawn do
|
19
|
+
redis = Redis.new
|
20
|
+
move_on_after(3) do
|
21
|
+
throttled_loop(1) do
|
22
|
+
redis.publish('redis-channel', Time.now)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
redis.publish('redis-channel', 'exit')
|
26
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
Polyphony = import('../../lib/polyphony')
|
7
|
+
import('../../lib/polyphony/extensions/redis')
|
8
|
+
|
9
|
+
X_SESSIONS = 1000
|
10
|
+
X_NODES = 10000
|
11
|
+
X_SUBSCRIPTIONS_PER_SESSION = 100
|
12
|
+
|
13
|
+
$sessions = []
|
14
|
+
X_SESSIONS.times do
|
15
|
+
$sessions << {
|
16
|
+
subscriptions: X_SUBSCRIPTIONS_PER_SESSION.times.map {
|
17
|
+
"node#{rand(X_NODES)}"
|
18
|
+
}.uniq
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
spawn do
|
23
|
+
redis = Redis.new
|
24
|
+
redis.subscribe('events') do |on|
|
25
|
+
on.message do |_, message|
|
26
|
+
distribute_event(JSON.parse(message, symbolize_names: true))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
$update_count = 0
|
32
|
+
|
33
|
+
def distribute_event(event)
|
34
|
+
$update_count += 1
|
35
|
+
t0 = Time.now
|
36
|
+
count = 0
|
37
|
+
$sessions.each do |s|
|
38
|
+
count += 1 if s[:subscriptions].include?(event[:path])
|
39
|
+
end
|
40
|
+
elapsed = Time.now - t0
|
41
|
+
rate = X_SESSIONS / elapsed
|
42
|
+
# puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
|
43
|
+
end
|
44
|
+
|
45
|
+
spawn do
|
46
|
+
redis = Redis.new
|
47
|
+
throttled_loop(1000) do
|
48
|
+
redis.publish('events', {path: "node#{rand(X_NODES)}"}.to_json)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
spawn do
|
53
|
+
last_count = 0
|
54
|
+
last_stamp = Time.now
|
55
|
+
throttled_loop(1) do
|
56
|
+
now = Time.now
|
57
|
+
elapsed = now - last_stamp
|
58
|
+
delta = $update_count - last_count
|
59
|
+
puts "update rate: #{delta.to_f/elapsed}"
|
60
|
+
last_stamp = now
|
61
|
+
last_count = $update_count
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
Polyphony.trap(:int) { puts "bye..."; exit! }
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
|
7
|
+
socket = Polyphony::Net.tcp_connect('127.0.0.1', 1234)
|
8
|
+
|
9
|
+
writer = spawn do
|
10
|
+
throttled_loop(1) { socket << "#{Time.now}\n" }
|
11
|
+
end
|
12
|
+
|
13
|
+
reader = spawn do
|
14
|
+
puts "received from echo server:"
|
15
|
+
while data = socket.read
|
16
|
+
STDOUT << data
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
sleep(5)
|
21
|
+
[reader, writer].each(&:stop)
|
22
|
+
socket.close
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
Polyphony = import('../../lib/polyphony')
|
5
|
+
|
6
|
+
server = TCPServer.open(1234)
|
7
|
+
puts "Echoing on port 1234..."
|
8
|
+
while client = server.accept
|
9
|
+
spawn do
|
10
|
+
while data = client.readpartial(8192) rescue nil
|
11
|
+
client.write("you said: ", data.chomp, "!\n")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
|
7
|
+
begin
|
8
|
+
server = Polyphony::Net.tcp_listen(nil, 1234, reuse_addr: true, dont_linger: true)
|
9
|
+
puts "listening on port 1234..."
|
10
|
+
|
11
|
+
loop do
|
12
|
+
client = server.accept
|
13
|
+
spawn do
|
14
|
+
cancel_scope = nil
|
15
|
+
move_on_after(5) do |s|
|
16
|
+
cancel_scope = s
|
17
|
+
loop do
|
18
|
+
data = client.read
|
19
|
+
s.reset_timeout
|
20
|
+
client.write(data)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
client.write "Disconnecting due to inactivity\n" if cancel_scope.cancelled?
|
24
|
+
rescue => e
|
25
|
+
puts "client error: #{e.inspect}"
|
26
|
+
ensure
|
27
|
+
client.close
|
28
|
+
end
|
29
|
+
end
|
30
|
+
rescue Exception => e
|
31
|
+
puts "uncaught exception: #{e.inspect}"
|
32
|
+
server&.close
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
|
7
|
+
puts "Write something..."
|
8
|
+
move_on_after(5) do |scope|
|
9
|
+
loop do
|
10
|
+
data = STDIN.read
|
11
|
+
scope.reset_timeout
|
12
|
+
puts "you wrote: #{data}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
puts "quitting due to inactivity"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
Polyphony = import('../../lib/polyphony')
|
5
|
+
|
6
|
+
async def try_connect(supervisor, target)
|
7
|
+
puts "trying #{target[2]}"
|
8
|
+
socket = Polyphony::Net.tcp_connect(target[2], 80)
|
9
|
+
supervisor.stop!([target[2], socket])
|
10
|
+
rescue IOError, SystemCallError
|
11
|
+
end
|
12
|
+
|
13
|
+
def happy_eyeballs(hostname, port, max_wait_time: 0.025)
|
14
|
+
targets = Socket.getaddrinfo(hostname, port, :INET, :STREAM)
|
15
|
+
t0 = Time.now
|
16
|
+
cancel_after(5) do
|
17
|
+
success = supervise do |supervisor|
|
18
|
+
targets.each_with_index do |t, idx|
|
19
|
+
sleep(max_wait_time) if idx > 0
|
20
|
+
supervisor.spawn try_connect(supervisor, t)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
if success
|
24
|
+
puts "success: #{success[0]} (#{Time.now - t0}s)"
|
25
|
+
else
|
26
|
+
puts "timed out (#{Time.now - t0}s)"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Let's try it out:
|
32
|
+
happy_eyeballs("debian.org", "https")
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
Agent = import('../../lib/polyphony/http/agent')
|
7
|
+
|
8
|
+
def get_server_time
|
9
|
+
Agent.get('https://ui.realiteq.net/', q: :time).json
|
10
|
+
end
|
11
|
+
|
12
|
+
X = 50
|
13
|
+
puts "Making #{X} requests..."
|
14
|
+
t0 = Time.now
|
15
|
+
supervise do |s|
|
16
|
+
X.times { get_server_time }
|
17
|
+
end
|
18
|
+
elapsed = Time.now - t0
|
19
|
+
puts "count: #{X} elapsed: #{elapsed} rate: #{X / elapsed} reqs/s"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
// For the sake of comparing performance, here's a node.js-based HTTP server
|
2
|
+
// doing roughly the same thing as http_server. Preliminary benchmarking shows
|
3
|
+
// the ruby version has a throughput (req/s) of about 2/3 of the JS version.
|
4
|
+
|
5
|
+
const http = require('http');
|
6
|
+
|
7
|
+
const MSG = 'Hello World';
|
8
|
+
|
9
|
+
const server = http.createServer((req, res) => {
|
10
|
+
// let requestCopy = {
|
11
|
+
// method: req.method,
|
12
|
+
// request_url: req.url,
|
13
|
+
// headers: req.headers
|
14
|
+
// };
|
15
|
+
|
16
|
+
// res.writeHead(200, { 'Content-Type': 'application/json' });
|
17
|
+
// res.end(JSON.stringify(requestCopy));
|
18
|
+
|
19
|
+
res.writeHead(200);
|
20
|
+
res.end(MSG)
|
21
|
+
});
|
22
|
+
|
23
|
+
server.listen(1235);
|
24
|
+
console.log('Listening on port 1235');
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
HTTPServer = import('../../lib/polyphony/http/server')
|
7
|
+
|
8
|
+
opts = { reuse_addr: true, dont_linger: true }
|
9
|
+
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
10
|
+
req.respond("Hello world!\n")
|
11
|
+
end
|
12
|
+
puts "pid: #{Process.pid}"
|
13
|
+
puts "Listening on port 1234..."
|
14
|
+
server.await
|
15
|
+
puts "bye bye"
|
16
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
require 'localhost/authority'
|
5
|
+
|
6
|
+
Polyphony = import('../../lib/polyphony')
|
7
|
+
HTTPServer = import('../../lib/polyphony/http/server')
|
8
|
+
|
9
|
+
opts = {
|
10
|
+
reuse_addr: true,
|
11
|
+
dont_linger: true,
|
12
|
+
}
|
13
|
+
runner = HTTPServer.listener('0.0.0.0', 1234, opts) do |req|
|
14
|
+
req.respond("Hello world!\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
puts "Listening on port 1234"
|
18
|
+
|
19
|
+
child_pids = []
|
20
|
+
4.times do
|
21
|
+
child_pids << Polyphony.fork do
|
22
|
+
puts "forked pid: #{Process.pid}"
|
23
|
+
spawn(&runner)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
child_pids.each { |pid| EV::Child.new(pid).await }
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
HTTPServer = import('../../lib/polyphony/http/server')
|
7
|
+
|
8
|
+
$throttler = throttle(1000)
|
9
|
+
opts = { reuse_addr: true, dont_linger: true }
|
10
|
+
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
11
|
+
$throttler.call { req.respond("Hello world!\n") }
|
12
|
+
end
|
13
|
+
puts "pid: #{Process.pid}"
|
14
|
+
puts "Listening on port 1234..."
|
15
|
+
server.await
|
16
|
+
puts "bye bye"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
STDOUT.sync = true
|
6
|
+
|
7
|
+
Polyphony = import('../../lib/polyphony')
|
8
|
+
HTTPServer = import('../../lib/polyphony/http/server')
|
9
|
+
Websocket = import('../../lib/polyphony/websocket')
|
10
|
+
|
11
|
+
def ws_handler(conn)
|
12
|
+
timer = spawn {
|
13
|
+
throttled_loop(1) {
|
14
|
+
conn << Time.now.to_s
|
15
|
+
}
|
16
|
+
}
|
17
|
+
while msg = conn.recv
|
18
|
+
# conn << "you said: #{msg}"
|
19
|
+
end
|
20
|
+
ensure
|
21
|
+
timer.stop
|
22
|
+
end
|
23
|
+
|
24
|
+
opts = {
|
25
|
+
reuse_addr: true,
|
26
|
+
dont_linger: true,
|
27
|
+
upgrade: {
|
28
|
+
websocket: Websocket.handler(&method(:ws_handler))
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
HTML = IO.read(File.join(__dir__, 'ws_page.html'))
|
33
|
+
|
34
|
+
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
35
|
+
req.respond(HTML, 'Content-Type' => 'text/html')
|
36
|
+
end
|
37
|
+
|
38
|
+
puts "pid: #{Process.pid}"
|
39
|
+
puts "Listening on port 1234..."
|
40
|
+
server.await
|
41
|
+
puts "bye bye"
|
42
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
|
7
|
+
spawn do
|
8
|
+
t0 = Time.now
|
9
|
+
io = Polyphony::Net.tcp_connect('google.com', 443, secure: true)
|
10
|
+
io.write("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")
|
11
|
+
reply = io.read(2**16)
|
12
|
+
puts "time: #{Time.now - t0}"
|
13
|
+
puts
|
14
|
+
puts reply
|
15
|
+
rescue => e
|
16
|
+
p e
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
require 'localhost/authority'
|
5
|
+
|
6
|
+
Polyphony = import('../../lib/polyphony')
|
7
|
+
HTTPServer = import('../../lib/polyphony/http/server')
|
8
|
+
|
9
|
+
spawn do
|
10
|
+
authority = Localhost::Authority.fetch
|
11
|
+
opts = {
|
12
|
+
reuse_addr: true,
|
13
|
+
dont_linger: true,
|
14
|
+
secure_context: authority.server_context
|
15
|
+
}
|
16
|
+
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
17
|
+
req.respond("Hello world!\n")
|
18
|
+
end
|
19
|
+
server.await
|
20
|
+
end
|
21
|
+
|
22
|
+
puts "pid: #{Process.pid}"
|
23
|
+
puts "Listening on port 1234..."
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
require 'localhost/authority'
|
5
|
+
|
6
|
+
STDOUT.sync = true
|
7
|
+
|
8
|
+
Polyphony = import('../../lib/polyphony')
|
9
|
+
HTTPServer = import('../../lib/polyphony/http/server')
|
10
|
+
Websocket = import('../../lib/polyphony/websocket')
|
11
|
+
|
12
|
+
def ws_handler(conn)
|
13
|
+
timer = spawn {
|
14
|
+
throttled_loop(1) {
|
15
|
+
conn << Time.now.to_s rescue nil
|
16
|
+
}
|
17
|
+
}
|
18
|
+
while msg = conn.recv
|
19
|
+
puts "msg: #{msg}"
|
20
|
+
# conn << "you said: #{msg}"
|
21
|
+
end
|
22
|
+
ensure
|
23
|
+
timer.stop
|
24
|
+
end
|
25
|
+
|
26
|
+
authority = Localhost::Authority.fetch
|
27
|
+
opts = {
|
28
|
+
reuse_addr: true,
|
29
|
+
dont_linger: true,
|
30
|
+
secure_context: authority.server_context,
|
31
|
+
upgrade: {
|
32
|
+
websocket: Websocket.handler(&method(:ws_handler))
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
HTML = IO.read(File.join(__dir__, 'wss_page.html'))
|
37
|
+
|
38
|
+
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
39
|
+
req.respond(HTML, 'Content-Type' => 'text/html')
|
40
|
+
end
|
41
|
+
|
42
|
+
puts "pid: #{Process.pid}"
|
43
|
+
puts "Listening on port 1234..."
|
44
|
+
server.await
|
45
|
+
puts "bye bye"
|
46
|
+
|