noderb 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README.md +157 -7
  2. data/ext/noderb_extension/extconf.rb +1 -3
  3. data/ext/noderb_extension/libuv/BSDmakefile +2 -0
  4. data/ext/noderb_extension/libuv/all.gyp +326 -0
  5. data/ext/noderb_extension/libuv/config-mingw.mk +0 -1
  6. data/ext/noderb_extension/libuv/config-unix.mk +7 -1
  7. data/ext/noderb_extension/libuv/create-msvs-files.bat +13 -6
  8. data/ext/noderb_extension/libuv/{build/gyp_uv → gyp_uv} +1 -2
  9. data/ext/noderb_extension/libuv/include/uv.h +5 -0
  10. data/ext/noderb_extension/libuv/src/eio/config_cygwin.h +3 -0
  11. data/ext/noderb_extension/libuv/src/eio/config_freebsd.h +3 -0
  12. data/ext/noderb_extension/libuv/src/eio/config_sunos.h +3 -0
  13. data/ext/noderb_extension/libuv/src/eio/ecb.h +1 -1
  14. data/ext/noderb_extension/libuv/src/eio/eio.c +8 -1
  15. data/ext/noderb_extension/libuv/src/uv-common.c +1 -0
  16. data/ext/noderb_extension/libuv/src/uv-sunos.c +1 -1
  17. data/ext/noderb_extension/libuv/src/uv-unix.c +72 -59
  18. data/ext/noderb_extension/libuv/src/win/core.c +3 -0
  19. data/ext/noderb_extension/libuv/src/win/internal.h +11 -0
  20. data/ext/noderb_extension/libuv/src/win/ntdll.h +130 -0
  21. data/ext/noderb_extension/libuv/src/win/pipe.c +105 -27
  22. data/ext/noderb_extension/libuv/src/win/process.c +76 -5
  23. data/ext/noderb_extension/libuv/src/win/req.c +7 -0
  24. data/ext/noderb_extension/libuv/src/win/winapi.c +52 -0
  25. data/ext/noderb_extension/libuv/test/benchmark-pound.c +50 -48
  26. data/ext/noderb_extension/libuv/test/echo-server.c +2 -2
  27. data/ext/noderb_extension/libuv/test/test-list.h +2 -0
  28. data/ext/noderb_extension/libuv/test/test-spawn.c +48 -1
  29. data/ext/noderb_extension/noderb.c +38 -339
  30. data/ext/noderb_extension/noderb.h +18 -2
  31. data/ext/noderb_extension/noderb_common.h +13 -0
  32. data/ext/noderb_extension/noderb_dns.c +37 -0
  33. data/ext/noderb_extension/noderb_dns.h +15 -0
  34. data/ext/noderb_extension/noderb_process.c +126 -0
  35. data/ext/noderb_extension/noderb_process.h +17 -0
  36. data/ext/noderb_extension/noderb_tcp.c +127 -0
  37. data/ext/noderb_extension/noderb_tcp.h +19 -0
  38. data/ext/noderb_extension/noderb_timers.c +58 -0
  39. data/ext/noderb_extension/noderb_timers.h +16 -0
  40. data/ext/noderb_extension/noderb_tools.c +127 -0
  41. data/ext/noderb_extension/noderb_tools.h +33 -0
  42. data/lib/noderb/dns.rb +11 -0
  43. data/lib/noderb/next_tick.rb +2 -1
  44. data/lib/noderb/tcp.rb +27 -0
  45. data/lib/noderb/timers.rb +24 -0
  46. data/lib/noderb/version.rb +1 -1
  47. data/lib/noderb.rb +6 -1
  48. metadata +23 -7
  49. data/ext/noderb_extension/libuv/build/all.gyp +0 -254
  50. data/ext/noderb_extension/libuv/doc/desired-api.md +0 -159
  51. /data/ext/noderb_extension/libuv/{build/common.gypi → common.gypi} +0 -0
@@ -1,361 +1,60 @@
1
+ #include <noderb_common.h>
1
2
  #include <noderb.h>
2
3
 
4
+ #include <noderb_process.h>
5
+ #include <noderb_tcp.h>
6
+ #include <noderb_dns.h>
7
+ #include <noderb_timers.h>
8
+ #include <noderb_tools.h>
9
+
10
+ // Core NodeRb module
3
11
  VALUE nodeRb;
12
+ // Pointer for saving native data
4
13
  VALUE nodeRbPointer;
5
- VALUE nodeRbConnection;
6
- VALUE nodeRbProcess;
7
-
8
- VALUE nodeRbModules;
9
-
10
- int nodeRbNextTickStatus = 0;
11
-
12
- typedef struct {
13
-
14
- } nodeRb_next_tick_handle;
15
-
16
- typedef struct {
17
- uv_write_t req;
18
- uv_buf_t buf;
19
- } write_req_t;
20
-
21
- typedef struct {
22
- long connection;
23
- } nodeRb_client;
24
-
25
- typedef struct {
26
- long target;
27
- uv_pipe_t* stdout;
28
- uv_pipe_t* stdin;
29
- uv_pipe_t* stderr;
30
- } nodeRb_process_handle;
31
-
32
-
33
- VALUE nodeRb_register_instance(VALUE self, VALUE instance) {
34
- rb_ary_push(rb_iv_get(self, "@instances"), instance);
35
- }
36
-
37
- VALUE nodeRb_unregister_instance(VALUE self, VALUE instance) {
38
- rb_ary_delete(rb_iv_get(self, "@instances"), instance);
39
- }
40
-
41
- VALUE nodeRb_get_class_from_id(long id) {
42
- return rb_funcall(rb_const_get(rb_cObject, rb_intern("ObjectSpace")), rb_intern("_id2ref"), 1, rb_int2inum(id));
43
- }
44
-
45
- int nodeRb_handle_error(int e) {
46
- if (e) {
47
- uv_err_t error = uv_last_error();
48
- fprintf(stderr, "%s\n", uv_strerror(error));
49
- return 1;
50
- } else {
51
- return 0;
52
- }
53
- };
54
-
55
- void nodeRb_next_tick(uv_idle_t* handle, int status) {
56
- uv_idle_stop(handle);
57
- free(handle);
58
- nodeRbNextTickStatus = 0;
59
- rb_funcall(nodeRb, rb_intern("next_tick_execute"), 0);
60
- }
61
-
62
- VALUE nodeRb_nextTick(VALUE self) {
63
- if(nodeRbNextTickStatus == 0){
64
- uv_idle_t* handle = malloc(sizeof(uv_idle_t));
65
- uv_idle_init(handle);
66
- nodeRbNextTickStatus = 1;
67
- uv_idle_start(handle, nodeRb_next_tick);
68
- }
69
- }
70
-
71
- VALUE nodeRb_start(VALUE self) {
72
- // Let the loop run
73
- uv_ref();
74
- // Run Ruby
75
- if (rb_block_given_p()) {
76
- rb_yield(Qnil);
77
- }
78
- // Start loop
79
- uv_run();
80
- };
81
-
82
- void nodeRb_after_write(uv_write_t* req, int status) {
83
- write_req_t* wr;
84
-
85
- if (status) {
86
- uv_err_t err = uv_last_error();
87
- fprintf(stderr, "uv_write error: %s\n", uv_strerror(err));
88
- return;
89
- }
90
-
91
- wr = (write_req_t*) req;
92
- free(wr);
93
-
94
- }
95
-
96
- VALUE nodeRb_send_data(VALUE self, VALUE data) {
97
- write_req_t* wr = malloc(sizeof (write_req_t));
98
- wr->buf.base = rb_string_value_cstr(&data);
99
- wr->buf.len = RSTRING_LEN(data);
100
- VALUE rhandler = rb_iv_get(self, "@_handle");
101
- uv_stream_t *handle;
102
- Data_Get_Struct(rhandler, uv_stream_t, handle);
103
- uv_write(&wr->req, handle, &wr->buf, 1, nodeRb_after_write);
104
- }
105
-
106
- void nodeRb_on_close(uv_handle_t* client) {
107
- nodeRb_client *client_data = client->data;
108
- VALUE object = nodeRb_get_class_from_id(client_data->connection);
109
- rb_funcall(object, rb_intern("on_close"), 0, 0);
110
- nodeRb_unregister_instance(nodeRb, object);
111
- rb_iv_set(object, "@_handle", Qnil);
112
- free(client_data);
113
- free(client);
114
- client_data = NULL;
115
- }
116
14
 
117
- void nodeRb_on_shutdown(uv_shutdown_t* req, int status) {
118
- uv_close((uv_handle_t*) req->handle, nodeRb_on_close);
119
- free(req);
15
+ // Core module of NodeRb
16
+ VALUE nodeRb_get_nodeRb_module(){
17
+ return nodeRb;
120
18
  }
121
19
 
122
- VALUE nodeRb_close_connection(VALUE self) {
123
- uv_shutdown_t* req = malloc(sizeof (uv_shutdown_t));
124
- VALUE rhandler = rb_iv_get(self, "@_handle");
125
- uv_stream_t *handle;
126
- Data_Get_Struct(rhandler, uv_stream_t, handle);
127
- uv_shutdown(req, handle, nodeRb_on_shutdown);
20
+ // NodeRb pointer is used for wrapping native structs into Ruby
21
+ VALUE nodeRb_get_nodeRb_pointer(){
22
+ return nodeRbPointer;
128
23
  }
129
24
 
130
- void nodeRb_on_read(uv_stream_t* client, ssize_t nread, uv_buf_t buf) {
131
- nodeRb_client *client_data = client->data;
132
- if (nread < 0) {
133
- if (buf.base) {
134
- free(buf.base);
135
- }
136
- return;
137
- }
138
-
139
- if (nread == 0) {
140
- free(buf.base);
141
- return;
142
- }
143
- rb_funcall(nodeRb_get_class_from_id(client_data->connection), rb_intern("on_data"), 1, rb_str_new2(buf.base));
144
- free(buf.base);
145
- }
146
-
147
- uv_buf_t nodeRb_read_alloc(uv_stream_t* handle, size_t suggested_size) {
148
- uv_buf_t buf;
149
- buf.base = (char*) malloc(suggested_size);
150
- buf.len = suggested_size;
151
- return buf;
152
- }
153
-
154
- void nodeRb_on_server_connect(uv_stream_t* server, int status) {
155
- nodeRb_client *client_data = malloc(sizeof (nodeRb_client));
156
- uv_stream_t *client = malloc(sizeof (uv_tcp_t));
157
- uv_tcp_init((uv_tcp_t*) client);
158
- int r = uv_accept(server, client);
159
- if (nodeRb_handle_error(r)) return;
160
- VALUE clazz = rb_path2class(server->data);
161
- VALUE obj = rb_funcall(clazz, rb_intern("new"), 0, 0);
162
- nodeRb_register_instance(nodeRb, obj);
163
- rb_funcall(obj, rb_intern("on_connect"), 0, 0);
164
- rb_iv_set(obj, "@_handle", Data_Wrap_Struct(nodeRbPointer, 0, NULL, client));
165
- long id = rb_num2long(rb_obj_id(obj));
166
- client_data->connection = id;
167
- client->data = client_data;
168
- uv_read_start(client, nodeRb_read_alloc, nodeRb_on_read);
169
- }
170
-
171
- VALUE nodeRb_startServer(VALUE self, VALUE address, VALUE port, VALUE clazz) {
172
- uv_tcp_t *server = malloc(sizeof (uv_tcp_t));
173
- uv_tcp_init(server);
174
- struct sockaddr_in socket = uv_ip4_addr(rb_string_value_cstr(&address), (int) rb_num2long(port));
175
- int r = uv_tcp_bind(server, socket);
176
- if (nodeRb_handle_error(r)) return Qnil;
177
- r = uv_listen((uv_stream_t*) server, 128, nodeRb_on_server_connect);
178
- if (nodeRb_handle_error(r)) return Qnil;
179
- VALUE name = rb_class_name(clazz);
180
- server->data = rb_string_value_cstr(&name);
181
- };
182
-
183
- void nodeRb_on_client_connect(uv_connect_t* client, int status) {
184
- nodeRb_client *client_data = client->handle->data;
185
- VALUE obj = nodeRb_get_class_from_id(client_data->connection);
186
- rb_iv_set(obj, "@_handle", Data_Wrap_Struct(nodeRbPointer, 0, NULL, client->handle));
187
- rb_funcall(obj, rb_intern("on_connect"), 0, 0);
188
- uv_read_start((uv_stream_t*) client->handle, nodeRb_read_alloc, nodeRb_on_read);
189
- }
190
-
191
- VALUE nodeRb_startClient(VALUE self, VALUE address, VALUE port, VALUE clazz) {
192
- uv_tcp_t *handle = malloc(sizeof (uv_tcp_t));
193
- uv_tcp_init(handle);
194
- uv_connect_t *connect = malloc(sizeof (uv_connect_t));
195
- struct sockaddr_in socket = uv_ip4_addr(rb_string_value_cstr(&address), (int) rb_num2long(port));
196
- int r = uv_tcp_connect(connect, handle, socket, nodeRb_on_client_connect);
197
- if (nodeRb_handle_error(r)) return Qnil;
198
- nodeRb_client *client_data = malloc(sizeof (nodeRb_client));
199
- VALUE obj = clazz;
200
- long id = rb_num2long(rb_obj_id(obj));
201
- client_data->connection = id;
202
- handle->data = client_data;
203
- };
204
-
205
- void nodeRb_process_close(uv_handle_t* handle) {
206
-
207
- }
208
-
209
- void nodeRb_process_write_after(uv_write_t* req, int status) {
210
-
211
- }
212
-
213
- VALUE nodeRb_process_write(VALUE self, VALUE data) {
214
- uv_process_t *handle;
215
- Data_Get_Struct(rb_iv_get(self, "@_handle"), uv_process_t, handle);
216
- uv_write_t write_req;
217
- uv_buf_t buf;
218
- char* buffer = rb_string_value_cstr(&data);
219
- buf.base = buffer;
220
- buf.len = sizeof (buffer);
221
- nodeRb_process_handle* nhandle = (nodeRb_process_handle*) handle->data;
222
- uv_write(&write_req, (uv_stream_t*) nhandle->stdin, &buf, 1, nodeRb_process_write_after);
223
- }
224
-
225
- void nodeRb_process_stdout_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
226
- uv_err_t err = uv_last_error();
227
- long id = ((nodeRb_process_handle*) handle->data)->target;
228
- VALUE clazz = nodeRb_get_class_from_id(id);
229
- if (nread > 0) {
230
- rb_funcall(clazz, rb_intern("on_stdout"), 1, rb_str_new(buf.base, nread));
231
- }
232
- if (nread < 0) {
233
- if (err.code == UV_EOF) {
234
- //uv_close((uv_handle_t*) handle, nodeRb_process_close);
235
- }
236
- }
237
- free(buf.base);
238
- }
239
-
240
- void nodeRb_process_stderr_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
241
- uv_err_t err = uv_last_error();
242
- long id = ((nodeRb_process_handle*) handle->data)->target;
243
- VALUE clazz = nodeRb_get_class_from_id(id);
244
- if (nread > 0) {
245
- rb_funcall(clazz, rb_intern("on_stderr"), 1, rb_str_new(buf.base, nread));
246
- }
247
- if (nread < 0) {
248
- if (err.code == UV_EOF) {
249
- //uv_close((uv_handle_t*) handle, nodeRb_process_close);
250
- }
251
- }
252
- free(buf.base);
253
- }
254
-
255
- VALUE nodeRb_process_kill(VALUE self, VALUE signal) {
256
- uv_process_t *handle;
257
- Data_Get_Struct(rb_iv_get(self, "@_handle"), uv_process_t, handle);
258
- uv_process_kill(handle, (int) rb_num2int(signal));
259
- }
260
-
261
- void nodeRb_process_exit(uv_process_t* handle, int status, int signal) {
262
- nodeRb_process_handle* nhandle = (nodeRb_process_handle*) handle->data;
263
- VALUE clazz = nodeRb_get_class_from_id(nhandle->target);
264
- rb_funcall(clazz, rb_intern("on_exit"), 2, rb_int2inum(status), rb_int2inum(signal));
265
- }
266
-
267
- VALUE nodeRb_startProcess(VALUE self, VALUE executable, VALUE arguments, VALUE environment, VALUE directory, VALUE clazz) {
268
- uv_process_options_t options = {0};
269
- // On process exit
270
- options.exit_cb = nodeRb_process_exit;
271
- // Executable
272
- options.file = rb_string_value_cstr(&executable);
273
- // Arguments
274
- long len;
275
- len = RARRAY_LEN(arguments);
276
- char* args[len + 2];
277
- args[0] = rb_string_value_cstr(&executable);
278
- args[len + 1] = NULL;
279
- options.args = args;
280
- if (len > 0) {
281
- long i;
282
- VALUE *arr = RARRAY_PTR(arguments);
283
- for (i = 0; i < len; i++) {
284
- options.args[i + 1] = rb_string_value_cstr(&arr[i]);
285
- }
286
- }
287
- // Environment
288
- len = RARRAY_LEN(environment);
289
- char* env[len+1];
290
- options.env = env;
291
- options.env[len] = NULL;
292
- if (len > 0) {
293
- long i;
294
- VALUE *arr = RARRAY_PTR(environment);
295
- for (i = 0; i < len; i++) {
296
- options.env[i] = rb_string_value_cstr(&arr[i]);
297
- }
298
- }
299
-
300
- // Working directory
301
- options.cwd = rb_string_value_cstr(&directory);
302
- // NodeRb helpers
303
- nodeRb_process_handle* nhandle = malloc(sizeof(nodeRb_process_handle));
304
- nhandle->target = rb_num2long(rb_obj_id(clazz));
305
- // Be safe of GC
306
- nodeRb_register_instance(nodeRb, clazz);
307
- // stdin/out/err
308
- uv_pipe_t* stdout = malloc(sizeof(uv_pipe_t));
309
- uv_pipe_t* stdin = malloc(sizeof(uv_pipe_t));
310
- uv_pipe_t* stderr = malloc(sizeof(uv_pipe_t));
311
- uv_pipe_init(stdout);
312
- uv_pipe_init(stdin);
313
- uv_pipe_init(stderr);
314
- options.stdout_stream = stdout;
315
- options.stdin_stream = stdin;
316
- options.stderr_stream = stderr;
317
- stdout->data = nhandle;
318
- stderr->data = nhandle;
319
- nhandle->stdin = stdin;
320
- // libuv handle
321
- uv_process_t* handle = malloc(sizeof(uv_process_t));
322
- handle->data = nhandle;
323
- // Save reference into Ruby object
324
- rb_iv_set(clazz, "@_handle", Data_Wrap_Struct(nodeRbPointer, 0, NULL, handle));
325
- // spawn process
326
- uv_spawn(handle, options);
327
- // Listen to stdout/err
328
- uv_read_start((uv_stream_t*) stdout, nodeRb_read_alloc, nodeRb_process_stdout_read);
329
- uv_read_start((uv_stream_t*) stderr, nodeRb_read_alloc, nodeRb_process_stderr_read);
330
- // call back ruby
331
- rb_funcall(clazz, rb_intern("on_start"), 0);
332
- };
333
-
334
25
  void Init_noderb_extension() {
335
- // Initialize
26
+ // Initialize event loop, but not start it
336
27
  uv_init();
337
28
  // Define module
338
29
  nodeRb = rb_define_module("NodeRb");
339
- nodeRbPointer = rb_define_class_under(nodeRb, "Pointer", rb_cObject);
340
- nodeRbConnection = rb_define_module_under(nodeRb, "Connection");
341
- nodeRbProcess = rb_define_module_under(nodeRb, "Process");
30
+ // Define native pointer
31
+ nodeRbPointer = rb_define_class_under(nodeRb, "NativePointer", rb_cObject);
32
+ // Define handlers of events
33
+ VALUE nodeRbConnection = rb_define_module_under(nodeRb, "Connection");
34
+ VALUE nodeRbProcess = rb_define_module_under(nodeRb, "Process");
342
35
  // Define connection methods
343
- rb_define_method(nodeRbConnection, "write", nodeRb_send_data, 1);
344
- rb_define_method(nodeRbConnection, "close_connection", nodeRb_close_connection, 0);
36
+ rb_define_method(nodeRbConnection, "write_data", nodeRb_tcp_send_data, 1);
37
+ rb_define_method(nodeRbConnection, "close_connection", nodeRb_tcp_close_connection, 0);
345
38
  // Define process methods
346
- rb_define_method(nodeRbProcess, "write", nodeRb_process_write, 1);
347
- rb_define_method(nodeRbProcess, "kill", nodeRb_process_kill, 1);
348
- // Run code on next tick
349
- rb_define_singleton_method(nodeRb, "native_next_tick", nodeRb_nextTick, 0);
39
+ rb_define_method(nodeRbProcess, "write_data", nodeRb_process_write, 1);
40
+ rb_define_method(nodeRbProcess, "kill_process", nodeRb_process_kill, 1);
41
+ // Define utility methods
42
+ rb_define_singleton_method(nodeRb, "next_tick_native", nodeRb_nextTick, 0);
43
+ // DNS related methods
44
+ rb_define_singleton_method(nodeRb, "resolve_native", nodeRb_dns_resolve, 2);
45
+ // Timer related functions
46
+ rb_define_singleton_method(nodeRb, "once_native", nodeRb_timers_once, 3);
47
+ VALUE timer = rb_define_module_under(nodeRb, "Timer");
48
+ rb_define_method(timer, "stop_timer", nodeRb_timers_stop, 0);
350
49
  // Define starting methods
351
50
  rb_define_singleton_method(nodeRb, "start", nodeRb_start, 0);
352
- rb_define_singleton_method(nodeRb, "start_server", nodeRb_startServer, 3);
353
- rb_define_singleton_method(nodeRb, "start_client", nodeRb_startClient, 3);
51
+ rb_define_singleton_method(nodeRb, "start_server_native", nodeRb_tcp_startServer, 3);
52
+ rb_define_singleton_method(nodeRb, "start_client_native", nodeRb_tcp_startClient, 3);
354
53
  rb_define_singleton_method(nodeRb, "start_process", nodeRb_startProcess, 5);
355
54
  // Memory management
356
55
  rb_iv_set(nodeRb, "@instances", rb_ary_new());
357
- rb_define_singleton_method(nodeRb, "register_instance", nodeRb_register_instance, 1);
358
- rb_define_singleton_method(nodeRb, "unregister_instance", nodeRb_unregister_instance, 1);
56
+ rb_define_singleton_method(nodeRb, "register_instance", nodeRb_registerInstance, 1);
57
+ rb_define_singleton_method(nodeRb, "unregister_instance", nodeRb_unregisterInstance, 1);
359
58
  // Modules
360
- nodeRbModules = rb_define_module_under(nodeRb, "Modules");
59
+ VALUE nodeRbModules = rb_define_module_under(nodeRb, "Modules");
361
60
  }
@@ -1,2 +1,18 @@
1
- #include <libuv/include/uv.h>
2
- #include <ruby.h>
1
+ #ifndef NODERB_H
2
+ #define NODERB_H
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ VALUE nodeRb_get_nodeRb_module();
9
+ VALUE nodeRb_get_nodeRb_pointer();
10
+
11
+ void Init_noderb_extension();
12
+
13
+ #ifdef __cplusplus
14
+ }
15
+ #endif
16
+
17
+ #endif /* NODERB_H */
18
+
@@ -0,0 +1,13 @@
1
+ #include <libuv/include/uv.h>
2
+ #include <ruby.h>
3
+
4
+ #define NODERB_BASIC_HANDLE \
5
+ long target; \
6
+ char* target_callback; \
7
+ void* proxy;
8
+
9
+ typedef struct {
10
+ NODERB_BASIC_HANDLE
11
+ } nodeRb_basic_handle;
12
+
13
+ #define rb_num2int(x) NUM2LONG(x)
@@ -0,0 +1,37 @@
1
+ #include <noderb_common.h>
2
+
3
+ #include <noderb_dns.h>
4
+ #include <noderb_tools.h>
5
+
6
+ typedef struct {
7
+ long target;
8
+ } nodeRb_dns_handle;
9
+
10
+ void nodeRb_dns_resolved(uv_getaddrinfo_t* handle, int status, struct addrinfo* res){
11
+ // Load data
12
+ nodeRb_dns_handle* data = (nodeRb_dns_handle*) handle->data;
13
+ // Get resolved address
14
+ char address[INET_ADDRSTRLEN];
15
+ inet_ntop(AF_INET, &(((struct sockaddr_in*) res->ai_addr)->sin_addr), address, INET_ADDRSTRLEN);
16
+ // Call back
17
+ VALUE callback = nodeRb_get_class_from_id(data->target);
18
+ rb_funcall(callback, rb_intern("call"), 1, rb_str_new2(address));
19
+ // Let callback GC
20
+ nodeRb_unregister_instance(callback);
21
+ free(handle);
22
+ free(data);
23
+ };
24
+
25
+ VALUE nodeRb_dns_resolve(VALUE self, VALUE host, VALUE callback){
26
+ // Allocate memory
27
+ uv_getaddrinfo_t* handle = malloc(sizeof(uv_getaddrinfo_t));
28
+ nodeRb_dns_handle* data = malloc(sizeof(nodeRb_dns_handle));
29
+ // Save from GC
30
+ nodeRb_register_instance(callback);
31
+ // Save data
32
+ data->target = rb_num2long(rb_obj_id(callback));
33
+ // Resolve
34
+ uv_getaddrinfo(handle, nodeRb_dns_resolved, rb_string_value_cstr(&host), NULL, NULL);
35
+ // Save callback
36
+ handle->data = data;
37
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef NODERB_DNS_H
2
+ #define NODERB_DNS_H
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ VALUE nodeRb_dns_resolve(VALUE self, VALUE host, VALUE callback);
9
+
10
+ #ifdef __cplusplus
11
+ }
12
+ #endif
13
+
14
+ #endif /* NODERB_DNS_H */
15
+
@@ -0,0 +1,126 @@
1
+ #include <noderb_common.h>
2
+ #include <noderb_process.h>
3
+ #include <noderb.h>
4
+ #include <noderb_tools.h>
5
+
6
+ typedef struct {
7
+ NODERB_BASIC_HANDLE
8
+ uv_pipe_t* stdout;
9
+ uv_pipe_t* stdin;
10
+ uv_pipe_t* stderr;
11
+ } nodeRb_process_handle;
12
+
13
+ typedef struct {
14
+ NODERB_BASIC_HANDLE
15
+ } nodeRb_process_read_handle;
16
+
17
+ void nodeRb_process_close(uv_handle_t* handle) {
18
+ nodeRb_process_handle* process_handle = (nodeRb_process_handle*) handle->data;
19
+ free(process_handle->stdin);
20
+ free(process_handle->stdout);
21
+ free(process_handle->stderr);
22
+ free(process_handle);
23
+ free(handle);
24
+ }
25
+
26
+ VALUE nodeRb_process_write(VALUE self, VALUE data) {
27
+ // Read data from Ruby
28
+ uv_process_t *handle;
29
+ Data_Get_Struct(rb_iv_get(self, "@_handle"), uv_process_t, handle);
30
+ uv_write_t write_req;
31
+ uv_buf_t buf;
32
+ // Get data to write from Ruby
33
+ char* buffer = rb_string_value_cstr(&data);
34
+ // Get process handle
35
+ nodeRb_process_handle* process_handle = (nodeRb_process_handle*) handle->data;
36
+ // Write data to stream
37
+ nodeRb_write((uv_stream_t*) process_handle->stdin, buffer, sizeof(buffer));
38
+ }
39
+
40
+ VALUE nodeRb_process_kill(VALUE self, VALUE signal) {
41
+ uv_process_t *handle;
42
+ Data_Get_Struct(rb_iv_get(self, "@_handle"), uv_process_t, handle);
43
+ uv_process_kill(handle, (int) rb_num2int(signal));
44
+ }
45
+
46
+ void nodeRb_process_exit(uv_process_t* handle, int status, int signal) {
47
+ nodeRb_process_handle* process_handle = (nodeRb_process_handle*) handle->data;
48
+ VALUE clazz = nodeRb_get_class_from_id(process_handle->target);
49
+ rb_funcall(clazz, rb_intern("on_exit"), 2, rb_int2inum(status), rb_int2inum(signal));
50
+ }
51
+
52
+ VALUE nodeRb_startProcess(VALUE self, VALUE executable, VALUE arguments, VALUE environment, VALUE directory, VALUE clazz) {
53
+ uv_process_options_t options = {0};
54
+ // On process exit
55
+ options.exit_cb = nodeRb_process_exit;
56
+ // Executable
57
+ options.file = rb_string_value_cstr(&executable);
58
+ // Arguments
59
+ long len;
60
+ len = RARRAY_LEN(arguments);
61
+ char* args[len + 2];
62
+ args[0] = rb_string_value_cstr(&executable);
63
+ args[len + 1] = NULL;
64
+ options.args = args;
65
+ if (len > 0) {
66
+ long i;
67
+ VALUE *arr = RARRAY_PTR(arguments);
68
+ for (i = 0; i < len; i++) {
69
+ options.args[i + 1] = rb_string_value_cstr(&arr[i]);
70
+ }
71
+ }
72
+ // Environment
73
+ len = RARRAY_LEN(environment);
74
+ char* env[len+1];
75
+ options.env = env;
76
+ options.env[len] = NULL;
77
+ if (len > 0) {
78
+ long i;
79
+ VALUE *arr = RARRAY_PTR(environment);
80
+ for (i = 0; i < len; i++) {
81
+ options.env[i] = rb_string_value_cstr(&arr[i]);
82
+ }
83
+ }
84
+ // Working directory
85
+ options.cwd = rb_string_value_cstr(&directory);
86
+ // NodeRb helpers
87
+ nodeRb_process_handle* process_handle = malloc(sizeof(nodeRb_process_handle));
88
+ process_handle->target = rb_num2long(rb_obj_id(clazz));
89
+ // Be safe of GC
90
+ nodeRb_register_instance(clazz);
91
+ // stdin
92
+ uv_pipe_t* stdin = malloc(sizeof(uv_pipe_t));
93
+ uv_pipe_init(stdin);
94
+ options.stdin_stream = stdin;
95
+ process_handle->stdin = stdin;
96
+ // stdout
97
+ uv_pipe_t* stdout = malloc(sizeof(uv_pipe_t));
98
+ uv_pipe_init(stdout);
99
+ options.stdout_stream = stdout;
100
+ nodeRb_process_read_handle* stdout_handle = malloc(sizeof(nodeRb_process_read_handle));
101
+ stdout_handle->target = process_handle->target;
102
+ stdout_handle->target_callback = (char*) "on_stdout";
103
+ stdout->data = stdout_handle;
104
+ process_handle->stdout = stdout;
105
+ // stderr
106
+ uv_pipe_t* stderr = malloc(sizeof(uv_pipe_t));
107
+ uv_pipe_init(stderr);
108
+ options.stderr_stream = stderr;
109
+ nodeRb_process_read_handle* stderr_handle = malloc(sizeof(nodeRb_process_read_handle));
110
+ stderr_handle->target = process_handle->target;
111
+ stderr_handle->target_callback = (char*) "on_stderr";
112
+ stderr->data = stderr_handle;
113
+ process_handle->stderr = stderr;
114
+ // libuv handle
115
+ uv_process_t* handle = malloc(sizeof(uv_process_t));
116
+ handle->data = process_handle;
117
+ // Save reference into Ruby object
118
+ rb_iv_set(clazz, "@_handle", Data_Wrap_Struct(nodeRb_get_nodeRb_pointer(), 0, NULL, handle));
119
+ // spawn process
120
+ uv_spawn(handle, options);
121
+ // Listen to stdout/err
122
+ uv_read_start((uv_stream_t*) stdout, nodeRb_read_alloc, nodeRb_read);
123
+ uv_read_start((uv_stream_t*) stderr, nodeRb_read_alloc, nodeRb_read);
124
+ // call back ruby
125
+ rb_funcall(clazz, rb_intern("on_start"), 0);
126
+ };
@@ -0,0 +1,17 @@
1
+ #ifndef NODERB_PROCESS_H
2
+ #define NODERB_PROCESS_H
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ VALUE nodeRb_startProcess(VALUE self, VALUE executable, VALUE arguments, VALUE environment, VALUE directory, VALUE clazz);
9
+ VALUE nodeRb_process_write(VALUE self, VALUE data);
10
+ VALUE nodeRb_process_kill(VALUE self, VALUE signal);
11
+
12
+ #ifdef __cplusplus
13
+ }
14
+ #endif
15
+
16
+ #endif /* NODERB_PROCESS_H */
17
+