polyphony 0.13 → 0.14

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.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.gitbook.yaml +5 -0
  3. data/.gitignore +55 -0
  4. data/.rubocop.yml +49 -0
  5. data/CHANGELOG.md +13 -2
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +31 -0
  8. data/LICENSE +21 -0
  9. data/README.md +35 -18
  10. data/Rakefile +20 -0
  11. data/TODO.md +49 -0
  12. data/docs/getting-started/getting-started.md +10 -0
  13. data/docs/getting-started/tutorial.md +2 -0
  14. data/docs/summary.md +9 -0
  15. data/examples/core/cancel.rb +10 -0
  16. data/examples/core/channel_echo.rb +43 -0
  17. data/examples/core/enumerator.rb +14 -0
  18. data/examples/core/fork.rb +22 -0
  19. data/examples/core/genserver.rb +74 -0
  20. data/examples/core/lock.rb +20 -0
  21. data/examples/core/move_on.rb +11 -0
  22. data/examples/core/move_on_twice.rb +17 -0
  23. data/examples/core/move_on_with_ensure.rb +17 -0
  24. data/examples/core/multiple_async.rb +17 -0
  25. data/examples/core/nested_async.rb +18 -0
  26. data/examples/core/nested_cancel.rb +41 -0
  27. data/examples/core/nested_multiple_async.rb +19 -0
  28. data/examples/core/next_tick.rb +13 -0
  29. data/examples/core/pulse.rb +13 -0
  30. data/examples/core/resource.rb +29 -0
  31. data/examples/core/resource_cancel.rb +34 -0
  32. data/examples/core/resource_delegate.rb +32 -0
  33. data/examples/core/sleep.rb +9 -0
  34. data/examples/core/sleep2.rb +13 -0
  35. data/examples/core/spawn.rb +15 -0
  36. data/examples/core/spawn_cancel.rb +19 -0
  37. data/examples/core/spawn_error.rb +28 -0
  38. data/examples/core/supervisor.rb +22 -0
  39. data/examples/core/supervisor_with_cancel_scope.rb +24 -0
  40. data/examples/core/supervisor_with_error.rb +23 -0
  41. data/examples/core/supervisor_with_manual_move_on.rb +25 -0
  42. data/examples/core/thread.rb +30 -0
  43. data/examples/core/thread_cancel.rb +30 -0
  44. data/examples/core/thread_pool.rb +60 -0
  45. data/examples/core/throttle.rb +17 -0
  46. data/examples/fs/read.rb +37 -0
  47. data/examples/interfaces/pg_client.rb +38 -0
  48. data/examples/interfaces/pg_pool.rb +37 -0
  49. data/examples/interfaces/pg_query.rb +32 -0
  50. data/examples/interfaces/redis_channels.rb +119 -0
  51. data/examples/interfaces/redis_client.rb +21 -0
  52. data/examples/interfaces/redis_pubsub.rb +26 -0
  53. data/examples/interfaces/redis_pubsub_perf.rb +65 -0
  54. data/examples/io/config.ru +3 -0
  55. data/examples/io/echo_client.rb +22 -0
  56. data/examples/io/echo_server.rb +14 -0
  57. data/examples/io/echo_server_with_timeout.rb +33 -0
  58. data/examples/io/echo_stdin.rb +15 -0
  59. data/examples/io/happy_eyeballs.rb +32 -0
  60. data/examples/io/http_client.rb +19 -0
  61. data/examples/io/http_server.js +24 -0
  62. data/examples/io/http_server.rb +16 -0
  63. data/examples/io/http_server_forked.rb +27 -0
  64. data/examples/io/http_server_throttled.rb +16 -0
  65. data/examples/io/http_ws_server.rb +42 -0
  66. data/examples/io/https_client.rb +17 -0
  67. data/examples/io/https_server.rb +23 -0
  68. data/examples/io/https_wss_server.rb +46 -0
  69. data/examples/io/rack_server.rb +19 -0
  70. data/examples/io/rack_server_https.rb +24 -0
  71. data/examples/io/rack_server_https_forked.rb +32 -0
  72. data/examples/io/websocket_server.rb +33 -0
  73. data/examples/io/ws_page.html +34 -0
  74. data/examples/io/wss_page.html +34 -0
  75. data/examples/performance/perf_multi_snooze.rb +21 -0
  76. data/examples/performance/perf_snooze.rb +30 -0
  77. data/examples/performance/thread-vs-fiber/polyphony_server.rb +63 -0
  78. data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
  79. data/examples/streams/lines.rb +27 -0
  80. data/examples/streams/stdio.rb +18 -0
  81. data/ext/ev/async.c +168 -0
  82. data/ext/ev/child.c +169 -0
  83. data/ext/ev/ev.h +32 -0
  84. data/ext/ev/ev_ext.c +20 -0
  85. data/ext/ev/ev_module.c +222 -0
  86. data/ext/ev/io.c +405 -0
  87. data/ext/ev/libev.h +9 -0
  88. data/ext/ev/signal.c +119 -0
  89. data/ext/ev/timer.c +197 -0
  90. data/ext/libev/Changes +513 -0
  91. data/ext/libev/LICENSE +37 -0
  92. data/ext/libev/README +58 -0
  93. data/ext/libev/README.embed +3 -0
  94. data/ext/libev/ev.c +5214 -0
  95. data/ext/libev/ev.h +849 -0
  96. data/ext/libev/ev_epoll.c +285 -0
  97. data/ext/libev/ev_kqueue.c +218 -0
  98. data/ext/libev/ev_poll.c +151 -0
  99. data/ext/libev/ev_port.c +189 -0
  100. data/ext/libev/ev_select.c +316 -0
  101. data/ext/libev/ev_vars.h +204 -0
  102. data/ext/libev/ev_win32.c +162 -0
  103. data/ext/libev/ev_wrap.h +200 -0
  104. data/ext/libev/test_libev_win32.c +123 -0
  105. data/lib/polyphony.rb +7 -2
  106. data/lib/polyphony/core.rb +1 -1
  107. data/lib/polyphony/core/{coroutine.rb → coprocess.rb} +10 -10
  108. data/lib/polyphony/core/exceptions.rb +5 -5
  109. data/lib/polyphony/core/supervisor.rb +16 -16
  110. data/lib/polyphony/core/thread.rb +1 -1
  111. data/lib/polyphony/extensions/io.rb +43 -42
  112. data/lib/polyphony/extensions/kernel.rb +10 -34
  113. data/lib/polyphony/extensions/postgres.rb +3 -2
  114. data/lib/polyphony/extensions/redis.rb +1 -1
  115. data/lib/polyphony/extensions/socket.rb +8 -4
  116. data/lib/polyphony/extensions/ssl.rb +0 -54
  117. data/lib/polyphony/http/agent.rb +4 -10
  118. data/lib/polyphony/http/http1.rb +25 -25
  119. data/lib/polyphony/http/http1_request.rb +38 -26
  120. data/lib/polyphony/http/http2.rb +4 -5
  121. data/lib/polyphony/http/http2_request.rb +12 -18
  122. data/lib/polyphony/http/rack.rb +1 -3
  123. data/lib/polyphony/http/server.rb +9 -9
  124. data/lib/polyphony/net.rb +2 -2
  125. data/lib/polyphony/resource_pool.rb +5 -1
  126. data/lib/polyphony/version.rb +1 -1
  127. data/lib/polyphony/websocket.rb +52 -0
  128. data/polyphony.gemspec +31 -0
  129. data/test/test_coprocess.rb +131 -0
  130. data/test/test_core.rb +274 -0
  131. data/test/test_ev.rb +117 -0
  132. data/test/test_io.rb +38 -0
  133. metadata +113 -7
  134. data/lib/polyphony/core/async.rb +0 -36
  135. data/lib/polyphony/net_old.rb +0 -299
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f95ac584e1a686e3ff45ec50878bce9cc3ea0457f2894e0839e69c79621e3ab9
4
- data.tar.gz: 189eb3effd86a54ab16eec64cd4159ce851fdbd249a6b227c02ecfedfd35c987
3
+ metadata.gz: 78b1d2bf93b1562b6ef1010acdf4a30993d6fd8f40e001ab13a00606e0ed2137
4
+ data.tar.gz: ea0f410c483ee06da41e1acdd342f9fccadf87c51bbca258571d8f5d2c6048a5
5
5
  SHA512:
6
- metadata.gz: e935934c596936a1fcce5ecf5f87cb288245755bd4e08f9dce6fde16cffd486134f66bc209774418b1942b00c13e015f6bfa6c55026e1233fe7a4533aa3411b6
7
- data.tar.gz: a95b472caf17fa3c5a1f7afb8757e891e445a9afe7770131054a1db49c4a4529afa85acc723e1b621f4ae1200de4bfaef42a6a72b8002decbba4324be21ea3d5
6
+ metadata.gz: 70af3ec736856b611bd1d4242f6430761b83382f88239a31a1a7e4124fbe6804153e08d248c03c61510c272f9511cdf7f6f4ada277eab2cbd6809f2e41daaa39
7
+ data.tar.gz: 678dad06dab6f6dbbccc23e39ac45e8045b4fdf0b2ea29959fd34e243d9d0f19f624ef80a8022f7dde4790e080302f59b06e65ec3ca26c9fe5efc4a70856f2c2
@@ -0,0 +1,5 @@
1
+ root: ./docs/
2
+ structure:
3
+ readme: ../README.md
4
+ summary: ./summary.md
5
+ getting-started: ./getting-started.md
@@ -0,0 +1,55 @@
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
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
51
+
52
+ test.rb
53
+ .vscode
54
+
55
+ lib/ev_ext.bundle
@@ -0,0 +1,49 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
3
+ RubyInterpreters:
4
+ - ruby
5
+ Exclude:
6
+ - '**/*.gemspec'
7
+ - 'test/**/*.rb'
8
+ - 'examples/**/*.rb'
9
+ - 'Gemfile*'
10
+
11
+ Style/LambdaCall:
12
+ Enabled: false
13
+ # Style/ModuleFunction:
14
+ # Enabled: false
15
+ # Style/RegexpLiteral:
16
+ # Enabled: false
17
+
18
+ # Naming/MemoizedInstanceVariableName:
19
+ # Enabled: false
20
+
21
+ Style/Alias:
22
+ EnforcedStyle: prefer_alias_method
23
+
24
+ Style/SpecialGlobalVars:
25
+ Enabled: false
26
+
27
+ Style/ClassAndModuleChildren:
28
+ Enabled: false
29
+
30
+ Metrics/AbcSize:
31
+ Enabled: false
32
+
33
+ Style/MixinUsage:
34
+ Enabled: false
35
+
36
+ Style/MultilineBlockChain:
37
+ Enabled: false
38
+
39
+ Lint/RescueException:
40
+ Enabled: false
41
+
42
+ Lint/InheritException:
43
+ Enabled: false
44
+
45
+ Style/NumericPredicate:
46
+ Enabled: false
47
+
48
+ Style/TrivialAccessors:
49
+ Enabled: false
@@ -1,3 +1,14 @@
1
+ 0.14 2019-05-17
2
+ ---------------
3
+
4
+ * Use chunked encoding in HTTP 1 response
5
+ * Rewrite IO#read, #readpartial, #write in C (about 30% performance improvement)
6
+ * Add method delegation to `ResourcePool`
7
+ * Optimize PG::Connection#async_exec
8
+ * Fix Coprocess#cancel!
9
+ * Preliminary support for websocket (see `examples/io/http_ws_server.rb`)
10
+ * Rename `Coroutine` to `Coprocess`
11
+
1
12
  0.13 2019-01-05
2
13
  ---------------
3
14
 
@@ -18,8 +29,8 @@
18
29
 
19
30
  * Move reactor loop to secondary fiber, allow blocking operations on main
20
31
  fiber.
21
- * Example implementation of erlang-style generic server pattern (implement
22
- async API to a coroutine)
32
+ * Example implementation of erlang-style generic server pattern (implement async
33
+ API to a coroutine)
23
34
  * Implement coroutine mailboxes, Coroutine#<<, Coroutine#receive, Kernel.receive
24
35
  for message passing
25
36
  * Add Coroutine.current for getting current coroutine
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ polyphony (0.14)
5
+ http-2 (= 0.10.0)
6
+ http_parser.rb (= 0.6.0)
7
+ modulation (= 0.23)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ http-2 (0.10.0)
13
+ http_parser.rb (0.6.0)
14
+ localhost (1.1.4)
15
+ minitest (5.11.3)
16
+ modulation (0.23)
17
+ rake (12.3.2)
18
+ rake-compiler (1.0.5)
19
+ rake
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ localhost (= 1.1.4)
26
+ minitest (= 5.11.3)
27
+ polyphony!
28
+ rake-compiler (= 1.0.5)
29
+
30
+ BUNDLED WITH
31
+ 1.17.2
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 CHANGED
@@ -19,7 +19,7 @@ supports Linux and MacOS only. This software is currently at the alpha stage.
19
19
  Polyphony is a library for building concurrent applications in Ruby. Polyphony
20
20
  harnesses the power of
21
21
  [Ruby fibers](https://ruby-doc.org/core-2.5.1/Fiber.html) to provide a
22
- cooperative, sequential coroutine-based concurrency model. Under the hood,
22
+ cooperative, sequential coprocess-based concurrency model. Under the hood,
23
23
  Polyphony uses [libev](https://github.com/enki/libev) as a high-performance event
24
24
  reactor that provides timers, I/O watchers and other asynchronous event
25
25
  primitives.
@@ -31,16 +31,18 @@ takes care of context-switching automatically whenever a blocking call like
31
31
 
32
32
  ## Features
33
33
 
34
+ - **Full-blown, integrated, high-performance HTTP 1 / HTTP 2 / WebSocket server
35
+ with TLS/SSL termination and automatic ALPN protocol selection**.
34
36
  - Co-operative scheduling of concurrent tasks using Ruby fibers.
35
37
  - High-performance event reactor for handling I/O events and timers.
36
38
  - Natural, sequential programming style that makes it easy to reason about
37
39
  concurrent code.
38
- - Higher-order constructs for controlling the execution of concurrent code:
40
+ - Abstractions and constructs for controlling the execution of concurrent code:
39
41
  coprocesses, supervisors, cancel scopes, throttling, resource pools etc.
40
42
  - Code can use native networking classes and libraries, growing support for
41
43
  third-party gems such as `pg` and `redis`.
42
- - Comprehensive HTTP 1.0 / 1.1 / 2 client and server APIs.
43
- - Excellent performance and scalability characteristics, in terms of both
44
+ - HTTP 1 / HTTP 2 client
45
+ - Competitive performance and scalability characteristics, in terms of both
44
46
  throughput and memory consumption.
45
47
 
46
48
  ## Prior Art
@@ -89,12 +91,12 @@ end
89
91
  In the above example, both `sleep` calls will be executed concurrently, and thus
90
92
  the program will take approximately only 1 second to execute. Note the lack of
91
93
  any boilerplate relating to concurrency. Each `spawn` block starts a
92
- *coroutine*, and is executed in sequential manner.
94
+ *coprocess*, and is executed in sequential manner.
93
95
 
94
- > **Coroutines - the basic unit of concurrency**: In Polyphony, concurrent
95
- > operations take place inside coroutines. A `Coroutine` is executed on top of a
96
- > `Fiber`, which allows it to be suspended whenever a blocking operation is
97
- > called, and resumed once that operation has been completed. Coroutines offer
96
+ > **Coprocesses - the basic unit of concurrency**: In Polyphony, concurrent
97
+ > operations take place inside coprocesses. A `Coprocess` is executed on top of
98
+ > a `Fiber`, which allows it to be suspended whenever a blocking operation is
99
+ > called, and resumed once that operation has been completed. Coprocesses offer
98
100
  > significant advantages over threads - they consume only about 10KB, switching
99
101
  > between them is much faster than switching threads, and literally millions of
100
102
  > them can be spawned without affecting performance*. Besides, Ruby does not yet
@@ -113,7 +115,7 @@ require 'polyphony'
113
115
 
114
116
  server = TCPServer.open(1234)
115
117
  while client = server.accept
116
- # spawn starts a new coroutine on a separate fiber
118
+ # spawn starts a new coprocess on a separate fiber
117
119
  spawn {
118
120
  while data = client.read rescue nil
119
121
  client.write(data)
@@ -128,10 +130,10 @@ This example demonstrates several features of Polyphony:
128
130
  server. The result of `server.accept` is also a native `TCPSocket` object.
129
131
  There are no wrapper classes being used.
130
132
  - The only hint of the code being concurrent is the use of `Kernel#spawn`,
131
- which starts a new coroutine on a dedicated fiber. This allows serving
133
+ which starts a new coprocess on a dedicated fiber. This allows serving
132
134
  multiple clients at once. Whenever a blocking call is issued, such as
133
135
  `#accept` or `#read`, execution is *yielded* to the event loop, which will
134
- resume only those coroutines which are ready to be resumed.
136
+ resume only those coprocesses which are ready to be resumed.
135
137
  - Exception handling is done using the normal Ruby constructs `raise`, `rescue`
136
138
  and `ensure`. Exceptions never go unhandled (as might be the case with Ruby
137
139
  threads), and must be dealt with explicitly. An unhandled exception will cause
@@ -224,9 +226,9 @@ In order to facilitate writing concurrent code, Polyphony provides additional
224
226
  constructs that make it easier to spawn concurrent tasks and to control them.
225
227
 
226
228
  `CancelScope` - an abstraction used to cancel the execution of one or more
227
- coroutines or supervisors. It usually works by defining a timeout for the
229
+ coprocesses or supervisors. It usually works by defining a timeout for the
228
230
  completion of a task. Any blocking operation can be cancelled, including
229
- a coroutine or a supervisor. The developer may choose to cancel with or without
231
+ a coprocess or a supervisor. The developer may choose to cancel with or without
230
232
  an exception with `cancel` or `move_on`, respectively. Cancel scopes are
231
233
  typically started using `Kernel.cancel_after` and `Kernel.move_on`:
232
234
 
@@ -261,9 +263,24 @@ Pool = Polyphony::ResourcePool.new(limit: 5) {
261
263
  }
262
264
  ```
263
265
 
264
- `Supervisor` - a class used to control one or more `Coroutine`s. It can be used
265
- to start, stop and restart multiple coroutines. A supervisor can also be
266
- used for awaiting the completion of multiple coroutines. It is usually started
266
+ You can also call arbitrary methods on the resource pool, which will be
267
+ delegated to the resource using `#method_missing`:
268
+
269
+ ```ruby
270
+ # up to 5 concurrent connections
271
+ Pool = Polyphony::ResourcePool.new(limit: 5) {
272
+ # the block sets up the resource
273
+ PG.connect(...)
274
+ }
275
+
276
+ 1000.times {
277
+ spawn { p Pool.query('select 1') }
278
+ }
279
+ ```
280
+
281
+ `Supervisor` - a class used to control one or more `Coprocess`s. It can be used
282
+ to start, stop and restart multiple coprocesses. A supervisor can also be
283
+ used for awaiting the completion of multiple coprocesses. It is usually started
267
284
  using `Kernel.supervise`:
268
285
 
269
286
  ```ruby
@@ -289,7 +306,7 @@ result = Polyphony::ThreadPool.process { long_running_process }
289
306
  `Throttler` - a mechanism for throttling an arbitrary task, such as sending of
290
307
  emails, or crawling a website. A throttler is normally created using
291
308
  `Kernel.throttle`, and can even be used to throttle operations across multiple
292
- coroutines:
309
+ coprocesses:
293
310
 
294
311
  ```ruby
295
312
  server = Net.tcp_listen(1234)
@@ -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("ev_ext") do |ext|
10
+ ext.ext_dir = "ext/ev"
11
+ end
12
+
13
+ task :default => [:compile, :test]
14
+ task :test do
15
+ Dir.glob('./test/test_*.rb').each { |file| require(file) }
16
+ end
17
+
18
+ # task default: %w[compile]# spec rubocop]
19
+
20
+ CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
data/TODO.md ADDED
@@ -0,0 +1,49 @@
1
+ ## Testing
2
+
3
+ - test IO
4
+ - test TCP server / client
5
+ - test thread / thread_pool modules
6
+
7
+ ## UDP socket
8
+
9
+ ```ruby
10
+ socket = UDPSocket.new
11
+ socket.bind("127.0.0.1", 1234)
12
+
13
+ socket.send "message-to-self", 0, "127.0.0.1", 1234
14
+ p socket.recvfrom(10)
15
+ #=> ["message-to", ["AF_INET", 4913, "localhost", "127.0.0.1"]]
16
+ ```
17
+
18
+ ## DNS client
19
+
20
+ ```ruby
21
+ ip_address = DNS.lookup('google.com', 'A')
22
+ ```
23
+
24
+ Prior art:
25
+
26
+ - https://github.com/alexdalitz/dnsruby
27
+ - https://github.com/eventmachine/eventmachine/blob/master/lib/em/resolver.rb
28
+ - https://github.com/gmodarelli/em-resolv-replace/blob/master/lib/em-dns-resolver.rb
29
+ - https://github.com/socketry/async-dns
30
+
31
+ ### DNS server
32
+
33
+ ```ruby
34
+ Server = import('../../lib/polyphony/dns/server')
35
+
36
+ server = Server.new do |transaction|
37
+ puts "got query from #{transaction.info[:client_ip_address]}"
38
+ transaction.questions.each do |q|
39
+ respond(transaction, q[:domain], q[:resource_class])
40
+ end
41
+ end
42
+
43
+ server.listen(port: 5300)
44
+ puts "listening on port 5300"
45
+ ```
46
+
47
+ Prior art:
48
+
49
+ - https://github.com/socketry/async-dns
@@ -0,0 +1,10 @@
1
+ # Installing
2
+
3
+ ## Installing
4
+
5
+ ```bash
6
+ $ gem install polyphony
7
+ ```
8
+
9
+ ## Tutorial
10
+
@@ -0,0 +1,2 @@
1
+ # Tutorial
2
+
@@ -0,0 +1,9 @@
1
+ # Table of contents
2
+
3
+ * [Introduction](../README.md)
4
+
5
+ ## Getting Started
6
+
7
+ * [Installing](getting-started/getting-started.md)
8
+ * [Tutorial](getting-started/tutorial.md)
9
+
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'modulation'
4
+
5
+ Polyphony = import('../../lib/polyphony')
6
+
7
+ puts "going to sleep..."
8
+ cancel_after(1) do
9
+ sleep(60)
10
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'modulation'
4
+
5
+ Polyphony = import('../../lib/polyphony')
6
+
7
+ def echo(rchan, wchan)
8
+ puts "start echoer"
9
+ while msg = rchan.receive
10
+ wchan << "you said: #{msg}"
11
+ end
12
+ ensure
13
+ puts "echoer stopped"
14
+ end
15
+
16
+ chan1, chan2 = Polyphony::Channel.new, Polyphony::Channel.new
17
+
18
+ echoer = spawn { echo(chan1, chan2) }
19
+
20
+ spawn do
21
+ puts "start receiver"
22
+ while msg = chan2.receive
23
+ puts msg
24
+ $main.resume if msg =~ /world/
25
+ end
26
+ ensure
27
+ puts "receiver stopped"
28
+ end
29
+
30
+ $main = spawn do
31
+ t0 = Time.now
32
+ puts "send hello"
33
+ chan1 << "hello"
34
+ puts "send world"
35
+ chan1 << "world"
36
+
37
+ suspend
38
+
39
+ puts "closing channels"
40
+ chan1.close
41
+ chan2.close
42
+ puts "done #{Time.now - t0}"
43
+ end