libuv 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +2 -0
- data/LICENSE +24 -0
- data/README.md +73 -0
- data/Rakefile +31 -0
- data/lib/libuv.rb +34 -0
- data/lib/libuv/assertions.rb +23 -0
- data/lib/libuv/async.rb +33 -0
- data/lib/libuv/check.rb +49 -0
- data/lib/libuv/error.rb +70 -0
- data/lib/libuv/ext/ext.rb +257 -0
- data/lib/libuv/ext/platform/darwin_x64.rb +12 -0
- data/lib/libuv/ext/platform/linux.rb +8 -0
- data/lib/libuv/ext/platform/unix.rb +14 -0
- data/lib/libuv/ext/platform/windows.rb +27 -0
- data/lib/libuv/ext/tasks.rb +27 -0
- data/lib/libuv/ext/tasks/mac.rb +23 -0
- data/lib/libuv/ext/tasks/unix.rb +23 -0
- data/lib/libuv/ext/tasks/win.rb +11 -0
- data/lib/libuv/ext/types.rb +230 -0
- data/lib/libuv/fs_event.rb +31 -0
- data/lib/libuv/handle.rb +82 -0
- data/lib/libuv/idle.rb +49 -0
- data/lib/libuv/listener.rb +34 -0
- data/lib/libuv/loop.rb +310 -0
- data/lib/libuv/net.rb +38 -0
- data/lib/libuv/pipe.rb +97 -0
- data/lib/libuv/prepare.rb +49 -0
- data/lib/libuv/q.rb +429 -0
- data/lib/libuv/resource.rb +28 -0
- data/lib/libuv/simple_async.rb +28 -0
- data/lib/libuv/stream.rb +124 -0
- data/lib/libuv/tcp.rb +194 -0
- data/lib/libuv/timer.rb +75 -0
- data/lib/libuv/tty.rb +34 -0
- data/lib/libuv/udp.rb +256 -0
- data/lib/libuv/version.rb +3 -0
- data/lib/libuv/work.rb +62 -0
- data/libuv.gemspec +54 -0
- data/spec/async_spec.rb +60 -0
- data/spec/defer_spec.rb +980 -0
- data/spec/idle_spec.rb +56 -0
- data/spec/pipe_spec.rb +148 -0
- data/spec/tcp_spec.rb +188 -0
- metadata +382 -0
data/lib/libuv/idle.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Libuv
|
2
|
+
class Idle < Handle
|
3
|
+
|
4
|
+
|
5
|
+
def initialize(loop, callback = nil, &blk)
|
6
|
+
@loop = loop
|
7
|
+
@callback = callback || blk
|
8
|
+
|
9
|
+
idle_ptr = ::Libuv::Ext.create_handle(:uv_idle)
|
10
|
+
error = check_result(::Libuv::Ext.idle_init(loop.handle, idle_ptr))
|
11
|
+
|
12
|
+
super(idle_ptr, error)
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
return if @closed
|
17
|
+
error = check_result ::Libuv::Ext.idle_start(handle, callback(:on_idle))
|
18
|
+
reject(error) if error
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
return if @closed
|
23
|
+
error = check_result ::Libuv::Ext.idle_stop(handle)
|
24
|
+
reject(error) if error
|
25
|
+
end
|
26
|
+
|
27
|
+
def progress(callback = nil, &blk)
|
28
|
+
@callback = callback || blk
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
|
35
|
+
def on_idle(handle, status)
|
36
|
+
e = check_result(status)
|
37
|
+
|
38
|
+
if e
|
39
|
+
reject(e)
|
40
|
+
else
|
41
|
+
begin
|
42
|
+
@callback.call
|
43
|
+
rescue Exception => e
|
44
|
+
@loop.log :error, :idle_cb, e
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'thread_safe'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Libuv
|
5
|
+
module Listener
|
6
|
+
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
|
11
|
+
CALLBACKS = ThreadSafe::Cache.new
|
12
|
+
|
13
|
+
|
14
|
+
def callbacks
|
15
|
+
@callbacks ||= Set.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def callback(name)
|
19
|
+
const_name = "#{name}_#{object_id}".to_sym
|
20
|
+
unless CALLBACKS[const_name]
|
21
|
+
callbacks << const_name
|
22
|
+
CALLBACKS[const_name] = method(name)
|
23
|
+
end
|
24
|
+
CALLBACKS[const_name]
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear_callbacks
|
28
|
+
callbacks.each do |name|
|
29
|
+
CALLBACKS.delete(name)
|
30
|
+
end
|
31
|
+
callbacks.clear
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/libuv/loop.rb
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Libuv
|
4
|
+
class Loop
|
5
|
+
include Resource, Assertions
|
6
|
+
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Get default loop
|
10
|
+
#
|
11
|
+
# @return [::Libuv::Loop]
|
12
|
+
def default
|
13
|
+
create(::Libuv::Ext.default_loop)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Create new loop
|
17
|
+
#
|
18
|
+
# @return [::Libuv::Loop]
|
19
|
+
def new
|
20
|
+
create(::Libuv::Ext.loop_new)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Create custom loop from pointer
|
24
|
+
#
|
25
|
+
# @return [::Libuv::Loop]
|
26
|
+
def create(pointer)
|
27
|
+
allocate.tap { |i| i.send(:initialize, FFI::AutoPointer.new(pointer, ::Libuv::Ext.method(:loop_delete))) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
extend ClassMethods
|
31
|
+
|
32
|
+
|
33
|
+
# Initialize a loop using an FFI::Pointer
|
34
|
+
#
|
35
|
+
# @return [::Libuv::Loop]
|
36
|
+
def initialize(pointer) # :notnew:
|
37
|
+
@pointer = pointer
|
38
|
+
@loop = self
|
39
|
+
|
40
|
+
# Create an async call for scheduling work from other threads
|
41
|
+
@run_queue = Queue.new
|
42
|
+
@queue_proc = proc do
|
43
|
+
# Rubinius fix for promises
|
44
|
+
# Anything calling schedule will
|
45
|
+
# be delayed a tick outside of promise callbacks on rubinius (see https://github.com/ffi/ffi/issues/279)
|
46
|
+
#@reactor_thread = Thread.current # Should work in rubinius 2.0
|
47
|
+
|
48
|
+
# ensure we only execute what was required for this tick
|
49
|
+
length = @run_queue.length
|
50
|
+
length.times do
|
51
|
+
begin
|
52
|
+
run = @run_queue.pop true # pop non-block
|
53
|
+
run.call
|
54
|
+
rescue Exception => e
|
55
|
+
@loop.log :error, :next_tick_cb, e
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@process_queue = SimpleAsync.new(@loop, @queue_proc)
|
60
|
+
|
61
|
+
# Create a next tick timer
|
62
|
+
@next_tick = @loop.timer do
|
63
|
+
@next_tick_scheduled = false
|
64
|
+
@queue_proc.call
|
65
|
+
end
|
66
|
+
|
67
|
+
# Create an async call for ending the loop
|
68
|
+
@stop_loop = SimpleAsync.new @loop do
|
69
|
+
@process_queue.close
|
70
|
+
@stop_loop.close
|
71
|
+
@next_tick.close
|
72
|
+
|
73
|
+
::Libuv::Ext.stop(@pointer)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def handle; @pointer; end
|
78
|
+
|
79
|
+
# Run the actual event loop. This method will block for the duration of event loop unless
|
80
|
+
# it is run inside an existing event loop, where a new thread will be created for it
|
81
|
+
#
|
82
|
+
# @param run_type [:UV_RUN_DEFAULT, :UV_RUN_ONCE, :UV_RUN_NOWAIT]
|
83
|
+
# @yieldparam promise [::Libuv::Loop] Yields a promise that can be used for logging unhandled
|
84
|
+
# exceptions on the loop.
|
85
|
+
# @return [::Libuv::Q::Promise]
|
86
|
+
def run(run_type = :UV_RUN_DEFAULT)
|
87
|
+
@loop_notify = @loop.defer
|
88
|
+
|
89
|
+
begin
|
90
|
+
@reactor_thread = Thread.current
|
91
|
+
yield @loop_notify.promise if block_given?
|
92
|
+
::Libuv::Ext.run(@pointer, run_type) # This is blocking
|
93
|
+
ensure
|
94
|
+
@reactor_thread = nil
|
95
|
+
@run_queue.clear
|
96
|
+
end
|
97
|
+
|
98
|
+
@loop
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
# Creates a deferred result object for where the result of an operation may only be returned
|
103
|
+
# at some point in the future or is being processed on a different thread (thread safe)
|
104
|
+
#
|
105
|
+
# @return [::Libuv::Q::Deferred]
|
106
|
+
def defer
|
107
|
+
Q.defer(@loop)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Combines multiple promises into a single promise that is resolved when all of the input
|
111
|
+
# promises are resolved. (thread safe)
|
112
|
+
#
|
113
|
+
# @param [*Promise] Promises a number of promises that will be combined into a single promise
|
114
|
+
# @return [Promise] Returns a single promise that will be resolved with an array of values,
|
115
|
+
# each value corresponding to the promise at the same index in the `promises` array. If any of
|
116
|
+
# the promises is resolved with a rejection, this resulting promise will be resolved with the
|
117
|
+
# same rejection.
|
118
|
+
def all(*promises)
|
119
|
+
Q.all(@loop, *promises)
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Combines multiple promises into a single promise that is resolved when any of the input
|
124
|
+
# promises are resolved.
|
125
|
+
#
|
126
|
+
# @param [*Promise] Promises a number of promises that will be combined into a single promise
|
127
|
+
# @return [Promise] Returns a single promise
|
128
|
+
def any(*promises)
|
129
|
+
Q.any(@loop, *promises)
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Combines multiple promises into a single promise that is resolved when all of the input
|
134
|
+
# promises are resolved or rejected.
|
135
|
+
#
|
136
|
+
# @param [*Promise] Promises a number of promises that will be combined into a single promise
|
137
|
+
# @return [Promise] Returns a single promise that will be resolved with an array of values,
|
138
|
+
# each [result, wasResolved] value pair corresponding to a at the same index in the `promises` array.
|
139
|
+
def finally(*promises)
|
140
|
+
Q.finally(@loop, *promises)
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
# forces loop time update, useful for getting more granular times
|
145
|
+
#
|
146
|
+
# @return nil
|
147
|
+
def update_time
|
148
|
+
::Libuv::Ext.update_time(@pointer)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Get current time in microseconds
|
152
|
+
#
|
153
|
+
# @return [Fixnum]
|
154
|
+
def now
|
155
|
+
::Libuv::Ext.now(@pointer)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Lookup an error code and return is as an error object
|
159
|
+
#
|
160
|
+
# @param err [Integer] The error code to look up.
|
161
|
+
# @return [::Libuv::Error]
|
162
|
+
def lookup_error(err)
|
163
|
+
name = ::Libuv::Ext.err_name(err)
|
164
|
+
msg = ::Libuv::Ext.strerror(err)
|
165
|
+
|
166
|
+
::Libuv::Error.const_get(name.to_sym).new(msg)
|
167
|
+
rescue Exception => e
|
168
|
+
@loop.log :warn, :error_lookup_failed, e
|
169
|
+
::Libuv::Error::UNKNOWN.new("error lookup failed for code #{err} #{name} #{msg}")
|
170
|
+
end
|
171
|
+
|
172
|
+
# Get a new TCP instance
|
173
|
+
#
|
174
|
+
# @return [::Libuv::TCP]
|
175
|
+
def tcp
|
176
|
+
TCP.new(@loop)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Get a new UDP instance
|
180
|
+
#
|
181
|
+
# @return [::Libuv::UDP]
|
182
|
+
def udp
|
183
|
+
UDP.new(@loop)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Get a new TTY instance
|
187
|
+
#
|
188
|
+
# @param fileno [Integer] Integer file descriptor of a tty device
|
189
|
+
# @param readable [true, false] Boolean indicating if TTY is readable
|
190
|
+
# @return [::Libuv::TTY]
|
191
|
+
def tty(fileno, readable = false)
|
192
|
+
assert_type(Integer, fileno, "io#fileno must return an integer file descriptor, #{fileno.inspect} given")
|
193
|
+
|
194
|
+
TTY.new(@loop, fileno, readable)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Get a new Pipe instance
|
198
|
+
#
|
199
|
+
# @param ipc [true, false]
|
200
|
+
# indicate if a handle will be used for ipc, useful for sharing tcp socket between processes
|
201
|
+
# @return [::Libuv::Pipe]
|
202
|
+
def pipe(ipc = false)
|
203
|
+
Pipe.new(@loop, ipc)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Get a new timer instance
|
207
|
+
#
|
208
|
+
# @return [::Libuv::Timer]
|
209
|
+
def timer(callback = nil, &blk)
|
210
|
+
Timer.new(@loop, callback || blk)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Get a new Prepare handle
|
214
|
+
#
|
215
|
+
# @return [::Libuv::Prepare]
|
216
|
+
def prepare
|
217
|
+
Prepare.new(@loop)
|
218
|
+
end
|
219
|
+
|
220
|
+
# Get a new Check handle
|
221
|
+
#
|
222
|
+
# @return [::Libuv::Check]
|
223
|
+
def check
|
224
|
+
Check.new(@loop)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Get a new Idle handle
|
228
|
+
#
|
229
|
+
# @return [::Libuv::Idle]
|
230
|
+
def idle(callback = nil, &block)
|
231
|
+
Idle.new(@loop, callback || block)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Get a new Async handle
|
235
|
+
#
|
236
|
+
# @return [::Libuv::Async]
|
237
|
+
def async(callback = nil, &block)
|
238
|
+
callback ||= block
|
239
|
+
handle = Async.new(@loop)
|
240
|
+
handle.progress callback if callback
|
241
|
+
handle
|
242
|
+
end
|
243
|
+
|
244
|
+
# Queue some work for processing in the libuv thread pool
|
245
|
+
#
|
246
|
+
# @return [::Libuv::Work]
|
247
|
+
# @raise [ArgumentError] if block is not given
|
248
|
+
def work(callback = nil, &block)
|
249
|
+
Work.new(@loop, callback || block) # Work is a promise object
|
250
|
+
end
|
251
|
+
|
252
|
+
# Get a new FSEvent instance
|
253
|
+
#
|
254
|
+
# @return [::Libuv::FSEvent]
|
255
|
+
def fs_event(path)
|
256
|
+
assert_type(String, path)
|
257
|
+
FSEvent.new(@loop, path)
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
# Schedule some work to be processed on the event loop (thread safe)
|
262
|
+
#
|
263
|
+
# @return [nil]
|
264
|
+
def schedule(&block)
|
265
|
+
assert_block(block)
|
266
|
+
|
267
|
+
if @reactor_thread == Thread.current
|
268
|
+
block.call
|
269
|
+
else
|
270
|
+
@run_queue << block
|
271
|
+
@process_queue.call
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# Schedule some work to be processed in the next iteration of the event loop (thread safe)
|
276
|
+
#
|
277
|
+
# @return [nil]
|
278
|
+
def next_tick(&block)
|
279
|
+
assert_block(block)
|
280
|
+
|
281
|
+
@run_queue << block
|
282
|
+
if @reactor_thread == Thread.current
|
283
|
+
# Create a next tick timer
|
284
|
+
if not @next_tick_scheduled
|
285
|
+
@next_tick.start(0)
|
286
|
+
@next_tick_scheduled = true
|
287
|
+
end
|
288
|
+
else
|
289
|
+
@process_queue.call
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Notifies the loop there was an event that should be logged
|
294
|
+
#
|
295
|
+
# @param level [Symbol] the error level (info, warn, error etc)
|
296
|
+
# @param id [Object] some kind of identifying information
|
297
|
+
# @param *args [*args] any additional information
|
298
|
+
# @return [nil]
|
299
|
+
def log(level, id, *args)
|
300
|
+
@loop_notify.notify(level, id, *args)
|
301
|
+
end
|
302
|
+
|
303
|
+
# Closes handles opened by the loop class and completes the current loop iteration (thread safe)
|
304
|
+
#
|
305
|
+
# @return [nil]
|
306
|
+
def stop
|
307
|
+
@stop_loop.call
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
data/lib/libuv/net.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Libuv
|
4
|
+
module Net
|
5
|
+
|
6
|
+
|
7
|
+
IP_ARGUMENT_ERROR = "ip must be a String".freeze # Arguments specifying an IP address
|
8
|
+
PORT_ARGUMENT_ERROR = "port must be an Integer".freeze # Arguments specifying an IP port
|
9
|
+
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
|
14
|
+
def get_sockaddr_and_len
|
15
|
+
sockaddr = FFI::MemoryPointer.new(UV::Sockaddr)
|
16
|
+
len = FFI::MemoryPointer.new(:int)
|
17
|
+
len.put_int(0, UV::Sockaddr.size)
|
18
|
+
[sockaddr, len]
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_ip_and_port(sockaddr, len=nil)
|
22
|
+
if sockaddr[:sa_family] == Socket::Constants::AF_INET6
|
23
|
+
len ||= Socket::Constants::INET6_ADDRSTRLEN
|
24
|
+
sockaddr_in6 = UV::SockaddrIn6.new(sockaddr.pointer)
|
25
|
+
ip_ptr = FFI::MemoryPointer.new(:char, len)
|
26
|
+
::Libuv::Ext.ip6_name(sockaddr_in6, ip_ptr, len)
|
27
|
+
port = ::Libuv::Ext.ntohs(sockaddr_in6[:sin6_port])
|
28
|
+
else
|
29
|
+
len ||= Socket::Constants::INET_ADDRSTRLEN
|
30
|
+
sockaddr_in = UV::SockaddrIn.new(sockaddr.pointer)
|
31
|
+
ip_ptr = FFI::MemoryPointer.new(:char, len)
|
32
|
+
::Libuv::Ext.ip4_name(sockaddr_in, ip_ptr, len)
|
33
|
+
port = ::Libuv::Ext.ntohs(sockaddr_in[:sin_port])
|
34
|
+
end
|
35
|
+
[ip_ptr.read_string, port]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/libuv/pipe.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
module Libuv
|
2
|
+
class Pipe < Handle
|
3
|
+
include Stream
|
4
|
+
|
5
|
+
|
6
|
+
def initialize(loop, ipc, acceptor = nil)
|
7
|
+
@loop, @ipc = loop, ipc
|
8
|
+
|
9
|
+
pipe_ptr = ::Libuv::Ext.create_handle(:uv_pipe)
|
10
|
+
error = check_result(::Libuv::Ext.pipe_init(loop.handle, pipe_ptr, ipc ? 1 : 0))
|
11
|
+
error = check_result(::Libuv::Ext.accept(acceptor, pipe_ptr)) if acceptor && error.nil?
|
12
|
+
|
13
|
+
super(pipe_ptr, error)
|
14
|
+
end
|
15
|
+
|
16
|
+
def bind(name, callback = nil, &blk)
|
17
|
+
@on_listen = callback || blk
|
18
|
+
assert_type(String, name, "name must be a String")
|
19
|
+
name = windows_path name if FFI::Platform.windows?
|
20
|
+
|
21
|
+
error = check_result ::Libuv::Ext.pipe_bind(handle, name)
|
22
|
+
reject(error) if error
|
23
|
+
end
|
24
|
+
|
25
|
+
def accept(callback = nil, &blk)
|
26
|
+
pipe = nil
|
27
|
+
begin
|
28
|
+
pipe = Pipe.new(loop, @ipc, handle)
|
29
|
+
rescue Exception => e
|
30
|
+
@loop.log :info, :pipe_accept_failed, e
|
31
|
+
end
|
32
|
+
if pipe
|
33
|
+
begin
|
34
|
+
(callback || blk).call(pipe)
|
35
|
+
rescue Exception => e
|
36
|
+
@loop.log :error, :pipe_accept_cb, e
|
37
|
+
end
|
38
|
+
end
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def open(fileno, callback = nil, &blk)
|
43
|
+
@callback = callback || blk
|
44
|
+
assert_type(Integer, fileno, "io#fileno must return an integer file descriptor")
|
45
|
+
begin
|
46
|
+
check_result! ::Libuv::Ext.pipe_open(handle, fileno)
|
47
|
+
|
48
|
+
# Emulate on_connect behavior
|
49
|
+
begin
|
50
|
+
@callback.call(self)
|
51
|
+
rescue Exception => e
|
52
|
+
@loop.log :error, :pipe_connect_cb, e
|
53
|
+
end
|
54
|
+
rescue Exception => e
|
55
|
+
reject(e)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def connect(name, callback = nil, &blk)
|
60
|
+
@callback = callback || blk
|
61
|
+
assert_type(String, name, "name must be a String")
|
62
|
+
begin
|
63
|
+
name = windows_path name if FFI::Platform.windows?
|
64
|
+
::Libuv::Ext.pipe_connect(::Libuv::Ext.create_request(:uv_connect), handle, name, callback(:on_connect))
|
65
|
+
rescue Exception => e
|
66
|
+
reject(e)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Windows only
|
71
|
+
def pending_instances=(count)
|
72
|
+
assert_type(Integer, count, "count must be an Integer")
|
73
|
+
::Libuv::Ext.pipe_pending_instances(handle, count)
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
|
80
|
+
def on_connect(req, status)
|
81
|
+
::Libuv::Ext.free(req)
|
82
|
+
begin
|
83
|
+
@callback.call(self)
|
84
|
+
rescue Exception => e
|
85
|
+
@loop.log :error, :pipe_connect_cb, e
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def windows_path(name)
|
90
|
+
# test for \\\\.\\pipe
|
91
|
+
if not name =~ /(\/|\\){2}\.(\/|\\)pipe/i
|
92
|
+
name = ::File.join("\\\\.\\pipe", name)
|
93
|
+
end
|
94
|
+
name.gsub("/", "\\")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|