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
@@ -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
|