mt-libuv 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,276 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MTLibuv
|
4
|
+
module Stream
|
5
|
+
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.define_callback function: :on_listen, params: [:pointer, :int]
|
9
|
+
base.define_callback function: :write_complete, params: [:pointer, :int]
|
10
|
+
base.define_callback function: :on_shutdown, params: [:pointer, :int]
|
11
|
+
|
12
|
+
base.define_callback function: :on_allocate, params: [:pointer, :size_t, Ext::UvBuf.by_ref]
|
13
|
+
base.define_callback function: :on_read, params: [:pointer, :ssize_t, Ext::UvBuf.by_ref]
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
BACKLOG_ERROR = "backlog must be an Integer"
|
19
|
+
WRITE_ERROR = "data must be a String"
|
20
|
+
STREAM_CLOSED_ERROR = "unable to write to a closed stream"
|
21
|
+
CLOSED_HANDLE_ERROR = "handle closed before accept called"
|
22
|
+
|
23
|
+
|
24
|
+
def listen(backlog)
|
25
|
+
return self if @closed
|
26
|
+
assert_type(Integer, backlog, BACKLOG_ERROR)
|
27
|
+
error = check_result ::MTLibuv::Ext.listen(handle, Integer(backlog), callback(:on_listen))
|
28
|
+
reject(error) if error
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Starts reading from the handle
|
33
|
+
def start_read
|
34
|
+
return self if @closed
|
35
|
+
error = check_result ::MTLibuv::Ext.read_start(handle, callback(:on_allocate), callback(:on_read))
|
36
|
+
reject(error) if error
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
# Stops reading from the handle
|
41
|
+
def stop_read
|
42
|
+
return self if @closed
|
43
|
+
error = check_result ::MTLibuv::Ext.read_stop(handle)
|
44
|
+
reject(error) if error
|
45
|
+
self
|
46
|
+
end
|
47
|
+
alias_method :close_read, :stop_read
|
48
|
+
|
49
|
+
# Shutsdown the writes on the handle waiting until the last write is complete before triggering the callback
|
50
|
+
def shutdown
|
51
|
+
return self if @closed
|
52
|
+
req = ::MTLibuv::Ext.allocate_request_shutdown
|
53
|
+
error = check_result ::MTLibuv::Ext.shutdown(req, handle, callback(:on_shutdown, req.address))
|
54
|
+
reject(error) if error
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def try_write(data)
|
59
|
+
assert_type(String, data, WRITE_ERROR)
|
60
|
+
|
61
|
+
buffer1 = ::FFI::MemoryPointer.from_string(data)
|
62
|
+
buffer = ::MTLibuv::Ext.buf_init(buffer1, data.respond_to?(:bytesize) ? data.bytesize : data.size)
|
63
|
+
|
64
|
+
result = ::MTLibuv::Ext.try_write(handle, buffer, 1)
|
65
|
+
buffer1.free
|
66
|
+
|
67
|
+
error = check_result result
|
68
|
+
raise error if error
|
69
|
+
return result
|
70
|
+
end
|
71
|
+
|
72
|
+
def write(data, wait: false)
|
73
|
+
# NOTE:: Similar to udp.rb -> send
|
74
|
+
deferred = @reactor.defer
|
75
|
+
if !@closed
|
76
|
+
begin
|
77
|
+
assert_type(String, data, WRITE_ERROR)
|
78
|
+
|
79
|
+
buffer1 = ::FFI::MemoryPointer.from_string(data)
|
80
|
+
buffer = ::MTLibuv::Ext.buf_init(buffer1, data.bytesize)
|
81
|
+
|
82
|
+
# local as this variable will be available until the handle is closed
|
83
|
+
@write_callbacks ||= {}
|
84
|
+
req = ::MTLibuv::Ext.allocate_request_write
|
85
|
+
@write_callbacks[req.address] = [deferred, buffer1]
|
86
|
+
error = check_result ::MTLibuv::Ext.write(req, handle, buffer, 1, callback(:write_complete, req.address))
|
87
|
+
|
88
|
+
if error
|
89
|
+
@write_callbacks.delete req.address
|
90
|
+
cleanup_callbacks req.address
|
91
|
+
|
92
|
+
::MTLibuv::Ext.free(req)
|
93
|
+
buffer1.free
|
94
|
+
deferred.reject(error)
|
95
|
+
|
96
|
+
reject(error) # close the handle
|
97
|
+
end
|
98
|
+
rescue => e
|
99
|
+
deferred.reject(e) # this write exception may not be fatal
|
100
|
+
end
|
101
|
+
else
|
102
|
+
deferred.reject(RuntimeError.new(STREAM_CLOSED_ERROR))
|
103
|
+
end
|
104
|
+
|
105
|
+
if wait
|
106
|
+
return deferred.promise if wait == :promise
|
107
|
+
deferred.promise.value
|
108
|
+
end
|
109
|
+
|
110
|
+
self
|
111
|
+
end
|
112
|
+
alias_method :puts, :write
|
113
|
+
alias_method :write_nonblock, :write
|
114
|
+
|
115
|
+
def readable?
|
116
|
+
return false if @closed
|
117
|
+
::MTLibuv::Ext.is_readable(handle) > 0
|
118
|
+
end
|
119
|
+
|
120
|
+
def writable?
|
121
|
+
return false if @closed
|
122
|
+
::MTLibuv::Ext.is_writable(handle) > 0
|
123
|
+
end
|
124
|
+
|
125
|
+
def progress(&blk)
|
126
|
+
@progress = blk
|
127
|
+
self
|
128
|
+
end
|
129
|
+
|
130
|
+
# Very basic IO emulation, in no way trying to be exact
|
131
|
+
def read(maxlen = nil, outbuf = nil)
|
132
|
+
raise ::EOFError.new('socket closed') if @closed
|
133
|
+
@read_defer = @reactor.defer
|
134
|
+
|
135
|
+
if @read_buffer.nil?
|
136
|
+
start_read
|
137
|
+
@read_buffer = String.new
|
138
|
+
self.finally do
|
139
|
+
@read_defer.reject(::EOFError.new('socket closed'))
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
if check_read_buffer(maxlen, outbuf, @read_defer)
|
144
|
+
progress do |data|
|
145
|
+
@read_buffer << data
|
146
|
+
check_read_buffer(maxlen, outbuf, @read_defer)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
@read_defer.promise.value
|
151
|
+
end
|
152
|
+
alias_method :read_nonblock, :read
|
153
|
+
|
154
|
+
# These are here purely for compatibility with rack hijack IO
|
155
|
+
def close_write; end
|
156
|
+
def flush
|
157
|
+
raise ::EOFError.new('socket closed') if @closed
|
158
|
+
|
159
|
+
@flush_defer = @reactor.defer
|
160
|
+
check_flush_buffer
|
161
|
+
@flush_defer.promise.value
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
|
168
|
+
def check_read_buffer(maxlen, outbuf, defer)
|
169
|
+
if maxlen && @read_buffer.bytesize >= maxlen
|
170
|
+
if outbuf
|
171
|
+
outbuf << @read_buffer[0...maxlen]
|
172
|
+
defer.resolve outbuf
|
173
|
+
else
|
174
|
+
defer.resolve @read_buffer[0...maxlen]
|
175
|
+
end
|
176
|
+
@read_buffer = @read_buffer[maxlen..-1]
|
177
|
+
progress do |data|
|
178
|
+
@read_buffer << data
|
179
|
+
end
|
180
|
+
false
|
181
|
+
elsif maxlen.nil?
|
182
|
+
defer.resolve @read_buffer
|
183
|
+
@read_buffer = String.new
|
184
|
+
progress do |data|
|
185
|
+
@read_buffer << data
|
186
|
+
end
|
187
|
+
false
|
188
|
+
else
|
189
|
+
true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def check_flush_buffer
|
194
|
+
if @flush_defer && (@write_callbacks.nil? || @write_callbacks.empty?) && (@pending_writes.nil? || @pending_writes.empty?) && @pending_write.nil?
|
195
|
+
@flush_defer.resolve(nil)
|
196
|
+
@flush_defer = nil
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
def on_listen(server, status)
|
202
|
+
e = check_result(status)
|
203
|
+
|
204
|
+
@reactor.exec do
|
205
|
+
if e
|
206
|
+
reject(e) # is this cause for closing the handle?
|
207
|
+
else
|
208
|
+
begin
|
209
|
+
@on_listen.call(self)
|
210
|
+
rescue Exception => e
|
211
|
+
@reactor.log e, 'performing stream listening callback'
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def on_allocate(client, suggested_size, buffer)
|
218
|
+
buffer[:len] = suggested_size
|
219
|
+
buffer[:base] = ::MTLibuv::Ext.malloc(suggested_size)
|
220
|
+
end
|
221
|
+
|
222
|
+
def write_complete(req, status)
|
223
|
+
deferred, buffer1 = @write_callbacks.delete req.address
|
224
|
+
cleanup_callbacks req.address
|
225
|
+
|
226
|
+
::MTLibuv::Ext.free(req)
|
227
|
+
buffer1.free
|
228
|
+
|
229
|
+
@reactor.exec do
|
230
|
+
resolve deferred, status
|
231
|
+
check_flush_buffer if @flush_defer
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def on_read(handle, nread, buf)
|
236
|
+
e = check_result(nread)
|
237
|
+
base = buf[:base]
|
238
|
+
|
239
|
+
if e
|
240
|
+
::MTLibuv::Ext.free(base)
|
241
|
+
|
242
|
+
@reactor.exec do
|
243
|
+
# I assume this is desirable behaviour
|
244
|
+
if e.is_a? ::MTLibuv::Error::EOF
|
245
|
+
close # Close gracefully
|
246
|
+
else
|
247
|
+
reject(e)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
else
|
251
|
+
data = base.read_string(nread)
|
252
|
+
::MTLibuv::Ext.free(base)
|
253
|
+
|
254
|
+
@reactor.exec do
|
255
|
+
if @tls.nil?
|
256
|
+
begin
|
257
|
+
@progress.call data, self
|
258
|
+
rescue Exception => e
|
259
|
+
@reactor.log e, 'performing stream read callback'
|
260
|
+
end
|
261
|
+
else
|
262
|
+
@tls.decrypt(data)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def on_shutdown(req, status)
|
269
|
+
cleanup_callbacks(req.address)
|
270
|
+
::MTLibuv::Ext.free(req)
|
271
|
+
@close_error = check_result(status)
|
272
|
+
|
273
|
+
@reactor.exec { close }
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MTLibuv
|
4
|
+
class Pipe < Handle
|
5
|
+
include Stream
|
6
|
+
|
7
|
+
|
8
|
+
define_callback function: :on_connect, params: [:pointer, :int]
|
9
|
+
define_callback function: :write2_complete, params: [:pointer, :int]
|
10
|
+
|
11
|
+
|
12
|
+
WRITE2_ERROR = "data must be a String"
|
13
|
+
|
14
|
+
|
15
|
+
def initialize(reactor, ipc, acceptor = nil)
|
16
|
+
@reactor, @ipc = reactor, ipc
|
17
|
+
|
18
|
+
pipe_ptr = ::MTLibuv::Ext.allocate_handle_pipe
|
19
|
+
error = check_result(::MTLibuv::Ext.pipe_init(reactor.handle, pipe_ptr, ipc ? 1 : 0))
|
20
|
+
error = check_result(::MTLibuv::Ext.accept(acceptor, pipe_ptr)) if acceptor && error.nil?
|
21
|
+
|
22
|
+
super(pipe_ptr, error)
|
23
|
+
end
|
24
|
+
|
25
|
+
def bind(name, &callback)
|
26
|
+
return if @closed
|
27
|
+
@on_accept = callback
|
28
|
+
@on_listen = proc { accept }
|
29
|
+
|
30
|
+
assert_type(String, name, "name must be a String")
|
31
|
+
name = windows_path name if FFI::Platform.windows?
|
32
|
+
|
33
|
+
error = check_result ::MTLibuv::Ext.pipe_bind(handle, name)
|
34
|
+
reject(error) if error
|
35
|
+
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def open(fileno)
|
40
|
+
assert_type(Integer, fileno, 'fileno must be an integer file descriptor')
|
41
|
+
|
42
|
+
begin
|
43
|
+
raise RuntimeError, CLOSED_HANDLE_ERROR if @closed
|
44
|
+
check_result! ::MTLibuv::Ext.pipe_open(handle, fileno)
|
45
|
+
|
46
|
+
# Emulate on_connect behavior
|
47
|
+
if block_given?
|
48
|
+
begin
|
49
|
+
yield(self)
|
50
|
+
rescue Exception => e
|
51
|
+
@reactor.log e, 'performing pipe connect callback'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue Exception => e
|
55
|
+
reject(e)
|
56
|
+
raise e unless block_given?
|
57
|
+
end
|
58
|
+
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def connect(name)
|
63
|
+
return if @closed
|
64
|
+
assert_type(String, name, "name must be a String")
|
65
|
+
|
66
|
+
begin
|
67
|
+
name = windows_path name if FFI::Platform.windows?
|
68
|
+
req = ::MTLibuv::Ext.allocate_request_connect
|
69
|
+
::MTLibuv::Ext.pipe_connect(req, handle, name, callback(:on_connect, req.address))
|
70
|
+
rescue Exception => e
|
71
|
+
reject(e)
|
72
|
+
end
|
73
|
+
|
74
|
+
if block_given?
|
75
|
+
@callback = Proc.new
|
76
|
+
else
|
77
|
+
@coroutine = @reactor.defer
|
78
|
+
@coroutine.promise.value
|
79
|
+
end
|
80
|
+
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def write2(fd, data = ".", wait: false)
|
85
|
+
deferred = @reactor.defer
|
86
|
+
if @ipc && !@closed
|
87
|
+
begin
|
88
|
+
assert_type(String, data, WRITE_ERROR)
|
89
|
+
assert_type(Handle, fd, WRITE2_ERROR)
|
90
|
+
|
91
|
+
size = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
92
|
+
buffer = ::MTLibuv::Ext.buf_init(FFI::MemoryPointer.from_string(data), size)
|
93
|
+
|
94
|
+
# local as this variable will be avaliable until the handle is closed
|
95
|
+
req = ::MTLibuv::Ext.allocate_request_write
|
96
|
+
@write_callbacks ||= {}
|
97
|
+
@write_callbacks[req.address] = deferred
|
98
|
+
error = check_result ::MTLibuv::Ext.write2(req, handle, buffer, 1, fd.handle, callback(:write2_complete, req.address))
|
99
|
+
|
100
|
+
if error
|
101
|
+
@write_callbacks.delete(req.address)
|
102
|
+
::MTLibuv::Ext.free(req)
|
103
|
+
deferred.reject(error)
|
104
|
+
|
105
|
+
reject(error) # close the handle
|
106
|
+
end
|
107
|
+
rescue Exception => e
|
108
|
+
deferred.reject(e) # this write exception may not be fatal
|
109
|
+
end
|
110
|
+
else
|
111
|
+
deferred.reject(TypeError.new('pipe not initialized for interprocess communication'))
|
112
|
+
end
|
113
|
+
|
114
|
+
if wait
|
115
|
+
return deferred.promise if wait == :promise
|
116
|
+
deferred.promise.value
|
117
|
+
end
|
118
|
+
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
# Windows only
|
123
|
+
def pending_instances=(count)
|
124
|
+
return 0 if @closed
|
125
|
+
assert_type(Integer, count, "count must be an Integer")
|
126
|
+
::MTLibuv::Ext.pipe_pending_instances(handle, count)
|
127
|
+
end
|
128
|
+
|
129
|
+
def check_pending(expecting = nil)
|
130
|
+
return nil if ::MTLibuv::Ext.pipe_pending_count(handle) <= 0
|
131
|
+
|
132
|
+
pending = ::MTLibuv::Ext.pipe_pending_type(handle).to_sym
|
133
|
+
raise TypeError, "IPC expecting #{expecting} and received #{pending}" if expecting && expecting.to_sym != pending
|
134
|
+
|
135
|
+
# Hide the accept logic
|
136
|
+
remote = nil
|
137
|
+
case pending
|
138
|
+
when :tcp
|
139
|
+
remote = TCP.new(reactor, handle)
|
140
|
+
when :pipe
|
141
|
+
remote = Pipe.new(reactor, @ipc, handle)
|
142
|
+
else
|
143
|
+
raise NotImplementedError, "IPC for handle #{pending} not supported"
|
144
|
+
end
|
145
|
+
remote
|
146
|
+
end
|
147
|
+
|
148
|
+
def getsockname
|
149
|
+
size = 256
|
150
|
+
len = FFI::MemoryPointer.new(:size_t)
|
151
|
+
len.put_int(0, size)
|
152
|
+
buffer = FFI::MemoryPointer.new(size)
|
153
|
+
check_result! ::MTLibuv::Ext.pipe_getsockname(handle, buffer, len)
|
154
|
+
buffer.read_string
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
|
161
|
+
def accept
|
162
|
+
pipe = nil
|
163
|
+
begin
|
164
|
+
raise RuntimeError, CLOSED_HANDLE_ERROR if @closed
|
165
|
+
pipe = Pipe.new(reactor, @ipc, handle)
|
166
|
+
rescue Exception => e
|
167
|
+
@reactor.log e, 'pipe accept failed'
|
168
|
+
end
|
169
|
+
if pipe
|
170
|
+
@reactor.exec do
|
171
|
+
begin
|
172
|
+
@on_accept.call(pipe)
|
173
|
+
rescue Exception => e
|
174
|
+
@reactor.log e, 'performing pipe accept callback'
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def on_connect(req, status)
|
181
|
+
cleanup_callbacks req.address
|
182
|
+
::MTLibuv::Ext.free(req)
|
183
|
+
e = check_result(status)
|
184
|
+
|
185
|
+
@reactor.exec do
|
186
|
+
if e
|
187
|
+
reject(e)
|
188
|
+
else
|
189
|
+
begin
|
190
|
+
@callback.call(self)
|
191
|
+
rescue Exception => e
|
192
|
+
@reactor.log e, 'performing pipe connected callback'
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def write2_complete(req, status)
|
199
|
+
promise = @write_callbacks.delete(req.address)
|
200
|
+
cleanup_callbacks req.address
|
201
|
+
|
202
|
+
::MTLibuv::Ext.free(req)
|
203
|
+
|
204
|
+
@reactor.exec do
|
205
|
+
resolve promise, status
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def windows_path(name)
|
210
|
+
# test for \\\\.\\pipe
|
211
|
+
if not name =~ /(\/|\\){2}\.(\/|\\)pipe/i
|
212
|
+
name = ::File.join("\\\\.\\pipe", name)
|
213
|
+
end
|
214
|
+
name.gsub("/", "\\")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MTLibuv
|
4
|
+
class Prepare < Handle
|
5
|
+
|
6
|
+
|
7
|
+
define_callback function: :on_prepare
|
8
|
+
|
9
|
+
|
10
|
+
# @param reactor [::MTLibuv::Reactor] reactor this prepare handle will be associated
|
11
|
+
# @param callback [Proc] callback to be called on reactor preparation
|
12
|
+
def initialize(reactor)
|
13
|
+
@reactor = reactor
|
14
|
+
|
15
|
+
prepare_ptr = ::MTLibuv::Ext.allocate_handle_prepare
|
16
|
+
error = check_result(::MTLibuv::Ext.prepare_init(reactor.handle, prepare_ptr))
|
17
|
+
|
18
|
+
super(prepare_ptr, error)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Enables the prepare handler.
|
22
|
+
def start
|
23
|
+
return if @closed
|
24
|
+
error = check_result ::MTLibuv::Ext.prepare_start(handle, callback(:on_prepare))
|
25
|
+
reject(error) if error
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Disables the prepare handler.
|
30
|
+
def stop
|
31
|
+
return if @closed
|
32
|
+
error = check_result ::MTLibuv::Ext.prepare_stop(handle)
|
33
|
+
reject(error) if error
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
# Used to update the callback that will be triggered on reactor prepare
|
38
|
+
#
|
39
|
+
# @param callback [Proc] the callback to be called on reactor prepare
|
40
|
+
def progress(&callback)
|
41
|
+
@callback = callback
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
|
49
|
+
def on_prepare(handle)
|
50
|
+
@reactor.exec do
|
51
|
+
begin
|
52
|
+
@callback.call
|
53
|
+
rescue Exception => e
|
54
|
+
@reactor.log e, 'performing prepare callback'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|