iodine 0.5.2 → 0.6.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.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +63 -100
  4. data/bin/raw-rbhttp +12 -7
  5. data/examples/config.ru +8 -7
  6. data/examples/echo.ru +8 -7
  7. data/examples/info.md +41 -35
  8. data/examples/pubsub_engine.ru +12 -12
  9. data/examples/redis.ru +10 -12
  10. data/examples/shootout.ru +19 -42
  11. data/exe/iodine +116 -1
  12. data/ext/iodine/defer.c +1 -1
  13. data/ext/iodine/facil.c +12 -8
  14. data/ext/iodine/facil.h +2 -2
  15. data/ext/iodine/iodine.c +177 -343
  16. data/ext/iodine/iodine.h +18 -72
  17. data/ext/iodine/iodine_caller.c +132 -0
  18. data/ext/iodine/iodine_caller.h +21 -0
  19. data/ext/iodine/iodine_connection.c +841 -0
  20. data/ext/iodine/iodine_connection.h +55 -0
  21. data/ext/iodine/iodine_defer.c +391 -0
  22. data/ext/iodine/iodine_defer.h +7 -0
  23. data/ext/iodine/{rb-fiobj2rb.h → iodine_fiobj2rb.h} +6 -6
  24. data/ext/iodine/iodine_helpers.c +51 -5
  25. data/ext/iodine/iodine_helpers.h +2 -3
  26. data/ext/iodine/iodine_http.c +284 -141
  27. data/ext/iodine/iodine_http.h +2 -2
  28. data/ext/iodine/iodine_json.c +13 -13
  29. data/ext/iodine/iodine_json.h +1 -1
  30. data/ext/iodine/iodine_pubsub.c +573 -823
  31. data/ext/iodine/iodine_pubsub.h +15 -27
  32. data/ext/iodine/{rb-rack-io.c → iodine_rack_io.c} +30 -8
  33. data/ext/iodine/{rb-rack-io.h → iodine_rack_io.h} +1 -0
  34. data/ext/iodine/iodine_store.c +136 -0
  35. data/ext/iodine/iodine_store.h +20 -0
  36. data/ext/iodine/iodine_tcp.c +385 -0
  37. data/ext/iodine/iodine_tcp.h +9 -0
  38. data/lib/iodine.rb +73 -171
  39. data/lib/iodine/connection.rb +34 -0
  40. data/lib/iodine/pubsub.rb +5 -18
  41. data/lib/iodine/rack_utils.rb +43 -0
  42. data/lib/iodine/version.rb +1 -1
  43. data/lib/rack/handler/iodine.rb +1 -182
  44. metadata +17 -18
  45. data/ext/iodine/iodine_protocol.c +0 -689
  46. data/ext/iodine/iodine_protocol.h +0 -13
  47. data/ext/iodine/iodine_websockets.c +0 -550
  48. data/ext/iodine/iodine_websockets.h +0 -17
  49. data/ext/iodine/rb-call.c +0 -156
  50. data/ext/iodine/rb-call.h +0 -70
  51. data/ext/iodine/rb-defer.c +0 -124
  52. data/ext/iodine/rb-registry.c +0 -150
  53. data/ext/iodine/rb-registry.h +0 -34
  54. data/lib/iodine/cli.rb +0 -89
  55. data/lib/iodine/monkeypatch.rb +0 -46
  56. data/lib/iodine/protocol.rb +0 -42
  57. data/lib/iodine/websocket.rb +0 -16
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-11 00:00:00.000000000 Z
11
+ date: 2018-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -214,28 +214,29 @@ files:
214
214
  - ext/iodine/http_mime_parser.h
215
215
  - ext/iodine/iodine.c
216
216
  - ext/iodine/iodine.h
217
+ - ext/iodine/iodine_caller.c
218
+ - ext/iodine/iodine_caller.h
219
+ - ext/iodine/iodine_connection.c
220
+ - ext/iodine/iodine_connection.h
221
+ - ext/iodine/iodine_defer.c
222
+ - ext/iodine/iodine_defer.h
223
+ - ext/iodine/iodine_fiobj2rb.h
217
224
  - ext/iodine/iodine_helpers.c
218
225
  - ext/iodine/iodine_helpers.h
219
226
  - ext/iodine/iodine_http.c
220
227
  - ext/iodine/iodine_http.h
221
228
  - ext/iodine/iodine_json.c
222
229
  - ext/iodine/iodine_json.h
223
- - ext/iodine/iodine_protocol.c
224
- - ext/iodine/iodine_protocol.h
225
230
  - ext/iodine/iodine_pubsub.c
226
231
  - ext/iodine/iodine_pubsub.h
227
- - ext/iodine/iodine_websockets.c
228
- - ext/iodine/iodine_websockets.h
232
+ - ext/iodine/iodine_rack_io.c
233
+ - ext/iodine/iodine_rack_io.h
234
+ - ext/iodine/iodine_store.c
235
+ - ext/iodine/iodine_store.h
236
+ - ext/iodine/iodine_tcp.c
237
+ - ext/iodine/iodine_tcp.h
229
238
  - ext/iodine/pubsub.c
230
239
  - ext/iodine/pubsub.h
231
- - ext/iodine/rb-call.c
232
- - ext/iodine/rb-call.h
233
- - ext/iodine/rb-defer.c
234
- - ext/iodine/rb-fiobj2rb.h
235
- - ext/iodine/rb-rack-io.c
236
- - ext/iodine/rb-rack-io.h
237
- - ext/iodine/rb-registry.c
238
- - ext/iodine/rb-registry.h
239
240
  - ext/iodine/redis_engine.c
240
241
  - ext/iodine/redis_engine.h
241
242
  - ext/iodine/resp_parser.h
@@ -247,13 +248,11 @@ files:
247
248
  - ext/iodine/websockets.h
248
249
  - iodine.gemspec
249
250
  - lib/iodine.rb
250
- - lib/iodine/cli.rb
251
+ - lib/iodine/connection.rb
251
252
  - lib/iodine/json.rb
252
- - lib/iodine/monkeypatch.rb
253
- - lib/iodine/protocol.rb
254
253
  - lib/iodine/pubsub.rb
254
+ - lib/iodine/rack_utils.rb
255
255
  - lib/iodine/version.rb
256
- - lib/iodine/websocket.rb
257
256
  - lib/rack/handler/iodine.rb
258
257
  - logo.png
259
258
  homepage: https://github.com/boazsegev/iodine
@@ -1,689 +0,0 @@
1
- /*
2
- Copyright: Boaz segev, 2016-2017
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #include "iodine_protocol.h"
8
- #include "iodine_pubsub.h"
9
-
10
- #include "fio_llist.h"
11
- #include "fiobj4sock.h"
12
- #include "pubsub.h"
13
-
14
- #include <ruby/io.h>
15
-
16
- static ID iodine_close_func_id;
17
-
18
- /* *****************************************************************************
19
- The protocol object
20
- ***************************************************************************** */
21
-
22
- typedef struct {
23
- protocol_s protocol;
24
- VALUE handler;
25
- fio_ls_s subscriptions;
26
- } iodine_protocol_s;
27
-
28
- VALUE IodineProtocol;
29
-
30
- static char *iodine_protocol_service = "Iodine Custom Protocol";
31
-
32
- /* *****************************************************************************
33
- Internal helpers
34
- ***************************************************************************** */
35
-
36
- static void iodine_clear_task(intptr_t origin, void *block_) {
37
- Registry.remove((VALUE)block_);
38
- (void)origin;
39
- }
40
-
41
- // static void iodine_perform_task(intptr_t uuid, protocol_s *pr, void *block_)
42
- // {
43
- // if (pr->service == iodine_protocol_service) {
44
- // RubyCaller.call2((VALUE)block_, iodine_call_proc_id, 1, (VALUE *)(pr +
45
- // 1));
46
- // }
47
- // (void)uuid;
48
- // }
49
-
50
- static void iodine_perform_task_and_free(intptr_t uuid, protocol_s *pr,
51
- void *block_) {
52
- if (pr->service == iodine_protocol_service) {
53
- RubyCaller.call2((VALUE)block_, iodine_call_proc_id, 1, (VALUE *)(pr + 1));
54
- }
55
- Registry.remove((VALUE)block_);
56
- (void)uuid;
57
- }
58
-
59
- static void remove_from_registry(intptr_t uuid, void *val) {
60
- Registry.remove((VALUE)val);
61
- (void)uuid;
62
- }
63
- /* *****************************************************************************
64
- Function placeholders
65
- ***************************************************************************** */
66
-
67
- /** Override this callback to handle the event. The default implementation will
68
- * close the connection. */
69
- static VALUE not_implemented_ping(VALUE self) {
70
- sock_close(iodine_get_fd(self));
71
- return Qnil;
72
- }
73
- /** Override this callback to handle the event. */
74
- static VALUE not_implemented(VALUE self) {
75
- (void)(self);
76
- return Qnil;
77
- }
78
-
79
- /** DEPRECATED! Please override {on_drained} instead. */
80
- static VALUE not_implemented_on_ready(VALUE self, VALUE data) {
81
- (void)(self);
82
- (void)(data);
83
- return Qnil;
84
- }
85
-
86
- /** Override this callback to handle the event. */
87
- static VALUE not_implemented_drained(VALUE self) {
88
- RubyCaller.call(self, rb_intern2("on_ready", 8));
89
- (void)(self);
90
- return Qnil;
91
- }
92
-
93
- /** Override this callback to handle the event. */
94
- static VALUE not_implemented2(VALUE self, VALUE data) {
95
- (void)(self);
96
- (void)(data);
97
- return Qnil;
98
- }
99
-
100
- static VALUE dyn_read(int argc, VALUE *argv, VALUE self);
101
- /**
102
- A default on_data implementation will read up to 1Kb into a reusable buffer from
103
- the socket and call the `on_message` callback.
104
-
105
- It is recommended that you implement this callback if messages might require
106
- more then 1Kb of space.
107
- */
108
- static VALUE default_on_data(VALUE self) {
109
- VALUE buff = rb_ivar_get(self, iodine_buff_var_id);
110
- if (buff == Qnil) {
111
- rb_ivar_set(self, iodine_buff_var_id, (buff = rb_str_buf_new(1024)));
112
- }
113
- do {
114
- dyn_read(1, &buff, self);
115
- if (!RSTRING_LEN(buff))
116
- return Qnil;
117
- rb_funcall(self, iodine_on_message_func_id, 1, buff);
118
- } while (RSTRING_LEN(buff) == (ssize_t)rb_str_capacity(buff));
119
- return Qnil;
120
- }
121
-
122
- /* *****************************************************************************
123
- Pub/Sub functions
124
- ***************************************************************************** */
125
-
126
- // clang-format off
127
- /**
128
- Subscribes the connection to a Pub/Sub channel.
129
-
130
- Since this connection's data packaging is unknown, a block (or handler) is required to handle pub/sub events.
131
-
132
- The method accepts 1-2 arguments and an optional block. These are all valid ways
133
- to call the method:
134
-
135
- subscribe("my_stream") {|from, msg| p msg }
136
- subscribe("my_stream", match: :redis) {|from, msg| p msg }
137
- subscribe(to: "my_stream") {|from, msg| p msg }
138
- subscribe to: "my_stream", match: :redis, handler: MyProc
139
-
140
- The first argument must be either a String or a Hash.
141
-
142
- The second, optional, argument must be a Hash (if given).
143
-
144
- The options Hash supports the following possible keys (other keys are ignored, all keys are Symbols):
145
-
146
- :match :: The channel / subject name matching type to be used. Valid value is: `:redis`. Future versions hope to support `:nats` and `:rabbit` patern matching as well.
147
-
148
- :to :: The channel / subject to subscribe to.
149
-
150
- :handler :: and Proc like object, must answer to `call(from, msg)`.
151
-
152
- Returns an {Iodine::PubSub::Subscription} object that answers to:
153
-
154
- close :: closes the connection.
155
- to_s :: returns the subscription's target (stream / channel / subject).
156
- ==(str) :: returns true if the string is an exact match for the target (even if the target itself is a pattern).
157
-
158
- */
159
- static VALUE iodine_proto_subscribe(int argc, VALUE *argv, VALUE self) {
160
- // clang-format on
161
- intptr_t uuid = iodine_get_fd(self);
162
- if (!uuid || (VALUE)uuid == Qnil || uuid < 0)
163
- return Qfalse;
164
- VALUE sub = iodine_subscribe(argc, argv, NULL, IODINE_PUBSUB_GLOBAL);
165
- if (sub == Qnil || sub == Qfalse)
166
- return Qfalse;
167
- Registry.add(sub);
168
-
169
- iodine_protocol_s *pr = iodine_get_cdata(self);
170
-
171
- fio_ls_push(&pr->subscriptions, (void *)sub);
172
- return sub;
173
- }
174
-
175
- /* *****************************************************************************
176
- Published functions
177
- ***************************************************************************** */
178
-
179
- /**
180
- Reads up to `n` bytes from the network connection.
181
- The number of bytes to be read (n) is:
182
- - the number of bytes set in the optional `buffer_or_length` argument.
183
- - the String capacity (not length) of the String passed as the optional
184
- `buffer_or_length` argument.
185
- - 1024 Bytes (1Kb) if the optional `buffer_or_length` is either missing or
186
- contains a String with a capacity less then 1Kb.
187
- Returns a String (either the same one used as the buffer or a new one) on a
188
- successful read.
189
- Returns `nil` if no data was available.
190
- */
191
- static VALUE dyn_read(int argc, VALUE *argv, VALUE self) {
192
- if (argc > 1) {
193
- rb_raise(
194
- rb_eArgError,
195
- "read accepts only one argument - a Fixnum (buffer length) or a String "
196
- "(it's capacity - or 1Kb, whichever's the higher - will be used as "
197
- "buffer's length).");
198
- return Qnil;
199
- }
200
- VALUE buffer = (argc == 1 ? argv[0] : Qnil);
201
- if (buffer != Qnil && TYPE(buffer) != T_FIXNUM && TYPE(buffer) != T_STRING) {
202
- rb_raise(rb_eTypeError,
203
- "buffer should either be a length (a new string will be created) "
204
- "or a string (reading will be limited to the original string's "
205
- "capacity or 1Kb - whichever the larger).");
206
- return Qnil;
207
- }
208
- VALUE str;
209
- long len;
210
- intptr_t fd = iodine_get_fd(self);
211
- if (buffer == Qnil) {
212
- buffer = LONG2FIX(1024);
213
- }
214
- if (TYPE(buffer) == T_FIXNUM) {
215
- len = FIX2LONG(buffer);
216
- if (len <= 0)
217
- len = 1024;
218
- str = rb_str_buf_new(len);
219
- // create a rb_String with X length and take it's pointer
220
- // rb_str_resize(VALUE str, long len)
221
- // RSTRING_PTR(str)
222
- } else {
223
- // take the string's pointer and length
224
- len = rb_str_capacity(buffer);
225
- // make sure the string is modifiable
226
- rb_str_modify(buffer);
227
- // resize the string if needed.
228
- if (len < 1024)
229
- rb_str_resize(buffer, (len = 1024));
230
- str = buffer;
231
- }
232
- ssize_t in = sock_read(fd, RSTRING_PTR(str), len);
233
- // make sure it's binary encoded
234
- rb_enc_associate_index(str, IodineBinaryEncodingIndex);
235
- // set actual size....
236
- if (in > 0)
237
- rb_str_set_len(str, (long)in);
238
- else {
239
- rb_str_set_len(str, 0);
240
- str = Qnil;
241
- }
242
- // return empty string? or fix above if to return Qnil?
243
- return str;
244
- }
245
-
246
- /**
247
- Writes data to the connection. Returns `false` on error and `self` on success.
248
- */
249
- static VALUE dyn_write(VALUE self, VALUE data) {
250
- Check_Type(data, T_STRING);
251
- intptr_t fd = iodine_get_fd(self);
252
- if (sock_write(fd, RSTRING_PTR(data), RSTRING_LEN(data))) {
253
- return Qfalse;
254
- }
255
- return self;
256
- }
257
-
258
- /**
259
- Moves a String to iodine's socket's buffer. This is a zero-copy write and
260
- requires that the string remain unchanged during the process.
261
-
262
- For example, Strings received by `on_message` can't be used, because they use a
263
- recyclable buffer and they will be destroyed once `on_message` returns.
264
- */
265
- static VALUE dyn_write_move(VALUE self, VALUE data) {
266
- Check_Type(data, T_STRING);
267
- Registry.add(data);
268
- intptr_t fd = iodine_get_fd(self);
269
- if (sock_write2(.uuid = fd, .buffer = RSTRING_PTR(data),
270
- .length = RSTRING_LEN(data),
271
- .dealloc = (void (*)(void *))Registry.remove))
272
- return Qfalse;
273
- return self;
274
- }
275
-
276
- /**
277
- Writes data to the connection. The data will be sent as soon as possible without
278
- fragmantation of previously scheduled data.
279
-
280
- Returns `false` on error and `self` on success.
281
- */
282
- static VALUE dyn_write_urgent(VALUE self, VALUE data) {
283
- Check_Type(data, T_STRING);
284
- intptr_t fd = iodine_get_fd(self);
285
- Registry.add(data);
286
- if (sock_write(fd, RSTRING_PTR(data), RSTRING_LEN(data))) {
287
- return Qfalse;
288
- }
289
- return self;
290
- }
291
-
292
- /**
293
- Update's a connection's timeout.
294
-
295
- Returns self.
296
- */
297
- static VALUE dyn_set_timeout(VALUE self, VALUE timeout) {
298
- intptr_t fd = iodine_get_fd(self);
299
- unsigned int tout = FIX2UINT(timeout);
300
- if (tout > 255)
301
- tout = 255;
302
- facil_set_timeout(fd, tout);
303
- return self;
304
- }
305
-
306
- /**
307
- Returns the connection's timeout.
308
- */
309
- static VALUE dyn_get_timeout(VALUE self) {
310
- intptr_t fd = iodine_get_fd(self);
311
- uint8_t tout = facil_get_timeout(fd);
312
- unsigned int tout_int = tout;
313
- return UINT2NUM(tout_int);
314
- }
315
-
316
- /**
317
- Closes a connection.
318
-
319
- The connection will be closed only once all the data was sent.
320
-
321
- Returns self.
322
- */
323
- static VALUE dyn_close(VALUE self) {
324
- intptr_t fd = iodine_get_fd(self);
325
- sock_close(fd);
326
- return self;
327
- }
328
-
329
- /**
330
- Returns a connection's localized ID which is valid for *this process* (not a
331
- machine or internet unique value).
332
-
333
- Once the connection is closed and the `on_close` callback was called, this
334
- method returns `nil`.
335
-
336
- This can be used together with a true process wide UUID to uniquely identify a
337
- connection across the internet.
338
- */
339
- static VALUE dyn_uuid(VALUE self) {
340
- intptr_t uuid = iodine_get_fd(self);
341
- if (!uuid || uuid == -1)
342
- return Qnil;
343
- return LONG2FIX(uuid);
344
- }
345
-
346
- /**
347
- Returns true if the connection is open and false if closed.
348
- */
349
- static VALUE dyn_is_open(VALUE self) {
350
- intptr_t uuid = iodine_get_fd(self);
351
- if (uuid && sock_isvalid(uuid))
352
- return Qtrue;
353
- return Qfalse;
354
- }
355
-
356
- /**
357
- Schedules a block to execute (defers the blocks execution).
358
-
359
- When this function is called by a Protocol instance, a lock on the connection
360
- will be used to prevent multiple tasks / callbacks from running concurrently.
361
- i.e.
362
-
363
- defer { write "this will run in a lock" }
364
-
365
- Otherwise, the deferred task will run acconrding to the requested concurrency
366
- model.
367
-
368
- Iodine.defer { puts "this will run concurrently" }
369
- Iodine.run { puts "this will run concurrently" }
370
-
371
- Tasks scheduled before calling {Iodine.start} will run once for every process.
372
-
373
- Returns the block given (or `false`).
374
-
375
- **Notice**: There's a possibility that the rask will never be called if it was
376
- associated with a specific connection (the method was called as an instance
377
- method) and the connection was closed before the deferred task was performed.
378
- */
379
- static VALUE dyn_defer(int argc, VALUE *argv, VALUE self) {
380
- rb_need_block();
381
- intptr_t fd;
382
- // check arguments.
383
- if (argc > 1)
384
- rb_raise(rb_eArgError, "this function expects no more then 1 (optional) "
385
- "argument.");
386
- else if (argc == 1) {
387
- Check_Type(*argv, T_FIXNUM);
388
- fd = FIX2LONG(*argv);
389
- } else
390
- fd = iodine_get_fd(self);
391
-
392
- if (!sock_isvalid(fd))
393
- return Qfalse;
394
-
395
- VALUE block = rb_block_proc();
396
- if (block == Qnil)
397
- return Qfalse;
398
- Registry.add(block);
399
- facil_defer(.uuid = fd, .task = iodine_perform_task_and_free,
400
- .type = FIO_PR_LOCK_TASK, .arg = (void *)block,
401
- .fallback = iodine_clear_task);
402
- return block;
403
- }
404
-
405
- /* *****************************************************************************
406
- Connection management
407
- ***************************************************************************** */
408
- #define dyn_prot(protocol) ((iodine_protocol_s *)(protocol))
409
-
410
- /** called when a data is available, but will not run concurrently */
411
- static void dyn_protocol_on_data(intptr_t fduuid, protocol_s *protocol) {
412
- (void)(fduuid);
413
- RubyCaller.call(dyn_prot(protocol)->handler, iodine_on_data_func_id);
414
- }
415
- /** called when the socket is ready to be written to. */
416
- static void dyn_protocol_on_ready(intptr_t fduuid, protocol_s *protocol) {
417
- (void)(fduuid);
418
- RubyCaller.call(dyn_prot(protocol)->handler, iodine_on_drained_func_id);
419
- }
420
- /** called when the server is shutting down,
421
- * but before closing the connection. */
422
- static void dyn_protocol_on_shutdown(intptr_t fduuid, protocol_s *protocol) {
423
- (void)(fduuid);
424
- RubyCaller.call(dyn_prot(protocol)->handler, iodine_on_shutdown_func_id);
425
- }
426
-
427
- static void *clear_subscriptions_inGVL(void *pr_) {
428
- iodine_protocol_s *pr = pr_;
429
- while (fio_ls_any(&pr->subscriptions)) {
430
- RubyCaller.call((VALUE)fio_ls_pop(&pr->subscriptions),
431
- iodine_close_func_id);
432
- }
433
- return NULL;
434
- }
435
-
436
- /** called when the connection was closed, but will not run concurrently */
437
- static void dyn_protocol_on_close(intptr_t uuid, protocol_s *protocol) {
438
- RubyCaller.call(dyn_prot(protocol)->handler, iodine_on_close_func_id);
439
- iodine_set_fd(dyn_prot(protocol)->handler, 0);
440
- iodine_set_cdata(dyn_prot(protocol)->handler, NULL);
441
- Registry.remove(dyn_prot(protocol)->handler);
442
- RubyCaller.call_c(clear_subscriptions_inGVL, protocol);
443
- free(protocol);
444
- (void)uuid;
445
- }
446
- /** called when a connection's timeout was reached */
447
- static void dyn_protocol_ping(intptr_t fduuid, protocol_s *protocol) {
448
- (void)(fduuid);
449
- RubyCaller.call(dyn_prot(protocol)->handler, iodine_ping_func_id);
450
- }
451
-
452
- /* *****************************************************************************
453
- Connection management API
454
- *****************************************************************************
455
- */
456
-
457
- /** Update's a connection's handler and timeout. */
458
- static inline protocol_s *dyn_set_protocol(intptr_t fduuid, VALUE handler,
459
- uint8_t timeout) {
460
- Registry.add(handler);
461
- iodine_protocol_s *protocol = malloc(sizeof(*protocol));
462
- if (protocol == NULL) {
463
- Registry.remove(handler);
464
- return NULL;
465
- }
466
- facil_set_timeout(fduuid, timeout);
467
- *protocol = (iodine_protocol_s){
468
- .protocol.on_data = dyn_protocol_on_data,
469
- .protocol.on_close = dyn_protocol_on_close,
470
- .protocol.on_shutdown = dyn_protocol_on_shutdown,
471
- .protocol.on_ready = dyn_protocol_on_ready,
472
- .protocol.ping = dyn_protocol_ping,
473
- .protocol.service = iodine_protocol_service,
474
- .handler = handler,
475
- .subscriptions = FIO_LS_INIT(protocol->subscriptions),
476
- };
477
- iodine_set_fd(handler, fduuid);
478
- iodine_set_cdata(handler, protocol);
479
- RubyCaller.call(handler, iodine_on_open_func_id);
480
- return &protocol->protocol;
481
- }
482
-
483
- static void on_open_dyn_protocol(intptr_t fduuid, void *udata) {
484
- VALUE rb_tout = rb_ivar_get((VALUE)udata, iodine_timeout_var_id);
485
- uint8_t timeout = (TYPE(rb_tout) == T_FIXNUM) ? FIX2UINT(rb_tout) : 0;
486
- VALUE handler = RubyCaller.call((VALUE)udata, iodine_new_func_id);
487
- if (handler == Qnil) {
488
- sock_close(fduuid);
489
- return;
490
- }
491
- facil_attach(fduuid, dyn_set_protocol(fduuid, handler, timeout));
492
- }
493
-
494
- /** Sets up a listening socket. Conncetions received at the assigned port will
495
- be handled by the assigned handler.
496
-
497
- Multiple services (listening sockets) can be registered before starting the
498
- Iodine event loop. */
499
- static VALUE iodine_listen(VALUE self, VALUE port, VALUE handler) {
500
- // validate that the handler is a class and include the Iodine::Protocol
501
- if (TYPE(handler) == T_CLASS) {
502
- // include the Protocol module
503
- // // do we neet to check?
504
- // if (rb_mod_include_p(protocol, rDynProtocol) == Qfalse)
505
- rb_include_module(handler, IodineProtocol);
506
- rb_extend_object(handler, IodineProtocol);
507
- } else {
508
- rb_raise(rb_eTypeError, "The connection handler MUST be of type Class.");
509
- return Qnil;
510
- }
511
- if (TYPE(port) != T_FIXNUM && TYPE(port) != T_STRING)
512
- rb_raise(rb_eTypeError, "The port variable must be a Fixnum or a String.");
513
- if (TYPE(port) == T_FIXNUM)
514
- port = rb_funcall2(port, iodine_to_s_method_id, 0, NULL);
515
- rb_ivar_set(self, rb_intern("_port"), port);
516
- // listen
517
- if (facil_listen(.port = StringValueCStr(port), .udata = (void *)handler,
518
- .on_open = on_open_dyn_protocol) == -1)
519
- return Qnil;
520
- return self;
521
- }
522
-
523
- VALUE dyn_switch_prot(VALUE self, VALUE handler) {
524
- uint8_t timeout;
525
- intptr_t fd = iodine_get_fd(self);
526
- if (TYPE(handler) == T_CLASS) {
527
- // get the timeout
528
- VALUE rb_tout = rb_ivar_get(handler, iodine_timeout_var_id);
529
- timeout = (TYPE(rb_tout) == T_FIXNUM) ? FIX2UINT(rb_tout) : 0;
530
- // include the Protocol module, preventing coder errors
531
- rb_include_module(handler, IodineProtocol);
532
- handler = RubyCaller.call(handler, iodine_new_func_id);
533
- } else {
534
- // include the Protocol module in the object's class
535
- VALUE p_class = rb_obj_class(handler);
536
- // include the Protocol module, preventing coder errors
537
- rb_include_module(p_class, IodineProtocol);
538
- // get the timeout
539
- VALUE rb_tout = rb_ivar_get(p_class, iodine_timeout_var_id);
540
- if (rb_tout == Qnil)
541
- rb_tout = rb_ivar_get(handler, iodine_timeout_var_id);
542
- timeout = (TYPE(rb_tout) == T_FIXNUM) ? FIX2UINT(rb_tout) : 0;
543
- }
544
- if (facil_attach(fd, dyn_set_protocol(fd, handler, timeout)))
545
- return Qnil;
546
- return handler;
547
- }
548
-
549
- static void on_open_dyn_protocol_instance(intptr_t fduuid, void *udata) {
550
- VALUE rb_tout = rb_ivar_get((VALUE)udata, iodine_timeout_var_id);
551
- uint8_t timeout = (TYPE(rb_tout) == T_FIXNUM) ? FIX2UINT(rb_tout) : 0;
552
- protocol_s *pr = dyn_set_protocol(fduuid, (VALUE)udata, timeout);
553
- Registry.remove((VALUE)udata);
554
- facil_attach(fduuid, pr);
555
- }
556
-
557
- /**
558
- Connects (as a TCP/IP client) to a remote TCP/IP server.
559
-
560
- i.e.
561
-
562
- Iodine.connect "example.com", 5000, MyProtocolClass.new
563
-
564
- */
565
- static VALUE iodine_connect(VALUE self, VALUE address, VALUE port,
566
- VALUE handler) {
567
- if (TYPE(handler) == T_CLASS || TYPE(handler) == T_MODULE) {
568
- // include the Protocol module, preventing coder errors
569
- rb_include_module(handler, IodineProtocol);
570
- handler = RubyCaller.call(handler, iodine_new_func_id);
571
- } else {
572
- // include the Protocol module in the object's class
573
- VALUE p_class = rb_obj_class(handler);
574
- // include the Protocol module, preventing coder errors
575
- rb_include_module(p_class, IodineProtocol);
576
- }
577
- if (TYPE(port) != T_FIXNUM && TYPE(port) != T_STRING)
578
- rb_raise(rb_eTypeError, "The port variable must be a Fixnum or a String.");
579
- Registry.add(handler);
580
- if (TYPE(port) == T_FIXNUM)
581
- port = rb_funcall2(port, iodine_to_s_method_id, 0, NULL);
582
- // connect
583
- intptr_t uuid = facil_connect(.port = StringValueCStr(port),
584
- .address = StringValueCStr(address),
585
- .udata = (void *)handler,
586
- .on_connect = on_open_dyn_protocol_instance,
587
- .on_fail = remove_from_registry);
588
- if (uuid == -1)
589
- return Qnil;
590
- iodine_set_fd(handler, uuid);
591
- return handler;
592
- (void)self;
593
- }
594
-
595
- /**
596
- Attaches an existing file descriptor (`fd`) (i.e., a pipe, a unix socket,
597
- etc') as if it were a regular connection.
598
-
599
- i.e.
600
-
601
- Iodine.attach my_io_obj.to_i, MyProtocolClass.new
602
-
603
- */
604
- static VALUE iodine_attach_fd(VALUE self, VALUE rbfd, VALUE handler) {
605
- Check_Type(rbfd, T_FIXNUM);
606
- if (handler == Qnil || handler == Qfalse)
607
- return Qfalse;
608
- intptr_t uuid = FIX2INT(rbfd);
609
- if (!uuid || uuid == -1)
610
- return Qfalse;
611
- /* make sure the uuid is connected to the sock library */
612
- if (sock_fd2uuid(uuid) == -1)
613
- sock_open(uuid);
614
- if (TYPE(handler) == T_CLASS) {
615
- // include the Protocol module, preventing coder errors
616
- rb_include_module(handler, IodineProtocol);
617
- handler = RubyCaller.call(handler, iodine_new_func_id);
618
- } else {
619
- // include the Protocol module in the object's class
620
- VALUE p_class = rb_obj_class(handler);
621
- // include the Protocol module, preventing coder errors
622
- rb_include_module(p_class, IodineProtocol);
623
- }
624
- Registry.add(handler);
625
- on_open_dyn_protocol_instance(uuid, (void *)handler);
626
- return self;
627
- }
628
- /**
629
- Attaches an existing IO object (i.e., a pipe, a unix socket, etc') as if it
630
- were a regular connection.
631
-
632
- i.e.
633
-
634
- Iodine.attach my_io_obj, MyProtocolClass.new
635
-
636
- */
637
- static VALUE iodine_attach_io(VALUE self, VALUE io, VALUE handler) {
638
- return iodine_attach_fd(self, RubyCaller.call(io, iodine_to_i_func_id),
639
- handler);
640
- }
641
- /* *****************************************************************************
642
- Library Initialization
643
- *****************************************************************************
644
- */
645
-
646
- ////////////////////////////////////////////////////////////////////////
647
- // Ruby loads the library and invokes the Init_<lib_name> function...
648
- //
649
- // Here we connect all the C code to the Ruby interface, completing the bridge
650
- // between Lib-Server and Ruby.
651
- void Iodine_init_protocol(void) {
652
-
653
- iodine_close_func_id = rb_intern("close");
654
-
655
- /* add Iodine module functions */
656
- rb_define_module_function(Iodine, "listen", iodine_listen, 2);
657
- rb_define_module_function(Iodine, "connect", iodine_connect, 3);
658
- rb_define_module_function(Iodine, "attach_io", iodine_attach_io, 2);
659
- rb_define_module_function(Iodine, "attach_fd", iodine_attach_fd, 2);
660
-
661
- /* Create the `Protocol` module and set stub functions */
662
- IodineProtocol = rb_define_module_under(Iodine, "Protocol");
663
- rb_define_method(IodineProtocol, "on_open", not_implemented, 0);
664
- rb_define_method(IodineProtocol, "on_close", not_implemented, 0);
665
- rb_define_method(IodineProtocol, "on_message", not_implemented2, 1);
666
- rb_define_method(IodineProtocol, "on_data", default_on_data, 0);
667
- rb_define_method(IodineProtocol, "on_ready", not_implemented_on_ready, 0);
668
- rb_define_method(IodineProtocol, "on_drained", not_implemented_drained, 0);
669
- rb_define_method(IodineProtocol, "on_shutdown", not_implemented, 0);
670
- rb_define_method(IodineProtocol, "ping", not_implemented_ping, 0);
671
-
672
- /* Add module functions */
673
- rb_define_singleton_method(IodineProtocol, "defer", dyn_defer, -1);
674
-
675
- /* Add module instance methods */
676
- rb_define_method(IodineProtocol, "open?", dyn_is_open, 0);
677
- rb_define_method(IodineProtocol, "conn_id", dyn_uuid, 0);
678
- rb_define_method(IodineProtocol, "read", dyn_read, -1);
679
- rb_define_method(IodineProtocol, "write", dyn_write, 1);
680
- rb_define_method(IodineProtocol, "write!", dyn_write_move, 1);
681
- rb_define_method(IodineProtocol, "write_urgent", dyn_write_urgent, 1);
682
- rb_define_method(IodineProtocol, "close", dyn_close, 0);
683
- rb_define_method(IodineProtocol, "defer", dyn_defer, -1);
684
- rb_define_method(IodineProtocol, "switch_protocol", dyn_switch_prot, 1);
685
- rb_define_method(IodineProtocol, "timeout=", dyn_set_timeout, 1);
686
- rb_define_method(IodineProtocol, "timeout", dyn_get_timeout, 0);
687
- rb_define_method(IodineProtocol, "subscribe", iodine_proto_subscribe, -1);
688
- rb_define_method(IodineProtocol, "publish", iodine_publish, -1);
689
- }