polyphony 0.23 → 0.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile.lock +4 -10
  4. data/README.md +0 -4
  5. data/TODO.md +5 -56
  6. data/docs/README.md +4 -7
  7. data/examples/core/{channel_echo.rb → xx-channels.rb} +0 -0
  8. data/examples/core/{defer.rb → xx-deferring-an-operation.rb} +0 -0
  9. data/examples/core/{genserver.rb → xx-erlang-style-genserver.rb} +2 -2
  10. data/examples/core/{fork.rb → xx-forking.rb} +2 -0
  11. data/examples/core/xx-move_on.rb +23 -0
  12. data/examples/core/{pulse.rb → xx-recurrent-timer.rb} +3 -2
  13. data/examples/core/{resource_cancel.rb → xx-resource_cancel.rb} +1 -2
  14. data/examples/core/{resource_delegate.rb → xx-resource_delegate.rb} +0 -0
  15. data/examples/core/{wait_for_signal.rb → xx-signals.rb} +0 -0
  16. data/examples/core/{sleep.rb → xx-sleeping.rb} +0 -0
  17. data/examples/core/{spin_error_backtrace.rb → xx-spin_error_backtrace.rb} +5 -2
  18. data/examples/core/{supervisor.rb → xx-supervisors.rb} +0 -0
  19. data/examples/core/{thread_cancel.rb → xx-thread_cancel.rb} +0 -0
  20. data/examples/core/{thread_pool.rb → xx-thread_pool.rb} +0 -0
  21. data/examples/core/{throttle.rb → xx-throttling.rb} +0 -0
  22. data/examples/core/{timeout.rb → xx-timeout.rb} +0 -0
  23. data/examples/core/{lock.rb → xx-using-a-mutex.rb} +0 -0
  24. data/examples/io/{backticks.rb → xx-backticks.rb} +0 -0
  25. data/examples/io/{echo_client.rb → xx-echo_client.rb} +0 -1
  26. data/examples/io/{echo_client_from_stdin.rb → xx-echo_client_from_stdin.rb} +0 -1
  27. data/examples/io/{echo_pipe.rb → xx-echo_pipe.rb} +0 -0
  28. data/examples/io/{echo_server.rb → xx-echo_server.rb} +0 -0
  29. data/examples/io/{echo_server_with_timeout.rb → xx-echo_server_with_timeout.rb} +0 -0
  30. data/examples/io/{echo_stdin.rb → xx-echo_stdin.rb} +0 -0
  31. data/examples/io/xx-httparty.rb +13 -0
  32. data/examples/io/{irb.rb → xx-irb.rb} +0 -0
  33. data/examples/io/{net-http.rb → xx-net-http.rb} +0 -0
  34. data/examples/io/{open.rb → xx-open.rb} +0 -1
  35. data/examples/io/{system.rb → xx-system.rb} +0 -0
  36. data/examples/io/{tcpserver.rb → xx-tcpserver.rb} +0 -0
  37. data/examples/io/{tcpsocket.rb → xx-tcpsocket.rb} +0 -1
  38. data/examples/{fs/read.rb → performance/fs_read.rb} +0 -0
  39. data/examples/{core → performance}/mem-usage.rb +1 -0
  40. data/examples/performance/multi_snooze.rb +2 -0
  41. data/examples/performance/snooze.rb +2 -0
  42. data/examples/performance/thread-vs-fiber/polyphony_server.rb +5 -3
  43. data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -1
  44. data/examples/{io/httparty_multi.rb → performance/thread-vs-fiber/xx-httparty_multi.rb} +16 -13
  45. data/examples/{io/httparty_threaded.rb → performance/thread-vs-fiber/xx-httparty_threaded.rb} +2 -2
  46. data/examples/performance/thread.rb +27 -0
  47. data/examples/{core → performance}/thread_pool_perf.rb +0 -0
  48. data/ext/gyro/extconf.rb +1 -0
  49. data/lib/polyphony/extensions/core.rb +0 -5
  50. data/lib/polyphony/version.rb +1 -1
  51. data/polyphony.gemspec +3 -9
  52. metadata +59 -167
  53. data/bin/poly +0 -11
  54. data/examples/core/cancel.rb +0 -13
  55. data/examples/core/enumerator.rb +0 -15
  56. data/examples/core/error_bubbling.rb +0 -35
  57. data/examples/core/fiber_error.rb +0 -9
  58. data/examples/core/fiber_error_with_backtrace.rb +0 -73
  59. data/examples/core/move_on.rb +0 -11
  60. data/examples/core/move_on_twice.rb +0 -16
  61. data/examples/core/move_on_with_ensure.rb +0 -13
  62. data/examples/core/move_on_with_value.rb +0 -14
  63. data/examples/core/multiple_spin.rb +0 -18
  64. data/examples/core/nested_cancel.rb +0 -40
  65. data/examples/core/nested_multiple_spin.rb +0 -20
  66. data/examples/core/nested_spin.rb +0 -19
  67. data/examples/core/pingpong.rb +0 -21
  68. data/examples/core/resource.rb +0 -30
  69. data/examples/core/sleep_spin.rb +0 -21
  70. data/examples/core/snooze.rb +0 -32
  71. data/examples/core/spin_error.rb +0 -17
  72. data/examples/core/spin_uncaught_error.rb +0 -16
  73. data/examples/core/supervisor_with_cancel_scope.rb +0 -23
  74. data/examples/core/supervisor_with_error.rb +0 -24
  75. data/examples/core/supervisor_with_manual_move_on.rb +0 -23
  76. data/examples/core/suspend.rb +0 -13
  77. data/examples/core/thread.rb +0 -27
  78. data/examples/http/config.ru +0 -7
  79. data/examples/http/cuba.ru +0 -22
  80. data/examples/http/happy_eyeballs.rb +0 -37
  81. data/examples/http/http2_raw.rb +0 -135
  82. data/examples/http/http_client.rb +0 -28
  83. data/examples/http/http_get.rb +0 -33
  84. data/examples/http/http_parse_experiment.rb +0 -123
  85. data/examples/http/http_proxy.rb +0 -83
  86. data/examples/http/http_server.js +0 -24
  87. data/examples/http/http_server.rb +0 -28
  88. data/examples/http/http_server_forked.rb +0 -29
  89. data/examples/http/http_server_graceful.rb +0 -27
  90. data/examples/http/http_server_simple.rb +0 -11
  91. data/examples/http/http_server_throttled.rb +0 -15
  92. data/examples/http/http_ws_server.rb +0 -37
  93. data/examples/http/https_raw_client.rb +0 -12
  94. data/examples/http/https_server.rb +0 -22
  95. data/examples/http/https_wss_server.rb +0 -39
  96. data/examples/http/rack_server.rb +0 -12
  97. data/examples/http/rack_server_https.rb +0 -19
  98. data/examples/http/rack_server_https_forked.rb +0 -27
  99. data/examples/http/websocket_secure_server.rb +0 -27
  100. data/examples/http/websocket_server.rb +0 -24
  101. data/examples/http/ws_page.html +0 -34
  102. data/examples/http/wss_page.html +0 -34
  103. data/examples/io/cat.rb +0 -12
  104. data/examples/io/httparty.rb +0 -10
  105. data/examples/io/io_read.rb +0 -9
  106. data/lib/ev_ext.bundle +0 -0
  107. data/lib/polyphony/http.rb +0 -16
  108. data/lib/polyphony/http/client/agent.rb +0 -131
  109. data/lib/polyphony/http/client/http1.rb +0 -129
  110. data/lib/polyphony/http/client/http2.rb +0 -180
  111. data/lib/polyphony/http/client/response.rb +0 -32
  112. data/lib/polyphony/http/client/site_connection_manager.rb +0 -109
  113. data/lib/polyphony/http/server.rb +0 -49
  114. data/lib/polyphony/http/server/http1.rb +0 -268
  115. data/lib/polyphony/http/server/http2.rb +0 -78
  116. data/lib/polyphony/http/server/http2_stream.rb +0 -136
  117. data/lib/polyphony/http/server/rack.rb +0 -64
  118. data/lib/polyphony/http/server/request.rb +0 -118
  119. data/lib/polyphony/websocket.rb +0 -59
  120. data/test/test_http_server.rb +0 -313
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42975a9e638525d2264fbddea88ee0756fb7e7dbc5c0585c033b71a06a27711c
4
- data.tar.gz: 2c233b91c02d60e1dc40fbacb1dbade17c591a9ddede854e71dc7b2a840dcfd0
3
+ metadata.gz: 8a8da629de739b6091367c7220fd4a69dd83d7c78eb6d8c55c67385c8ca3edb2
4
+ data.tar.gz: 351f78d8b9635b6bc2c9838d652781a66009554287cfb5486c9fe0a0748ed6d6
5
5
  SHA512:
6
- metadata.gz: 339373f341a10fa68bec7d39588407519c12e17f9b02f774b9179af9b682512c156aa254cac116d4f60d1528e4dae21cfe220e71bf998787c0f1b55c244ef959
7
- data.tar.gz: 429a5960bbc3a38d23282ab1a8339b1ae556832fd098e34ae1a63fca36f4bc9f15f8996a715c70ac3363e01ea1858c2cf9de6b9296e90cf7f6a6c8a79f42c48c
6
+ metadata.gz: 768ed2703dd01653e5c71c2d17799b0c42fd9eb03f382dd3e4d3e4a337f7055d7a68643f479160febd3aa9412a9b66ccf0adf79f1608882ef0d61b625c8f7ed2
7
+ data.tar.gz: eab163c7ce680640def7fe6971359969202e6cb53238e8006c479e158c9b488bf73a2e575008a94cee1320fcf6899276da85df33d2fb00f97fa8133ad8fc3f06
@@ -1,3 +1,10 @@
1
+ 0.24 2020-01-08
2
+ ---------------
3
+
4
+ * Extract HTTP code into separate polyphony-http gem
5
+ * Cull core, io examples
6
+ * Remove `SIGINT` handler
7
+
1
8
  0.23 2020-01-07
2
9
  ---------------
3
10
 
@@ -1,11 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.23)
5
- http-2 (= 0.10.0)
6
- http_parser.rb (= 0.6.0)
7
- modulation (~> 0.25)
8
- rack
4
+ polyphony (0.24)
5
+ modulation (~> 1.0)
9
6
 
10
7
  GEM
11
8
  remote: https://rubygems.org/
@@ -14,7 +11,6 @@ GEM
14
11
  builder (3.2.4)
15
12
  docile (1.3.2)
16
13
  hiredis (0.6.3)
17
- http-2 (0.10.0)
18
14
  http_parser.rb (0.6.0)
19
15
  httparty (0.17.0)
20
16
  mime-types (~> 3.0)
@@ -30,10 +26,9 @@ GEM
30
26
  builder
31
27
  minitest (>= 5.0)
32
28
  ruby-progressbar
33
- modulation (0.34)
29
+ modulation (1.0)
34
30
  multi_xml (0.6.0)
35
31
  pg (1.1.3)
36
- rack (2.0.8)
37
32
  rake (13.0.1)
38
33
  rake-compiler (1.0.5)
39
34
  rake
@@ -44,13 +39,13 @@ GEM
44
39
  json (>= 1.8, < 3)
45
40
  simplecov-html (~> 0.10.0)
46
41
  simplecov-html (0.10.2)
47
- websocket (1.2.8)
48
42
 
49
43
  PLATFORMS
50
44
  ruby
51
45
 
52
46
  DEPENDENCIES
53
47
  hiredis (= 0.6.3)
48
+ http_parser.rb (~> 0.6.0)
54
49
  httparty (= 0.17.0)
55
50
  localhost (= 1.1.4)
56
51
  minitest (= 5.11.3)
@@ -60,7 +55,6 @@ DEPENDENCIES
60
55
  rake-compiler (= 1.0.5)
61
56
  redis (= 4.1.0)
62
57
  simplecov (= 0.17.1)
63
- websocket (= 1.2.8)
64
58
 
65
59
  BUNDLED WITH
66
60
  2.1.3
data/README.md CHANGED
@@ -13,9 +13,6 @@ Polyphony makes it possible to use normal Ruby built-in classes like `IO`, and `
13
13
 
14
14
  ## Features
15
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
16
  * Co-operative scheduling of concurrent tasks using Ruby fibers.
20
17
  * High-performance event reactor for handling I/O events and timers.
21
18
  * Natural, sequential programming style that makes it easy to reason about
@@ -25,7 +22,6 @@ Polyphony makes it possible to use normal Ruby built-in classes like `IO`, and `
25
22
  * Code can use native networking classes and libraries, growing support for
26
23
  third-party gems such as `pg` and `redis`.
27
24
  * Use stdlib classes such as `TCPServer`, `TCPSocket` and
28
- * HTTP 1 / HTTP 2 client agent with persistent connections.
29
25
  * Competitive performance and scalability characteristics, in terms of both
30
26
  throughput and memory consumption.
31
27
 
data/TODO.md CHANGED
@@ -1,54 +1,8 @@
1
- # HTTP Client Agent
1
+ ## 0.25 Move Other interface code into separate gem
2
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.24 Move HTTP code into separate gem
47
-
48
- - Pull out HTTP/websocket code, put into new `polyphony-http` gem
49
3
  - Pull out redis/postgres code, put into new `polyphony-contrib` gem
50
4
 
51
- ## 0.25 Full Rack adapter implementation
5
+ ## 0.26 Full Rack adapter implementation
52
6
 
53
7
  - Work better mechanism supervising multiple coprocesses (`when_done` feels a
54
8
  bit hacky)
@@ -56,21 +10,16 @@ end
56
10
  - Homogenize HTTP 1 and HTTP 2 headers - upcase ? downcase ?
57
11
  - find some demo Rack apps and test with Polyphony
58
12
 
59
- ## 0.26 Working Sinatra application
13
+ ## 0.27 Working Sinatra application
60
14
 
61
15
  - app with database access (postgresql)
62
16
  - benchmarks!
63
17
 
64
- ## 0.27 Support for multi-threading
18
+ ## 0.28 Support for multi-threading
65
19
 
66
20
  - Separate event loop for each thread
67
21
 
68
- ## 0.28 Testing
69
-
70
- - test thread / thread_pool modules
71
- - report test coverage
72
-
73
- ## 0.29 Documentation
22
+ ## 0.29 Testing && Docs
74
23
 
75
24
  ## 0.30 Integration
76
25
 
@@ -1,8 +1,8 @@
1
1
  # Polyphony - Easy Concurrency for Ruby
2
2
 
3
- > 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.
4
-
5
- ## What is Polyphony
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
6
 
7
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
8
 
@@ -10,14 +10,12 @@ Polyphony makes it possible to use normal Ruby built-in classes like `IO`, and `
10
10
 
11
11
  ## Features
12
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
13
  * Co-operative scheduling of concurrent tasks using Ruby fibers.
15
14
  * High-performance event reactor for handling I/O events and timers.
16
15
  * Natural, sequential programming style that makes it easy to reason about concurrent code.
17
16
  * Abstractions and constructs for controlling the execution of concurrent code: coprocesses, supervisors, cancel scopes, throttling, resource pools etc.
18
17
  * Code can use native networking classes and libraries, growing support for third-party gems such as `pg` and `redis`.
19
18
  * Use stdlib classes such as `TCPServer` and `TCPSocket` and `Net::HTTP`.
20
- * HTTP 1 / HTTP 2 client agent with persistent connections.
21
19
  * Competitive performance and scalability characteristics, in terms of both throughput and memory consumption.
22
20
 
23
21
  ## Prior Art
@@ -35,5 +33,4 @@ To learn more about using Polyphony to build concurrent applications, read the t
35
33
 
36
34
  ## Contributing to Polyphony
37
35
 
38
- If there's some blocking behavior you'd like to see handled by Polyphony, please let us know by [creating an issue](https://github.com/digital-fabric/polyphony/issues). Our aim is for Polyphony to be a comprehensive solution for writing concurrent Ruby programs.
39
-
36
+ 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.
@@ -65,14 +65,14 @@ module Map
65
65
  end
66
66
  end
67
67
 
68
- map_server = GenServer.start(Map, foo: :bar)
68
+ map_server = GenServer.start(Map, {foo: :bar})
69
69
 
70
70
  puts 'getting value from map server'
71
71
  v = map_server.get(:foo)
72
72
  puts "value: #{v.inspect}"
73
73
 
74
74
  puts 'putting value in map server'
75
- map_server.put!(:foo, 42)
75
+ map_server.put!(:foo, :baz)
76
76
 
77
77
  puts 'getting value from map server'
78
78
  v = map_server.get(:foo)
@@ -13,6 +13,8 @@ pid = Polyphony.fork do
13
13
  sleep 1
14
14
  puts 'child woke up 1'
15
15
  end
16
+
17
+ suspend
16
18
  end
17
19
 
18
20
  puts "got child pid #{pid}"
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ Exception.__disable_sanitized_backtrace__ = true
6
+
7
+ puts 'going to sleep...'
8
+ move_on_after(1) do
9
+ sleep 60
10
+ puts 'woke up'
11
+ end
12
+
13
+ puts 'going to sleep...'
14
+ move_on_after(0.5) do
15
+ t0 = Time.now
16
+ sleep(60)
17
+ ensure
18
+ puts 'woke up'
19
+ end
20
+
21
+ puts 'going to sleep...'
22
+ value = move_on_after(1, with_value: :bar) { sleep 60 }
23
+ puts "got value #{value.inspect}"
@@ -5,7 +5,8 @@ require 'polyphony'
5
5
 
6
6
  move_on_after(3) do
7
7
  puts 'Start...'
8
- pulser = pulse(1)
9
- puts Time.now while pulser.await
8
+ every(1) do
9
+ puts Time.now
10
+ end
10
11
  end
11
12
  puts 'done!'
@@ -5,7 +5,7 @@ require 'polyphony'
5
5
 
6
6
  resource_count = 0
7
7
  Pool = Polyphony::ResourcePool.new(limit: 3) do
8
- :"resource#{resource_count += 1}"
8
+ +"resource#{resource_count += 1}"
9
9
  end
10
10
 
11
11
  def user(number)
@@ -13,7 +13,6 @@ def user(number)
13
13
  Polyphony::CancelScope.new(timeout: 0.2) do |scope|
14
14
  scope.on_cancel { puts "#{number} (cancelled)" }
15
15
  Pool.acquire do |r|
16
- scope.disable
17
16
  puts "#{number} #{r.inspect} >"
18
17
  sleep(0.1 + rand * 0.2)
19
18
  puts "#{number} #{r.inspect} <"
@@ -8,8 +8,8 @@ def error(t)
8
8
  end
9
9
 
10
10
  def deferred_error(t)
11
- snooze
12
- de2(t)
11
+ puts "deferred_error"
12
+ defer { de2(t) }
13
13
  end
14
14
 
15
15
  def de2(t)
@@ -28,3 +28,6 @@ spin do
28
28
  end.await
29
29
  end.await
30
30
  end.await
31
+
32
+ suspend
33
+ suspend
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
- require 'polyphony/extensions/backtrace'
6
5
 
7
6
  socket = Polyphony::Net.tcp_connect('127.0.0.1', 1234)
8
7
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
- require 'polyphony/extensions/backtrace'
6
5
 
7
6
  socket = Polyphony::Net.tcp_connect('127.0.0.1', 1234)
8
7
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'httparty'
6
+
7
+ timer = spin { throttled_loop(100) {
8
+ STDOUT << '.'
9
+ } }
10
+
11
+ res = HTTParty.get('http://worldtimeapi.org/api/timezone/Europe/Paris')
12
+ puts res
13
+ timer.stop
File without changes
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
- require 'irb'
6
5
 
7
6
  stdin = IO.open(STDIN.to_i)
8
7
 
File without changes
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
- require 'polyphony/extensions/backtrace'
6
5
 
7
6
  socket = TCPSocket.new('google.com', 80)
8
7
 
@@ -24,6 +24,7 @@ def calculate_coprocess_memory_cost(count)
24
24
  GC.disable
25
25
  rss0 = mem_usage
26
26
  count.times { spin { :foo } }
27
+ snooze
27
28
  rss1 = mem_usage
28
29
  GC.start
29
30
  cost = (rss1 - rss0).to_f / count
@@ -20,6 +20,8 @@ def bm(fibers, iterations)
20
20
  puts "#{[fibers, iterations].inspect} count: #{count} #{count / dt.to_f}/s"
21
21
  end
22
22
 
23
+ GC.disable
24
+
23
25
  bm(1, 1_000_000)
24
26
  bm(10, 100_000)
25
27
  bm(100, 10_000)
@@ -5,6 +5,8 @@ require 'polyphony'
5
5
 
6
6
  X = 1_000_000
7
7
 
8
+ GC.disable
9
+
8
10
  STDOUT << 'Fiber.yield: '
9
11
  f = Fiber.new do
10
12
  loop { Fiber.yield }
@@ -18,7 +18,7 @@ class Http::Parser
18
18
  end
19
19
  end
20
20
 
21
- async def handle_client(socket)
21
+ def handle_client(socket)
22
22
  parser = Http::Parser.new
23
23
  req = nil
24
24
  parser.on_message_complete = proc do |env|
@@ -47,12 +47,12 @@ def handle_request(client, parser)
47
47
  end
48
48
 
49
49
  spin do
50
- server = TCPServer.open(1234)
50
+ server = TCPServer.open('0.0.0.0', 1234)
51
51
  puts "listening on port 1234"
52
52
 
53
53
  loop do
54
54
  client = server.accept
55
- coproc handle_client(client)
55
+ spin { handle_client(client) }
56
56
  end
57
57
  rescue Exception => e
58
58
  puts "uncaught exception: #{e.inspect}"
@@ -60,3 +60,5 @@ rescue Exception => e
60
60
  exit!
61
61
  server.close
62
62
  end
63
+
64
+ suspend