mt-libuv 4.1.0
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 +7 -0
- data/.gitignore +22 -0
- data/.gitmodules +6 -0
- data/.rspec +1 -0
- data/.travis.yml +24 -0
- data/Gemfile +9 -0
- data/LICENSE +24 -0
- data/README.md +195 -0
- data/Rakefile +31 -0
- data/ext/README.md +6 -0
- data/ext/Rakefile +28 -0
- data/lib/mt-libuv/async.rb +51 -0
- data/lib/mt-libuv/check.rb +59 -0
- data/lib/mt-libuv/coroutines.rb +79 -0
- data/lib/mt-libuv/dns.rb +98 -0
- data/lib/mt-libuv/error.rb +88 -0
- data/lib/mt-libuv/ext/ext.rb +322 -0
- data/lib/mt-libuv/ext/platform/darwin_x64.rb +61 -0
- data/lib/mt-libuv/ext/platform/unix.rb +69 -0
- data/lib/mt-libuv/ext/platform/windows.rb +83 -0
- data/lib/mt-libuv/ext/tasks/mac.rb +24 -0
- data/lib/mt-libuv/ext/tasks/unix.rb +42 -0
- data/lib/mt-libuv/ext/tasks/win.rb +29 -0
- data/lib/mt-libuv/ext/tasks.rb +27 -0
- data/lib/mt-libuv/ext/types.rb +253 -0
- data/lib/mt-libuv/fiber_pool.rb +83 -0
- data/lib/mt-libuv/file.rb +309 -0
- data/lib/mt-libuv/filesystem.rb +263 -0
- data/lib/mt-libuv/fs_event.rb +37 -0
- data/lib/mt-libuv/handle.rb +108 -0
- data/lib/mt-libuv/idle.rb +59 -0
- data/lib/mt-libuv/mixins/accessors.rb +41 -0
- data/lib/mt-libuv/mixins/assertions.rb +25 -0
- data/lib/mt-libuv/mixins/fs_checks.rb +96 -0
- data/lib/mt-libuv/mixins/listener.rb +69 -0
- data/lib/mt-libuv/mixins/net.rb +42 -0
- data/lib/mt-libuv/mixins/resource.rb +30 -0
- data/lib/mt-libuv/mixins/stream.rb +276 -0
- data/lib/mt-libuv/pipe.rb +217 -0
- data/lib/mt-libuv/prepare.rb +59 -0
- data/lib/mt-libuv/q.rb +475 -0
- data/lib/mt-libuv/reactor.rb +567 -0
- data/lib/mt-libuv/signal.rb +62 -0
- data/lib/mt-libuv/spawn.rb +113 -0
- data/lib/mt-libuv/tcp.rb +465 -0
- data/lib/mt-libuv/timer.rb +107 -0
- data/lib/mt-libuv/tty.rb +42 -0
- data/lib/mt-libuv/udp.rb +302 -0
- data/lib/mt-libuv/version.rb +5 -0
- data/lib/mt-libuv/work.rb +86 -0
- data/lib/mt-libuv.rb +80 -0
- data/mt-libuv.gemspec +62 -0
- data/spec/async_spec.rb +67 -0
- data/spec/coroutines_spec.rb +121 -0
- data/spec/cpu_spec.rb +10 -0
- data/spec/defer_spec.rb +906 -0
- data/spec/dns_spec.rb +110 -0
- data/spec/dsl_spec.rb +43 -0
- data/spec/filesystem_spec.rb +270 -0
- data/spec/idle_spec.rb +44 -0
- data/spec/pipe_spec.rb +151 -0
- data/spec/spawn_spec.rb +119 -0
- data/spec/tcp_spec.rb +272 -0
- data/spec/test.sh +4 -0
- data/spec/test_fail.sh +3 -0
- data/spec/test_read.sh +3 -0
- data/spec/timer_spec.rb +14 -0
- data/spec/udp_spec.rb +73 -0
- data/spec/zen_spec.rb +34 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 55ed231748185b35f9e88cb285439d40bc75172b4c0133badf659b6a70be6969
|
4
|
+
data.tar.gz: 51622861571ac5be5a93e06ee86e64f5c92ed3b4bbd37236717999694c60b5cc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3e1d126ffe76a1eb330bdb3203293088d0826270151c7e15cd6db1c09874304a2d745f5ba5909ab48268d9775a909da75f920e799a2c291229a280c1463099da
|
7
|
+
data.tar.gz: c30c8f7243fc969d1ae70b1e587a89f31ec49f552a085eccdf45ab031989f27731423373eb633a4e11f7def2d7ab4f2b3874ba2599d73f77c35a94a4f950494a
|
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--format progress
|
data/.travis.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- ruby-2.3.5
|
4
|
+
- ruby-2.4.2
|
5
|
+
- ruby-head
|
6
|
+
- rubinius
|
7
|
+
- jruby-9.1.13.0
|
8
|
+
- jruby-head
|
9
|
+
branches:
|
10
|
+
only:
|
11
|
+
- master
|
12
|
+
before_install:
|
13
|
+
- git submodule update --init --recursive
|
14
|
+
- gem install ffi
|
15
|
+
before_script:
|
16
|
+
- rake compile
|
17
|
+
sudo: false
|
18
|
+
matrix:
|
19
|
+
allow_failures:
|
20
|
+
- rvm: jruby-head
|
21
|
+
- rvm: ruby-head
|
22
|
+
- rvm: rubinius
|
23
|
+
sudo: required
|
24
|
+
dist: trusty
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Copyright (c) 2004-2013 Cotag Media
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is furnished
|
8
|
+
to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
20
|
+
|
21
|
+
===
|
22
|
+
|
23
|
+
This license applies to all parts of uvrb (Ruby FFI bindings for libuv only)
|
24
|
+
Libuv itself [is using Node license](https://github.com/joyent/libuv/blob/master/LICENSE)
|
data/README.md
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
# Libuv FFI bindings for Ruby
|
2
|
+
|
3
|
+
[](https://travis-ci.org/cotag/libuv)
|
4
|
+
|
5
|
+
[Libuv](https://github.com/libuv/libuv) is a cross platform asynchronous IO implementation that powers NodeJS. It supports sockets, both UDP and TCP, filesystem watch, TTY, Pipes and other asynchronous primitives like timer, check, prepare and idle.
|
6
|
+
|
7
|
+
The Libuv gem contains Libuv and a Ruby wrapper that implements [pipelined promises](http://en.wikipedia.org/wiki/Futures_and_promises#Promise_pipelining) for asynchronous flow control and [coroutines](http://en.wikipedia.org/wiki/Coroutine) / [futures](https://en.wikipedia.org/wiki/Futures_and_promises) for untangling evented code
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Libuv supports multiple reactors that can run on different threads.
|
12
|
+
|
13
|
+
For convenience the thread local or default reactor can be accessed via the `reactor` method
|
14
|
+
You can pass a block to be executed on the reactor and the reactor will run until there is nothing left to do.
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
require 'libuv'
|
18
|
+
|
19
|
+
reactor do |reactor|
|
20
|
+
reactor.timer {
|
21
|
+
puts "5 seconds passed"
|
22
|
+
}.start(5000)
|
23
|
+
end
|
24
|
+
|
25
|
+
puts "reactor stopped. No more IO to process"
|
26
|
+
```
|
27
|
+
|
28
|
+
Promises are used to simplify code flow.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'libuv'
|
32
|
+
|
33
|
+
reactor do |reactor|
|
34
|
+
reactor.tcp { |data, socket|
|
35
|
+
puts "received: #{data}"
|
36
|
+
socket.close
|
37
|
+
}
|
38
|
+
.connect('127.0.0.1', 3000) { |socket|
|
39
|
+
socket.start_read
|
40
|
+
.write("GET / HTTP/1.1\r\n\r\n")
|
41
|
+
}
|
42
|
+
.catch { |error|
|
43
|
+
puts "error: #{error}"
|
44
|
+
}
|
45
|
+
.finally {
|
46
|
+
puts "socket closed"
|
47
|
+
}
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
Continuations are used if callbacks are not defined
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
require 'libuv'
|
55
|
+
|
56
|
+
reactor do |reactor|
|
57
|
+
begin
|
58
|
+
reactor.tcp { |data, socket|
|
59
|
+
puts "received: #{data}"
|
60
|
+
socket.close
|
61
|
+
}
|
62
|
+
.connect('127.0.0.1', 3000)
|
63
|
+
.start_read
|
64
|
+
.write("GET / HTTP/1.1\r\n\r\n")
|
65
|
+
rescue => error
|
66
|
+
puts "error: #{error}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
Any promise can be converted into a continuation
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
require 'libuv'
|
75
|
+
|
76
|
+
reactor do |reactor|
|
77
|
+
# Perform work on the thread pool with promises
|
78
|
+
reactor.work {
|
79
|
+
10 * 2
|
80
|
+
}.then { |result|
|
81
|
+
puts "result using a promise #{result}"
|
82
|
+
}
|
83
|
+
|
84
|
+
# Use the coroutine helper to obtain the result without a callback
|
85
|
+
result = reactor.work {
|
86
|
+
10 * 3
|
87
|
+
}.value
|
88
|
+
puts "no additional callbacks here #{result}"
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
|
93
|
+
Check out the [yard documentation](http://rubydoc.info/gems/libuv/Libuv/Reactor)
|
94
|
+
|
95
|
+
|
96
|
+
## Installation
|
97
|
+
|
98
|
+
```shell
|
99
|
+
gem install libuv
|
100
|
+
```
|
101
|
+
|
102
|
+
or
|
103
|
+
|
104
|
+
```shell
|
105
|
+
git clone https://github.com/cotag/libuv.git
|
106
|
+
cd libuv
|
107
|
+
bundle install
|
108
|
+
rake compile
|
109
|
+
```
|
110
|
+
|
111
|
+
### Prerequisites
|
112
|
+
|
113
|
+
* The installation on BSD/Linux requires [python 2.x](http://www.python.org/getit/) to be installed and available on the PATH
|
114
|
+
* setting the environmental variable `USE_GLOBAL_LIBUV` will prevent compiling the packaged version.
|
115
|
+
* if you have a compatible `libuv.(so | dylib | dll)` on the PATH already
|
116
|
+
|
117
|
+
On Windows the GEM ships with a pre-compiled binary. If you would like to build yourself:
|
118
|
+
|
119
|
+
- A copy of Visual Studio 2017. [Visual Studio Build Tools](https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017) works fine.
|
120
|
+
- Windows 10 SDK
|
121
|
+
- C++/CLI Support
|
122
|
+
- C++ tools for CMake
|
123
|
+
- A copy of [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html) x64 - ~30MB installs
|
124
|
+
- ruby 2.4+ x64 with MSYS2 is preferred
|
125
|
+
- Add the env var `set GYP_MSVS_VERSION=2017`
|
126
|
+
- If using jRuby then [GCC](http://win-builds.org/stable/) is also required
|
127
|
+
- Setup the paths as described on the gcc page
|
128
|
+
- Add required environmental variable `set LIBRARY_PATH=X:\win-builds-64\lib;X:\win-builds-64\x86_64-w64-mingw32\lib`
|
129
|
+
- `rake compile`
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
## Features
|
134
|
+
|
135
|
+
* TCP (with TLS support)
|
136
|
+
* UDP
|
137
|
+
* TTY
|
138
|
+
* Pipes
|
139
|
+
* Timer
|
140
|
+
* Prepare
|
141
|
+
* Check
|
142
|
+
* Idle
|
143
|
+
* Signals
|
144
|
+
* Async callbacks
|
145
|
+
* Async DNS Resolution
|
146
|
+
* Filesystem Events
|
147
|
+
* Filesystem manipulation
|
148
|
+
* File manipulation
|
149
|
+
* Errors (with a catch-all fallback for anything unhandled on the event reactor)
|
150
|
+
* Work queue (thread pool)
|
151
|
+
* Coroutines / futures (makes use of Fibers)
|
152
|
+
|
153
|
+
### Server Name Indication
|
154
|
+
|
155
|
+
You can host a TLS enabled server with multiple hostnames using SNI.
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
server = reactor.tcp
|
159
|
+
server.bind('0.0.0.0', 3000, **{
|
160
|
+
hosts: [{
|
161
|
+
private_key: '/blah.key',
|
162
|
+
cert_chain: '/blah.crt',
|
163
|
+
host_name: 'somehost.com',
|
164
|
+
},
|
165
|
+
{
|
166
|
+
private_key: '/blah2.key',
|
167
|
+
cert_chain: '/blah2.crt',
|
168
|
+
host_name: 'somehost2.com'
|
169
|
+
},
|
170
|
+
{
|
171
|
+
private_key: '/blah3.key',
|
172
|
+
cert_chain: '/blah3.crt',
|
173
|
+
host_name: 'somehost3.com'
|
174
|
+
}]
|
175
|
+
}) do |client|
|
176
|
+
client.start_tls
|
177
|
+
client.start_read
|
178
|
+
end
|
179
|
+
|
180
|
+
# at some point later
|
181
|
+
server.add_host(private_key: '/blah4.key', cert_chain: '/blah4.crt', host_name: 'somehost4.com')
|
182
|
+
server.remove_host('somehost2.com')
|
183
|
+
```
|
184
|
+
|
185
|
+
You don't have to specify any hosts at binding time.
|
186
|
+
|
187
|
+
|
188
|
+
## Protocols and 3rd party plugins
|
189
|
+
|
190
|
+
* [HTTP](https://github.com/cotag/uv-rays - with SNI [server name indication] support)
|
191
|
+
* [Faraday plugin](https://github.com/cotag/uv-rays/blob/master/lib/faraday/adapter/libuv.rb)
|
192
|
+
* [HTTPI plugin](https://github.com/cotag/uv-rays/blob/master/lib/httpi/adapter/libuv.rb)
|
193
|
+
* [HTTP2](https://github.com/igrigorik/http-2)
|
194
|
+
* [SOAP](https://github.com/savonrb/savon) (using HTTPI plugin)
|
195
|
+
* [SNMP](https://github.com/acaprojects/ruby-engine/blob/master/lib/protocols/snmp.rb)
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec/core/rake_task' # testing framework
|
3
|
+
require 'yard' # yard documentation
|
4
|
+
require 'ffi' # loads the extension
|
5
|
+
require 'rake/clean' # for the :clobber rake task
|
6
|
+
require File.expand_path('../lib/mt-libuv/ext/tasks', __FILE__) # platform specific rake tasks used by compile
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
# By default we don't run network tests
|
11
|
+
task :default => :limited_spec
|
12
|
+
RSpec::Core::RakeTask.new(:limited_spec) do |t|
|
13
|
+
# Exclude network tests
|
14
|
+
t.rspec_opts = "--tag ~network"
|
15
|
+
end
|
16
|
+
RSpec::Core::RakeTask.new(:spec)
|
17
|
+
|
18
|
+
|
19
|
+
desc "Run all tests"
|
20
|
+
task :test => [:spec]
|
21
|
+
|
22
|
+
|
23
|
+
YARD::Rake::YardocTask.new do |t|
|
24
|
+
t.files = ['lib/**/*.rb', '-', 'ext/README.md', 'README.md']
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
desc "Compile libuv from submodule"
|
29
|
+
task :compile => ["ext/libuv/lib/libuv.#{FFI::Platform::LIBSUFFIX}"]
|
30
|
+
|
31
|
+
CLOBBER.include("ext/libuv/lib/libuv.#{FFI::Platform::LIBSUFFIX}")
|
data/ext/README.md
ADDED
data/ext/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
if ENV.has_key?('USE_GLOBAL_LIBUV')
|
5
|
+
exit(0)
|
6
|
+
else
|
7
|
+
require 'rubygems'
|
8
|
+
require 'ffi'
|
9
|
+
require 'rake/clean'
|
10
|
+
require '../lib/libuv/ext/tasks'
|
11
|
+
|
12
|
+
Dir.chdir File.expand_path("../", __FILE__)
|
13
|
+
Dir.chdir '..'
|
14
|
+
|
15
|
+
task :default => :libuv
|
16
|
+
|
17
|
+
if FFI::Platform.windows?
|
18
|
+
task :libuv do
|
19
|
+
FileUtils.mkdir('ext/libuv/lib')
|
20
|
+
FileUtils.cp 'ext/libuv.dll', 'ext/libuv/lib/libuv.dll'
|
21
|
+
end
|
22
|
+
else
|
23
|
+
desc "Compile libuv from submodule"
|
24
|
+
task :libuv => ["ext/libuv/lib/libuv.#{FFI::Platform::LIBSUFFIX}"]
|
25
|
+
|
26
|
+
CLOBBER.include("ext/libuv/lib/libuv.#{FFI::Platform::LIBSUFFIX}")
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MTLibuv
|
4
|
+
class Async < Handle
|
5
|
+
|
6
|
+
|
7
|
+
define_callback function: :on_async
|
8
|
+
|
9
|
+
|
10
|
+
# @param reactor [::MTLibuv::Reactor] reactor this async callback will be associated
|
11
|
+
def initialize(reactor)
|
12
|
+
@reactor = reactor
|
13
|
+
|
14
|
+
async_ptr = ::MTLibuv::Ext.allocate_handle_async
|
15
|
+
on_async = callback(:on_async, async_ptr.address)
|
16
|
+
error = check_result(::MTLibuv::Ext.async_init(reactor.handle, async_ptr, on_async))
|
17
|
+
|
18
|
+
super(async_ptr, error)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Triggers a notify event, calling everything in the notify chain
|
22
|
+
def call
|
23
|
+
return if @closed
|
24
|
+
error = check_result ::MTLibuv::Ext.async_send(handle)
|
25
|
+
reject(error) if error
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Used to update the callback that will be triggered when async is called
|
30
|
+
#
|
31
|
+
# @param callback [Proc] the callback to be called on reactor prepare
|
32
|
+
def progress(&callback)
|
33
|
+
@callback = callback
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
|
41
|
+
def on_async(handle)
|
42
|
+
@reactor.exec do
|
43
|
+
begin
|
44
|
+
@callback.call
|
45
|
+
rescue Exception => e
|
46
|
+
@reactor.log e, 'performing async callback'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MTLibuv
|
4
|
+
class Check < Handle
|
5
|
+
|
6
|
+
|
7
|
+
define_callback function: :on_check
|
8
|
+
|
9
|
+
|
10
|
+
# @param reactor [::MTLibuv::Reactor] reactor this check will be associated
|
11
|
+
# @param callback [Proc] callback to be called on reactor check
|
12
|
+
def initialize(reactor)
|
13
|
+
@reactor = reactor
|
14
|
+
|
15
|
+
check_ptr = ::MTLibuv::Ext.allocate_handle_check
|
16
|
+
error = check_result(::MTLibuv::Ext.check_init(reactor.handle, check_ptr))
|
17
|
+
|
18
|
+
super(check_ptr, error)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Enables the check handler.
|
22
|
+
def start
|
23
|
+
return if @closed
|
24
|
+
error = check_result ::MTLibuv::Ext.check_start(handle, callback(:on_check))
|
25
|
+
reject(error) if error
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Disables the check handler.
|
30
|
+
def stop
|
31
|
+
return if @closed
|
32
|
+
error = check_result ::MTLibuv::Ext.check_stop(handle)
|
33
|
+
reject(error) if error
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
# Used to update the callback that will be triggered on reactor check
|
38
|
+
#
|
39
|
+
# @param callback [Proc] the callback to be called on reactor check
|
40
|
+
def progress(&callback)
|
41
|
+
@callback = callback
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
|
49
|
+
def on_check(handle)
|
50
|
+
@reactor.exec do
|
51
|
+
begin
|
52
|
+
@callback.call
|
53
|
+
rescue Exception => e
|
54
|
+
@reactor.log e, 'performing check callback'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fiber'
|
4
|
+
|
5
|
+
class CoroutineRejection < RuntimeError
|
6
|
+
attr_accessor :value
|
7
|
+
end
|
8
|
+
|
9
|
+
module MTLibuv
|
10
|
+
# Takes a Promise response and turns it into a co-routine
|
11
|
+
# for code execution without using callbacks
|
12
|
+
#
|
13
|
+
# @param *promises [::MTLibuv::Q::Promise] a number of promises that will be combined into a single promise
|
14
|
+
# @return [Object] Returns the result of a single promise or an array of results if provided multiple promises
|
15
|
+
# @raise [Exception] if the promise is rejected
|
16
|
+
def co(*yieldable)
|
17
|
+
on_reactor = MTLibuv::Reactor.current
|
18
|
+
raise 'must be running on a reactor thread to use coroutines' unless on_reactor
|
19
|
+
|
20
|
+
f = Fiber.current
|
21
|
+
wasError = false
|
22
|
+
|
23
|
+
# Convert the input into a promise on the current reactor
|
24
|
+
if yieldable.length == 1
|
25
|
+
promise = yieldable[0]
|
26
|
+
# Passed independently as this is often overwritten for performance
|
27
|
+
promise.progress &Proc.new if block_given?
|
28
|
+
else
|
29
|
+
promise = on_reactor.all(*yieldable)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Use the promise to resume the Fiber
|
33
|
+
promise.then(proc { |res|
|
34
|
+
if MTLibuv::Reactor.current == on_reactor
|
35
|
+
f.resume res
|
36
|
+
else
|
37
|
+
on_reactor.schedule { f.resume(res) }
|
38
|
+
end
|
39
|
+
}, proc { |err|
|
40
|
+
wasError = true
|
41
|
+
if MTLibuv::Reactor.current == on_reactor
|
42
|
+
f.resume err
|
43
|
+
else
|
44
|
+
on_reactor.schedule { f.resume(err) }
|
45
|
+
end
|
46
|
+
})
|
47
|
+
|
48
|
+
# We want to prevent the reactor from stopping while we are waiting on a response
|
49
|
+
on_reactor.ref
|
50
|
+
result = Fiber.yield # Assign the result from the resume
|
51
|
+
on_reactor.unref
|
52
|
+
|
53
|
+
# Either return the result or raise an error
|
54
|
+
if wasError
|
55
|
+
if result.is_a?(Exception)
|
56
|
+
backtrace = caller
|
57
|
+
backtrace.shift
|
58
|
+
if result.respond_to?(:backtrace) && result.backtrace
|
59
|
+
backtrace << '---- continuation ----'
|
60
|
+
backtrace.concat(result.backtrace)
|
61
|
+
end
|
62
|
+
result.set_backtrace(backtrace)
|
63
|
+
raise result
|
64
|
+
else
|
65
|
+
e = case result
|
66
|
+
when String, Symbol
|
67
|
+
CoroutineRejection.new(result.to_s)
|
68
|
+
else
|
69
|
+
CoroutineRejection.new
|
70
|
+
end
|
71
|
+
e.value = result
|
72
|
+
raise e
|
73
|
+
end
|
74
|
+
end
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
module_function :co
|
79
|
+
end
|
data/lib/mt-libuv/dns.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MTLibuv
|
4
|
+
class Dns < Q::DeferredPromise
|
5
|
+
include Resource, Listener, Net
|
6
|
+
|
7
|
+
|
8
|
+
define_callback function: :on_complete, params: [:pointer, :int, Ext::UvAddrinfo.by_ref]
|
9
|
+
|
10
|
+
|
11
|
+
attr_reader :results
|
12
|
+
attr_reader :domain
|
13
|
+
attr_reader :port
|
14
|
+
attr_reader :hint
|
15
|
+
|
16
|
+
|
17
|
+
HINTS = {
|
18
|
+
:IPv4 => ::MTLibuv::Ext::UvAddrinfo.new,
|
19
|
+
:IPv6 => ::MTLibuv::Ext::UvAddrinfo.new
|
20
|
+
}
|
21
|
+
HINTS[:IPv4].tap do |hint|
|
22
|
+
hint[:family] = FFI::Platform.windows? ? 2 : Socket::Constants::AF_INET
|
23
|
+
hint[:socktype] = Socket::Constants::SOCK_STREAM
|
24
|
+
hint[:protocol] = Socket::Constants::IPPROTO_TCP
|
25
|
+
end
|
26
|
+
HINTS[:IPv6].tap do |hint|
|
27
|
+
hint[:family] = FFI::Platform.windows? ? 23 : Socket::Constants::AF_INET6
|
28
|
+
hint[:socktype] = Socket::Constants::SOCK_STREAM
|
29
|
+
hint[:protocol] = Socket::Constants::IPPROTO_TCP
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# @param reactor [::MTLibuv::Reactor] reactor this work request will be associated
|
34
|
+
# @param domain [String] the domain name to resolve
|
35
|
+
# @param port [Integer, String] the port we wish to use
|
36
|
+
def initialize(reactor, domain, port, hint = :IPv4, wait: true)
|
37
|
+
super(reactor, reactor.defer)
|
38
|
+
|
39
|
+
@domain = domain
|
40
|
+
@port = port
|
41
|
+
@hint = hint
|
42
|
+
@complete = false
|
43
|
+
@pointer = ::MTLibuv::Ext.allocate_request_getaddrinfo
|
44
|
+
@error = nil # error in callback
|
45
|
+
|
46
|
+
@instance_id = @pointer.address
|
47
|
+
error = check_result ::MTLibuv::Ext.getaddrinfo(@reactor, @pointer, callback(:on_complete), domain, port.to_s, HINTS[hint])
|
48
|
+
|
49
|
+
if error
|
50
|
+
::MTLibuv::Ext.free(@pointer)
|
51
|
+
@complete = true
|
52
|
+
@defer.reject(error)
|
53
|
+
end
|
54
|
+
|
55
|
+
@defer.promise.value if wait
|
56
|
+
end
|
57
|
+
|
58
|
+
# Indicates if the lookup has completed yet or not.
|
59
|
+
#
|
60
|
+
# @return [true, false]
|
61
|
+
def completed?
|
62
|
+
return @complete
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
|
69
|
+
def on_complete(req, status, addrinfo)
|
70
|
+
@complete = true
|
71
|
+
::MTLibuv::Ext.free(req)
|
72
|
+
|
73
|
+
e = check_result(status)
|
74
|
+
|
75
|
+
@reactor.exec do
|
76
|
+
if e
|
77
|
+
@defer.reject(e)
|
78
|
+
else
|
79
|
+
begin
|
80
|
+
current = addrinfo
|
81
|
+
@results = []
|
82
|
+
while !current.null?
|
83
|
+
@results << get_ip_and_port(current[:addr])
|
84
|
+
current = current[:next]
|
85
|
+
end
|
86
|
+
@defer.resolve(@results)
|
87
|
+
rescue Exception => e
|
88
|
+
@defer.reject(e)
|
89
|
+
end
|
90
|
+
::MTLibuv::Ext.freeaddrinfo(addrinfo)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Clean up references
|
95
|
+
cleanup_callbacks
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|