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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.gitmodules +6 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +24 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE +24 -0
  8. data/README.md +195 -0
  9. data/Rakefile +31 -0
  10. data/ext/README.md +6 -0
  11. data/ext/Rakefile +28 -0
  12. data/lib/mt-libuv/async.rb +51 -0
  13. data/lib/mt-libuv/check.rb +59 -0
  14. data/lib/mt-libuv/coroutines.rb +79 -0
  15. data/lib/mt-libuv/dns.rb +98 -0
  16. data/lib/mt-libuv/error.rb +88 -0
  17. data/lib/mt-libuv/ext/ext.rb +322 -0
  18. data/lib/mt-libuv/ext/platform/darwin_x64.rb +61 -0
  19. data/lib/mt-libuv/ext/platform/unix.rb +69 -0
  20. data/lib/mt-libuv/ext/platform/windows.rb +83 -0
  21. data/lib/mt-libuv/ext/tasks/mac.rb +24 -0
  22. data/lib/mt-libuv/ext/tasks/unix.rb +42 -0
  23. data/lib/mt-libuv/ext/tasks/win.rb +29 -0
  24. data/lib/mt-libuv/ext/tasks.rb +27 -0
  25. data/lib/mt-libuv/ext/types.rb +253 -0
  26. data/lib/mt-libuv/fiber_pool.rb +83 -0
  27. data/lib/mt-libuv/file.rb +309 -0
  28. data/lib/mt-libuv/filesystem.rb +263 -0
  29. data/lib/mt-libuv/fs_event.rb +37 -0
  30. data/lib/mt-libuv/handle.rb +108 -0
  31. data/lib/mt-libuv/idle.rb +59 -0
  32. data/lib/mt-libuv/mixins/accessors.rb +41 -0
  33. data/lib/mt-libuv/mixins/assertions.rb +25 -0
  34. data/lib/mt-libuv/mixins/fs_checks.rb +96 -0
  35. data/lib/mt-libuv/mixins/listener.rb +69 -0
  36. data/lib/mt-libuv/mixins/net.rb +42 -0
  37. data/lib/mt-libuv/mixins/resource.rb +30 -0
  38. data/lib/mt-libuv/mixins/stream.rb +276 -0
  39. data/lib/mt-libuv/pipe.rb +217 -0
  40. data/lib/mt-libuv/prepare.rb +59 -0
  41. data/lib/mt-libuv/q.rb +475 -0
  42. data/lib/mt-libuv/reactor.rb +567 -0
  43. data/lib/mt-libuv/signal.rb +62 -0
  44. data/lib/mt-libuv/spawn.rb +113 -0
  45. data/lib/mt-libuv/tcp.rb +465 -0
  46. data/lib/mt-libuv/timer.rb +107 -0
  47. data/lib/mt-libuv/tty.rb +42 -0
  48. data/lib/mt-libuv/udp.rb +302 -0
  49. data/lib/mt-libuv/version.rb +5 -0
  50. data/lib/mt-libuv/work.rb +86 -0
  51. data/lib/mt-libuv.rb +80 -0
  52. data/mt-libuv.gemspec +62 -0
  53. data/spec/async_spec.rb +67 -0
  54. data/spec/coroutines_spec.rb +121 -0
  55. data/spec/cpu_spec.rb +10 -0
  56. data/spec/defer_spec.rb +906 -0
  57. data/spec/dns_spec.rb +110 -0
  58. data/spec/dsl_spec.rb +43 -0
  59. data/spec/filesystem_spec.rb +270 -0
  60. data/spec/idle_spec.rb +44 -0
  61. data/spec/pipe_spec.rb +151 -0
  62. data/spec/spawn_spec.rb +119 -0
  63. data/spec/tcp_spec.rb +272 -0
  64. data/spec/test.sh +4 -0
  65. data/spec/test_fail.sh +3 -0
  66. data/spec/test_read.sh +3 -0
  67. data/spec/timer_spec.rb +14 -0
  68. data/spec/udp_spec.rb +73 -0
  69. data/spec/zen_spec.rb +34 -0
  70. metadata +196 -0
@@ -0,0 +1,309 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ class File < Q::DeferredPromise
5
+ include Assertions, Resource, Listener, FsChecks
6
+
7
+
8
+ fs_params = {
9
+ params: [Ext::FsRequest.by_ref],
10
+ lookup: :fs_lookup
11
+ }
12
+ define_callback function: :on_open, **fs_params
13
+ define_callback function: :on_close, **fs_params
14
+ define_callback function: :on_read, **fs_params
15
+ define_callback function: :on_write, **fs_params
16
+ define_callback function: :on_sync, **fs_params
17
+ define_callback function: :on_datasync, **fs_params
18
+ define_callback function: :on_truncate, **fs_params
19
+ define_callback function: :on_utime, **fs_params
20
+ define_callback function: :on_chmod, **fs_params
21
+ define_callback function: :on_chown, **fs_params
22
+ define_callback function: :on_stat, **fs_params
23
+
24
+
25
+ EOF = "0\r\n\r\n"
26
+ CRLF = "\r\n"
27
+
28
+
29
+ attr_reader :fileno, :closed
30
+
31
+
32
+ def initialize(thread, path, flags = 0, mode: 0)
33
+ super(thread, thread.defer)
34
+
35
+ @fileno = -1
36
+ @closed = true
37
+ @path, @flags, @mode = path, flags, mode
38
+ @request_refs = {}
39
+
40
+ request = ::MTLibuv::Ext.allocate_request_fs
41
+ pre_check @defer, request, ::MTLibuv::Ext.fs_open(@reactor, request, @path, @flags, @mode, callback(:on_open, request.address))
42
+
43
+ if block_given?
44
+ self.progress &Proc.new
45
+ else
46
+ @coroutine = @reactor.defer
47
+ @coroutine.promise.value
48
+ end
49
+ end
50
+
51
+ def close
52
+ @closed = true
53
+ request = ::MTLibuv::Ext.allocate_request_fs
54
+ pre_check(@defer, request, ::MTLibuv::Ext.fs_close(@reactor.handle, request, @fileno, callback(:on_close, request.address)))
55
+ self
56
+ end
57
+
58
+ def read(length, offset = 0, wait: true)
59
+ assert_type(Integer, length, "length must be an Integer")
60
+ assert_type(Integer, offset, "offset must be an Integer")
61
+ deferred = @reactor.defer
62
+
63
+ buffer1 = FFI::MemoryPointer.new(length)
64
+ buffer = ::MTLibuv::Ext.buf_init(buffer1, length)
65
+ request = ::MTLibuv::Ext.allocate_request_fs
66
+
67
+ @request_refs[request.address] = [deferred, buffer1]
68
+
69
+ promise = pre_check(deferred, request, ::MTLibuv::Ext.fs_read(@reactor.handle, request, @fileno, buffer, 1, offset, callback(:on_read, request.address)))
70
+ wait ? promise.value : promise
71
+ end
72
+
73
+ def write(data, offset = 0, wait: true)
74
+ assert_type(String, data, "data must be a String")
75
+ assert_type(Integer, offset, "offset must be an Integer")
76
+ deferred = @reactor.defer
77
+
78
+ length = data.respond_to?(:bytesize) ? data.bytesize : data.size
79
+
80
+ buffer1 = FFI::MemoryPointer.from_string(data)
81
+ buffer = ::MTLibuv::Ext.buf_init(buffer1, length)
82
+ request = ::MTLibuv::Ext.allocate_request_fs
83
+
84
+ @request_refs[request.address] = [deferred, buffer1]
85
+
86
+ respond wait, pre_check(deferred, request, ::MTLibuv::Ext.fs_write(@reactor.handle, request, @fileno, buffer, 1, offset, callback(:on_write, request.address)))
87
+ end
88
+
89
+ def sync(wait: false)
90
+ deferred = @reactor.defer
91
+
92
+ request = ::MTLibuv::Ext.allocate_request_fs
93
+ @request_refs[request.address] = deferred
94
+
95
+ respond wait, pre_check(deferred, request, ::MTLibuv::Ext.fs_fsync(@reactor.handle, request, @fileno, callback(:on_sync, request.address)))
96
+ end
97
+
98
+ def datasync(wait: false)
99
+ deferred = @reactor.defer
100
+
101
+ request = ::MTLibuv::Ext.allocate_request_fs
102
+ @request_refs[request.address] = deferred
103
+
104
+ respond wait, pre_check(deferred, request, ::MTLibuv::Ext.fs_fdatasync(@reactor.handle, request, @fileno, callback(:on_datasync, request.address)))
105
+ end
106
+
107
+ def truncate(offset, wait: true)
108
+ assert_type(Integer, offset, "offset must be an Integer")
109
+ deferred = @reactor.defer
110
+
111
+ request = ::MTLibuv::Ext.allocate_request_fs
112
+ @request_refs[request.address] = deferred
113
+
114
+ respond wait, pre_check(deferred, request, ::MTLibuv::Ext.fs_ftruncate(@reactor.handle, request, @fileno, offset, callback(:on_truncate, request.address)))
115
+ end
116
+
117
+ def utime(atime:, mtime:, wait: true)
118
+ assert_type(Integer, atime, "atime must be an Integer")
119
+ assert_type(Integer, mtime, "mtime must be an Integer")
120
+ deferred = @reactor.defer
121
+
122
+ request = ::MTLibuv::Ext.allocate_request_fs
123
+ @request_refs[request.address] = deferred
124
+
125
+ promise = pre_check deferred, request, ::MTLibuv::Ext.fs_futime(@reactor.handle, request, @fileno, atime, mtime, callback(:on_utime, request.address))
126
+ wait ? promise.value : promise
127
+ end
128
+
129
+ def chmod(mode, wait: true)
130
+ assert_type(Integer, mode, "mode must be an Integer")
131
+ deferred = @reactor.defer
132
+
133
+ request = ::MTLibuv::Ext.allocate_request_fs
134
+ @request_refs[request.address] = deferred
135
+
136
+ respond wait, pre_check(deferred, request, ::MTLibuv::Ext.fs_fchmod(@reactor.handle, request, @fileno, mode, callback(:on_chmod, request.address)))
137
+ end
138
+
139
+ def chown(uid:, gid:, wait: true)
140
+ assert_type(Integer, uid, "uid must be an Integer")
141
+ assert_type(Integer, gid, "gid must be an Integer")
142
+ deferred = @reactor.defer
143
+
144
+ request = ::MTLibuv::Ext.allocate_request_fs
145
+ @request_refs[request.address] = deferred
146
+
147
+ respond wait, pre_check(deferred, request, ::MTLibuv::Ext.fs_fchown(@reactor.handle, request, @fileno, uid, gid, callback(:on_chown, request.address)))
148
+ end
149
+
150
+ def send_file(stream, using: :raw, chunk_size: 4096, wait: true)
151
+ @transmit_failure ||= proc { |reason| @sending_file.reject(reason) }
152
+ @start_transmit ||= proc { |stats|
153
+ @file_stream_total = stats[:st_size]
154
+ next_chunk
155
+ }
156
+ @transmit_data ||= proc { |data| transmit_data(data) }
157
+
158
+ @sending_file = @reactor.defer
159
+ @file_stream = stream
160
+ @file_stream_type = using
161
+ @file_chunk_size = chunk_size
162
+ @file_chunk_count = 0
163
+
164
+ stat(wait: false).then @start_transmit, @transmit_failure
165
+
166
+ promise = @sending_file.promise
167
+ promise.finally { clean_up_send }
168
+ respond wait, promise
169
+ end
170
+
171
+
172
+ private
173
+
174
+
175
+ ##
176
+ # File transmit functions -------------
177
+ def transmit_data(data)
178
+ @file_chunk_count += 1
179
+ if @file_stream_type == :http
180
+ resp = String.new
181
+ resp << data.bytesize.to_s(16) << CRLF
182
+ resp << data
183
+ resp << CRLF
184
+ data = resp
185
+ end
186
+ @file_stream.write(data, wait: :promise).then(proc { next_chunk }, @transmit_failure)
187
+ nil
188
+ end
189
+
190
+ def next_chunk
191
+ next_size = @file_chunk_size
192
+ next_offset = @file_chunk_size * @file_chunk_count
193
+
194
+ if next_offset >= @file_stream_total
195
+ if @file_stream_type == :http
196
+ @file_stream.write(EOF, wait: :promise).then(proc {
197
+ @sending_file.resolve(@file_stream_total)
198
+ }, @transmit_failure)
199
+ else
200
+ @sending_file.resolve(@file_stream_total)
201
+ end
202
+ else
203
+ if next_offset + next_size > @file_stream_total
204
+ next_size = @file_stream_total - next_offset
205
+ end
206
+ read(next_size, next_offset, wait: false).then(@transmit_data, @transmit_failure)
207
+ end
208
+ nil
209
+ end
210
+
211
+ def clean_up_send
212
+ @sending_file = nil
213
+ @file_stream = nil
214
+ @file_stream_type = nil
215
+ @file_chunk_size = nil
216
+ @file_chunk_count = nil
217
+ @file_stream_total = nil
218
+ end
219
+ # -------------------------------------
220
+ ##
221
+
222
+
223
+ def on_open(req)
224
+ if post_check(req, @defer)
225
+ @fileno = req[:result]
226
+ cleanup(req)
227
+ @closed = false
228
+ @reactor.exec { @defer.notify(self) }
229
+
230
+ if @coroutine
231
+ @coroutine.resolve(nil)
232
+ @coroutine = nil
233
+ end
234
+ end
235
+ end
236
+
237
+ def on_close(req)
238
+ if post_check(req, @defer)
239
+ cleanup(req)
240
+ @reactor.exec { @defer.resolve(nil) }
241
+ end
242
+ end
243
+
244
+ def on_read(req)
245
+ deferred, buffer1 = @request_refs.delete req.to_ptr.address
246
+ if post_check(req, deferred)
247
+ data = buffer1.read_string(req[:result])
248
+ cleanup(req)
249
+ @reactor.exec { deferred.resolve(data) }
250
+ end
251
+ end
252
+
253
+ def on_write(req)
254
+ deferred, buffer1 = @request_refs.delete req.to_ptr.address
255
+ if post_check(req, deferred)
256
+ cleanup(req)
257
+ @reactor.exec { deferred.resolve(nil) }
258
+ end
259
+ end
260
+
261
+ def on_sync(req)
262
+ deferred = @request_refs.delete req.to_ptr.address
263
+ if post_check(req, deferred)
264
+ cleanup(req)
265
+ @reactor.exec { deferred.resolve(nil) }
266
+ end
267
+ end
268
+
269
+ def on_datasync(req)
270
+ deferred = @request_refs.delete req.to_ptr.address
271
+ if post_check(req, deferred)
272
+ cleanup(req)
273
+ @reactor.exec { deferred.resolve(nil) }
274
+ end
275
+ end
276
+
277
+ def on_truncate(req)
278
+ deferred = @request_refs.delete req.to_ptr.address
279
+ if post_check(req, deferred)
280
+ cleanup(req)
281
+ @reactor.exec { deferred.resolve(nil) }
282
+ end
283
+ end
284
+
285
+ def on_utime(req)
286
+ deferred = @request_refs.delete req.to_ptr.address
287
+ if post_check(req, deferred)
288
+ cleanup(req)
289
+ @reactor.exec { deferred.resolve(nil) }
290
+ end
291
+ end
292
+
293
+ def on_chmod(req)
294
+ deferred = @request_refs.delete req.to_ptr.address
295
+ if post_check(req, deferred)
296
+ cleanup(req)
297
+ @reactor.exec { deferred.resolve(nil) }
298
+ end
299
+ end
300
+
301
+ def on_chown(req)
302
+ deferred = @request_refs.delete req.to_ptr.address
303
+ if post_check(req, deferred)
304
+ cleanup(req)
305
+ @reactor.exec { deferred.resolve(nil) }
306
+ end
307
+ end
308
+ end
309
+ end
@@ -0,0 +1,263 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ class Filesystem
5
+ include Assertions, Resource, Listener, FsChecks
6
+
7
+
8
+ fs_params = {
9
+ params: [Ext::FsRequest.by_ref],
10
+ lookup: :fs_lookup
11
+ }
12
+ define_callback function: :on_unlink, **fs_params
13
+ define_callback function: :on_mkdir, **fs_params
14
+ define_callback function: :on_rmdir, **fs_params
15
+ define_callback function: :on_readdir, **fs_params
16
+ define_callback function: :on_rename, **fs_params
17
+ define_callback function: :on_chmod, **fs_params
18
+ define_callback function: :on_utime, **fs_params
19
+ define_callback function: :on_stat, **fs_params
20
+ define_callback function: :on_link, **fs_params
21
+ define_callback function: :on_symlink, **fs_params
22
+ define_callback function: :on_readlink, **fs_params
23
+ define_callback function: :on_chown, **fs_params
24
+
25
+
26
+ def initialize(reactor)
27
+ @reactor = reactor
28
+ end
29
+
30
+ def unlink(path, wait: true)
31
+ assert_type(String, path, "path must be a String")
32
+ @unlink_deferred = @reactor.defer
33
+
34
+ request = ::MTLibuv::Ext.allocate_request_fs
35
+ pre_check @unlink_deferred, request, ::MTLibuv::Ext.fs_unlink(@reactor, request, path, callback(:on_unlink, request.address))
36
+ respond wait, @unlink_deferred.promise
37
+ end
38
+
39
+ def mkdir(path, mode = 0777, wait: true)
40
+ assert_type(String, path, "path must be a String")
41
+ assert_type(Integer, mode, "mode must be an Integer")
42
+ @mkdir_deferred = @reactor.defer
43
+
44
+ request = ::MTLibuv::Ext.allocate_request_fs
45
+ pre_check @mkdir_deferred, request, ::MTLibuv::Ext.fs_mkdir(@reactor, request, path, mode, callback(:on_mkdir, request.address))
46
+ respond wait, @mkdir_deferred.promise
47
+ end
48
+
49
+ def rmdir(path, wait: true)
50
+ assert_type(String, path, "path must be a String")
51
+ @rmdir_deferred = @reactor.defer
52
+
53
+ request = ::MTLibuv::Ext.allocate_request_fs
54
+ pre_check @rmdir_deferred, request, ::MTLibuv::Ext.fs_rmdir(@reactor, request, path, callback(:on_rmdir, request.address))
55
+ respond wait, @rmdir_deferred.promise
56
+ end
57
+
58
+ def readdir(path, wait: true)
59
+ assert_type(String, path, "path must be a String")
60
+ @readdir_deferred = @reactor.defer
61
+
62
+ request = ::MTLibuv::Ext.allocate_request_fs
63
+ pre_check @readdir_deferred, request, ::MTLibuv::Ext.fs_readdir(@reactor, request, path, 0, callback(:on_readdir, request.address))
64
+ respond wait, @readdir_deferred.promise
65
+ end
66
+
67
+ def rename(old_path, new_path, wait: true)
68
+ assert_type(String, old_path, "old_path must be a String")
69
+ assert_type(String, new_path, "new_path must be a String")
70
+ @rename_deferred = @reactor.defer
71
+
72
+ request = ::MTLibuv::Ext.allocate_request_fs
73
+ pre_check @rename_deferred, request, ::MTLibuv::Ext.fs_rename(@reactor, request, old_path, new_path, callback(:on_rename, request.address))
74
+ respond wait, @rename_deferred.promise
75
+ end
76
+
77
+ def chmod(path, mode, wait: true)
78
+ assert_type(String, path, "path must be a String")
79
+ assert_type(Integer, mode, "mode must be an Integer")
80
+ @chmod_deferred = @reactor.defer
81
+
82
+ request = ::MTLibuv::Ext.allocate_request_fs
83
+ pre_check @chmod_deferred, request, ::MTLibuv::Ext.fs_chmod(@reactor, request, path, mode, callback(:on_chmod, request.address))
84
+ respond wait, @chmod_deferred.promise
85
+ end
86
+
87
+ def utime(path, atime, mtime, wait: true)
88
+ assert_type(String, path, "path must be a String")
89
+ assert_type(Integer, atime, "atime must be an Integer")
90
+ assert_type(Integer, mtime, "mtime must be an Integer")
91
+ @utime_deferred = @reactor.defer
92
+
93
+ request = ::MTLibuv::Ext.allocate_request_fs
94
+ pre_check @utime_deferred, request, ::MTLibuv::Ext.fs_utime(@reactor, request, path, atime, mtime, callback(:on_utime, request.address))
95
+ respond wait, @utime_deferred.promise
96
+ end
97
+
98
+ def lstat(path, wait: true)
99
+ assert_type(String, path, "path must be a String")
100
+ @stat_deferred = @reactor.defer
101
+
102
+ request = ::MTLibuv::Ext.allocate_request_fs
103
+ pre_check @stat_deferred, request, ::MTLibuv::Ext.fs_lstat(@reactor, request, path, callback(:on_stat, request.address))
104
+ respond wait, @stat_deferred.promise
105
+ end
106
+
107
+ def link(old_path, new_path, wait: true)
108
+ assert_type(String, old_path, "old_path must be a String")
109
+ assert_type(String, new_path, "new_path must be a String")
110
+ @link_deferred = @reactor.defer
111
+
112
+ request = ::MTLibuv::Ext.allocate_request_fs
113
+ pre_check @link_deferred, request, ::MTLibuv::Ext.fs_link(@reactor, request, old_path, new_path, callback(:on_link, request.address))
114
+ respond wait, @link_deferred.promise
115
+ end
116
+
117
+ def symlink(old_path, new_path, wait: true)
118
+ assert_type(String, old_path, "old_path must be a String")
119
+ assert_type(String, new_path, "new_path must be a String")
120
+ @symlink_deferred = @reactor.defer
121
+
122
+ request = ::MTLibuv::Ext.allocate_request_fs
123
+ pre_check @symlink_deferred, request, ::MTLibuv::Ext.fs_symlink(@reactor, request, old_path, new_path, 0, callback(:on_symlink, request.address))
124
+ respond wait, @symlink_deferred.promise
125
+ end
126
+
127
+ def readlink(path, wait: true)
128
+ assert_type(String, path, "path must be a String")
129
+ @readlink_deferred = @reactor.defer
130
+
131
+ request = ::MTLibuv::Ext.allocate_request_fs
132
+ pre_check @readlink_deferred, request, ::MTLibuv::Ext.fs_readlink(@reactor, request, path, callback(:on_readlink, request.address))
133
+ respond wait, @readlink_deferred.promise
134
+ end
135
+
136
+ def chown(path, uid, gid, wait: true)
137
+ assert_type(String, path, "path must be a String")
138
+ assert_type(Integer, uid, "uid must be an Integer")
139
+ assert_type(Integer, gid, "gid must be an Integer")
140
+ @chown_deferred = @reactor.defer
141
+
142
+ request = ::MTLibuv::Ext.allocate_request_fs
143
+ pre_check @chown_deferred, request, ::MTLibuv::Ext.fs_chown(@reactor, request, path, uid, gid, callback(:on_chown, request.address))
144
+ respond wait, @chown_deferred.promise
145
+ end
146
+
147
+
148
+ private
149
+
150
+
151
+ def on_unlink(req)
152
+ if post_check(req, @unlink_deferred)
153
+ path = req[:path]
154
+ cleanup(req)
155
+ @reactor.exec { @unlink_deferred.resolve(path) }
156
+ end
157
+ @unlink_deferred = nil
158
+ end
159
+
160
+ def on_mkdir(req)
161
+ if post_check(req, @mkdir_deferred)
162
+ path = req[:path]
163
+ cleanup(req)
164
+ @reactor.exec { @mkdir_deferred.resolve(path) }
165
+ end
166
+ @mkdir_deferred = nil
167
+ end
168
+
169
+ def on_rmdir(req)
170
+ if post_check(req, @rmdir_deferred)
171
+ path = req[:path]
172
+ cleanup(req)
173
+ @reactor.exec { @rmdir_deferred.resolve(path) }
174
+ end
175
+ @rmdir_deferred = nil
176
+ end
177
+
178
+ def on_readdir(req)
179
+ if post_check(req, @readdir_deferred)
180
+ num_files = req[:result]
181
+
182
+ info = ::MTLibuv::Ext::UvDirent.new
183
+ files = []
184
+ ret = 1
185
+ loop do
186
+ ret = ::MTLibuv::Ext.fs_readdir_next(req, info)
187
+ files << [info[:name], info[:type]]
188
+
189
+ # EOF is the alternative
190
+ break unless ret == 0
191
+ end
192
+
193
+ cleanup(req)
194
+ @reactor.exec { @readdir_deferred.resolve(files) }
195
+ end
196
+ @readdir_deferred = nil
197
+ end
198
+
199
+ def on_rename(req)
200
+ if post_check(req, @rename_deferred)
201
+ path = req[:path]
202
+ cleanup(req)
203
+ @reactor.exec { @rename_deferred.resolve(path) }
204
+ end
205
+ @rename_deferred = nil
206
+ end
207
+
208
+ def on_chmod(req)
209
+ if post_check(req, @chmod_deferred)
210
+ path = req[:path]
211
+ cleanup(req)
212
+ @reactor.exec { @chmod_deferred.resolve(path) }
213
+ end
214
+ @chmod_deferred = nil
215
+ end
216
+
217
+ def on_utime(req)
218
+ if post_check(req, @utime_deferred)
219
+ path = req[:path]
220
+ cleanup(req)
221
+ @reactor.exec { @utime_deferred.resolve(path) }
222
+ end
223
+ @utime_deferred = nil
224
+ end
225
+
226
+ def on_link(req)
227
+ if post_check(req, @link_deferred)
228
+ path = req[:path]
229
+ cleanup(req)
230
+ @reactor.exec { @link_deferred.resolve(path) }
231
+ end
232
+ @link_deferred = nil
233
+ end
234
+
235
+ def on_symlink(req)
236
+ if post_check(req, @symlink_deferred)
237
+ path = req[:path]
238
+ cleanup(req)
239
+ @reactor.exec { @symlink_deferred.resolve(path) }
240
+ end
241
+ @symlink_deferred = nil
242
+ end
243
+
244
+ def on_readlink(req)
245
+ if post_check(req, @readlink_deferred)
246
+ string_ptr = req[:ptr]
247
+ path = string_ptr.null? ? nil : string_ptr.read_string_to_null
248
+ cleanup(req)
249
+ @reactor.exec { @readlink_deferred.resolve(path) }
250
+ end
251
+ @readlink_deferred = nil
252
+ end
253
+
254
+ def on_chown(req)
255
+ if post_check(req, @chown_deferred)
256
+ path = req[:path]
257
+ cleanup(req)
258
+ @reactor.exec { @chown_deferred.resolve(path) }
259
+ end
260
+ @chown_deferred = nil
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ class FSEvent < Handle
5
+
6
+
7
+ define_callback function: :on_fs_event, params: [:pointer, :string, :int, :int]
8
+
9
+
10
+ EVENTS = {1 => :rename, 2 => :change}.freeze
11
+
12
+
13
+ def initialize(reactor, path)
14
+ @reactor = reactor
15
+
16
+ fs_event_ptr = ::MTLibuv::Ext.allocate_handle_fs_event
17
+ error = check_result ::MTLibuv::Ext.fs_event_init(reactor.handle, fs_event_ptr, path, callback(:on_fs_event, fs_event_ptr.address), 0)
18
+
19
+ super(fs_event_ptr, error)
20
+ end
21
+
22
+
23
+ private
24
+
25
+
26
+ def on_fs_event(handle, filename, events, status)
27
+ e = check_result(status)
28
+
29
+ if e
30
+ reject(e)
31
+ else
32
+ # notify of a change
33
+ @reactor.exec { defer.notify(filename, EVENTS[events]) }
34
+ end
35
+ end
36
+ end
37
+ end