iodine 0.7.59 → 0.8.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 (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -20
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -146
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -1,580 +0,0 @@
1
- #include "iodine_pubsub.h"
2
- #include "iodine_fiobj2rb.h"
3
-
4
- #include "redis_engine.h"
5
-
6
- /*
7
- NOTE:
8
-
9
- This file defines Pub/Sub management and settings, not Pub/Sub usage.
10
-
11
- This file doen't include the `Iodine.subscribe`, `Iodine.unsubscribe` and
12
- `Iodine.publish` methods.
13
-
14
- These methods are all defined in the Connection module (iodine_connection.h).
15
- */
16
-
17
- /* *****************************************************************************
18
- static consts
19
- ***************************************************************************** */
20
-
21
- static ID subscribe_id;
22
- static ID unsubscribe_id;
23
- static ID publish_id;
24
- static ID default_id;
25
- static ID redis_id;
26
- static ID call_id;
27
-
28
- /**
29
- The {Iodine::PubSub::Engine} class is the parent for all engines to inherit
30
- from.
31
-
32
- Engines should inherit this class and override the `subscribe`, `unsubscribe`
33
- and `publish` callbacks (which shall be called by {Iodine}).
34
-
35
- After creation, Engines should attach themselves to Iodine using
36
- {Iodine::PubSub.attach} or their callbacks will never get called.
37
-
38
- Engines can also set themselves to be the default engine using
39
- {Iodine::PubSub.default=}.
40
- */
41
- static VALUE EngineClass;
42
-
43
- /* *****************************************************************************
44
- Ruby <=> C Callbacks
45
- ***************************************************************************** */
46
-
47
- typedef struct {
48
- iodine_pubsub_s *eng;
49
- fio_str_info_s ch;
50
- fio_str_info_s msg;
51
- fio_match_fn pattern;
52
- } iodine_pubsub_task_s;
53
-
54
- #define iodine_engine(eng) ((iodine_pubsub_s *)(eng))
55
-
56
- /* calls an engine's `subscribe` callback within the GVL */
57
- static void *iodine_pubsub_GIL_subscribe(void *tsk_) {
58
- iodine_pubsub_task_s *task = tsk_;
59
- VALUE args[2];
60
- args[0] = rb_str_new(task->ch.data, task->ch.len);
61
- args[1] = task->pattern ? Qtrue : Qnil; // TODO: Qtrue should be :redis
62
- IodineCaller.call2(task->eng->handler, subscribe_id, 2, args);
63
- return NULL;
64
- }
65
-
66
- /** Must subscribe channel. Failures are ignored. */
67
- static void iodine_pubsub_on_subscribe(const fio_pubsub_engine_s *eng,
68
- fio_str_info_s channel,
69
- fio_match_fn match) {
70
- if (iodine_engine(eng)->handler == Qnil) {
71
- return;
72
- }
73
- iodine_pubsub_task_s task = {
74
- .eng = iodine_engine(eng), .ch = channel, .pattern = match};
75
- IodineCaller.enterGVL(iodine_pubsub_GIL_subscribe, &task);
76
- }
77
-
78
- /* calls an engine's `unsubscribe` callback within the GVL */
79
- static void *iodine_pubsub_GIL_unsubscribe(void *tsk_) {
80
- iodine_pubsub_task_s *task = tsk_;
81
- VALUE args[2];
82
- args[0] = rb_str_new(task->ch.data, task->ch.len);
83
- args[1] = task->pattern ? Qtrue : Qnil; // TODO: Qtrue should be :redis
84
- IodineCaller.call2(task->eng->handler, unsubscribe_id, 2, args);
85
- return NULL;
86
- }
87
-
88
- /** Must unsubscribe channel. Failures are ignored. */
89
- static void iodine_pubsub_on_unsubscribe(const fio_pubsub_engine_s *eng,
90
- fio_str_info_s channel,
91
- fio_match_fn match) {
92
- if (iodine_engine(eng)->handler == Qnil) {
93
- return;
94
- }
95
- iodine_pubsub_task_s task = {
96
- .eng = iodine_engine(eng), .ch = channel, .pattern = match};
97
- IodineCaller.enterGVL(iodine_pubsub_GIL_unsubscribe, &task);
98
- }
99
-
100
- /* calls an engine's `unsubscribe` callback within the GVL */
101
- static void *iodine_pubsub_GIL_publish(void *tsk_) {
102
- iodine_pubsub_task_s *task = tsk_;
103
- VALUE args[2];
104
- args[0] = rb_str_new(task->ch.data, task->ch.len);
105
- args[1] = rb_str_new(task->msg.data, task->msg.len);
106
- IodineCaller.call2(task->eng->handler, publish_id, 2, args);
107
- return NULL;
108
- }
109
-
110
- /** Should return 0 on success and -1 on failure. */
111
- static void iodine_pubsub_on_publish(const fio_pubsub_engine_s *eng,
112
- fio_str_info_s channel, fio_str_info_s msg,
113
- uint8_t is_json) {
114
- if (iodine_engine(eng)->handler == Qnil) {
115
- return;
116
- }
117
- iodine_pubsub_task_s task = {
118
- .eng = iodine_engine(eng), .ch = channel, .msg = msg};
119
- IodineCaller.enterGVL(iodine_pubsub_GIL_publish, &task);
120
- (void)is_json;
121
- }
122
-
123
- /* *****************************************************************************
124
- Ruby methods
125
- ***************************************************************************** */
126
-
127
- /**
128
- OVERRIDE this callback - it will be called by {Iodine} whenever the process
129
- CLUSTER (not just this process) subscribes to a stream / channel.
130
- */
131
- static VALUE iodine_pubsub_subscribe(VALUE self, VALUE to, VALUE match) {
132
- return Qnil;
133
- (void)self;
134
- (void)to;
135
- (void)match;
136
- }
137
-
138
- /**
139
- OVERRIDE this callback - it will be called by {Iodine} whenever the whole
140
- process CLUSTER (not just this process) unsubscribes from a stream / channel.
141
- */
142
- static VALUE iodine_pubsub_unsubscribe(VALUE self, VALUE to, VALUE match) {
143
- return Qnil;
144
- (void)self;
145
- (void)to;
146
- (void)match;
147
- }
148
-
149
- /**
150
- OVERRIDE this callback - it will be called by {Iodine} whenever the
151
- {Iodine.publish} (or {Iodine::Connection#publish}) is called for this engine.
152
-
153
- If this {Engine} is set as the default {Engine}, then any call to
154
- {Iodine.publish} (or {Iodine::Connection#publish} will invoke this callback
155
- (unless another {Engine} was specified).
156
-
157
- NOTE: this callback is called per process event (not per cluster event) and the
158
- {Engine} is responsible for message propagation.
159
- */
160
- static VALUE iodine_pubsub_publish(VALUE self, VALUE to, VALUE message) {
161
- iodine_pubsub_s *e = iodine_pubsub_CData(self);
162
- if (!e || e->engine == &e->do_not_touch) {
163
- /* this is a Ruby engine, nothing to do. */
164
- return Qnil;
165
- }
166
- fio_publish(.engine = e->engine, .channel = IODINE_RSTRINFO(to),
167
- .message = IODINE_RSTRINFO(message));
168
- return self;
169
- }
170
-
171
- /* *****************************************************************************
172
- Ruby <=> C Data Type
173
- ***************************************************************************** */
174
-
175
- /* a callback for the GC (marking active objects) */
176
- static void iodine_pubsub_data_mark(void *c_) {
177
- iodine_pubsub_s *c = c_;
178
- if (c->handler != Qnil) {
179
- rb_gc_mark(c->handler);
180
- }
181
- }
182
- /* a callback for the GC (marking active objects) */
183
- static void iodine_pubsub_data_free(void *c_) {
184
- FIO_LOG_DEBUG("iodine destroying engine");
185
- iodine_pubsub_s *data = c_;
186
- fio_pubsub_detach(data->engine);
187
- IodineStore.remove(data->handler); /* redundant except during exit */
188
- if (data->dealloc) {
189
- data->dealloc(data->engine);
190
- }
191
- free(data);
192
- }
193
-
194
- static size_t iodine_pubsub_data_size(const void *c_) {
195
- return sizeof(iodine_pubsub_s);
196
- (void)c_;
197
- }
198
-
199
- const rb_data_type_t iodine_pubsub_data_type = {
200
- .wrap_struct_name = "IodinePubSubData",
201
- .function =
202
- {
203
- .dmark = iodine_pubsub_data_mark,
204
- .dfree = iodine_pubsub_data_free,
205
- .dsize = iodine_pubsub_data_size,
206
- },
207
- .data = NULL,
208
- // .flags = RUBY_TYPED_FREE_IMMEDIATELY,
209
- };
210
-
211
- /* Iodine::PubSub::Engine.allocate */
212
- static VALUE iodine_pubsub_data_alloc_c(VALUE self) {
213
- iodine_pubsub_s *c = malloc(sizeof(*c));
214
- *c = (iodine_pubsub_s){
215
- .do_not_touch =
216
- {
217
- .subscribe = iodine_pubsub_on_subscribe,
218
- .unsubscribe = iodine_pubsub_on_unsubscribe,
219
- .publish = iodine_pubsub_on_publish,
220
- },
221
- .handler = Qnil,
222
- .engine = &c->do_not_touch,
223
- };
224
- return TypedData_Wrap_Struct(self, &iodine_pubsub_data_type, c);
225
- }
226
-
227
- /* *****************************************************************************
228
- C engines
229
- ***************************************************************************** */
230
-
231
- static VALUE iodine_pubsub_make_C_engine(const fio_pubsub_engine_s *e) {
232
- VALUE engine = IodineCaller.call(EngineClass, rb_intern2("new", 3));
233
- if (engine == Qnil) {
234
- return Qnil;
235
- }
236
- iodine_pubsub_CData(engine)->engine = (fio_pubsub_engine_s *)e;
237
- return engine;
238
- }
239
-
240
- /* *****************************************************************************
241
- PubSub module methods
242
- ***************************************************************************** */
243
-
244
- /** Sets the default {Iodine::PubSub::Engine} for pub/sub methods. */
245
- static VALUE iodine_pubsub_default_set(VALUE self, VALUE engine) {
246
- if (engine == Qnil) {
247
- engine = rb_const_get(self, rb_intern2("CLUSTER", 7));
248
- }
249
- iodine_pubsub_s *e = iodine_pubsub_CData(engine);
250
- if (!e) {
251
- rb_raise(rb_eTypeError, "not a valid engine");
252
- return Qnil;
253
- }
254
- if (e->handler == Qnil) {
255
- e->handler = engine;
256
- }
257
- FIO_PUBSUB_DEFAULT = e->engine;
258
- rb_ivar_set(self, rb_intern2("default_engine", 14), engine);
259
- return engine;
260
- }
261
-
262
- /** Returns the default {Iodine::PubSub::Engine} for pub/sub methods. */
263
- static VALUE iodine_pubsub_default_get(VALUE self) {
264
- VALUE def = rb_ivar_get(self, rb_intern2("default_engine", 14));
265
- if (def == Qnil) {
266
- def = rb_const_get(self, rb_intern2("CLUSTER", 7));
267
- iodine_pubsub_default_set(self, def);
268
- }
269
- return def;
270
- }
271
-
272
- /**
273
- * Attaches an {Iodine::PubSub::Engine} to the pub/sub system (more than a
274
- * single engine can be attached at the same time).
275
- *
276
- * After an engine was attached, it's callbacks will be called
277
- * ({Iodine::PubSub::Engine#subscribe} and {Iodine::PubSub::Engine#unsubscribe})
278
- * in response to Pub/Sub events.
279
- */
280
- static VALUE iodine_pubsub_attach(VALUE self, VALUE engine) {
281
- iodine_pubsub_s *e = iodine_pubsub_CData(engine);
282
- if (!e) {
283
- rb_raise(rb_eTypeError, "not a valid engine");
284
- return Qnil;
285
- }
286
- if (e->handler == Qnil) {
287
- e->handler = engine;
288
- }
289
- IodineStore.add(engine);
290
- fio_pubsub_attach(e->engine);
291
- return engine;
292
- (void)self;
293
- }
294
-
295
- /**
296
- * Removes an {Iodine::PubSub::Engine} from the pub/sub system.
297
- *
298
- * After an {Iodine::PubSub::Engine} was detached, Iodine will no longer call
299
- * the {Iodine::PubSub::Engine}'s callbacks ({Iodine::PubSub::Engine#subscribe}
300
- * and {Iodine::PubSub::Engine#unsubscribe})
301
- */
302
- static VALUE iodine_pubsub_detach(VALUE self, VALUE engine) {
303
- iodine_pubsub_s *e = iodine_pubsub_CData(engine);
304
- if (!e) {
305
- rb_raise(rb_eTypeError, "not a valid engine");
306
- return Qnil;
307
- }
308
- if (e->handler == Qnil) {
309
- e->handler = engine;
310
- }
311
- IodineStore.remove(engine);
312
- fio_pubsub_detach(e->engine);
313
- return engine;
314
- (void)self;
315
- }
316
-
317
- /**
318
- * Forces {Iodine} to call the {Iodine::PubSub::Engine#subscribe} callback for
319
- * all existing subscriptions (i.e., when reconnecting to a Pub/Sub backend such
320
- * as Redis).
321
- */
322
- static VALUE iodine_pubsub_reset(VALUE self, VALUE engine) {
323
- iodine_pubsub_s *e = iodine_pubsub_CData(engine);
324
- if (!e) {
325
- rb_raise(rb_eTypeError, "not a valid engine");
326
- return Qnil;
327
- }
328
- if (e->handler == Qnil) {
329
- e->handler = engine;
330
- }
331
- fio_pubsub_reattach(e->engine);
332
- return engine;
333
- (void)self;
334
- }
335
-
336
- /* *****************************************************************************
337
- Redis Engine
338
- ***************************************************************************** */
339
-
340
- /**
341
- Initializes a new {Iodine::PubSub::Redis} engine.
342
-
343
- Iodine::PubSub::Redis.new(url, opt = {})
344
-
345
- use:
346
-
347
- REDIS_URL = "redis://localhost:6379/"
348
- Iodine::PubSub::Redis.new(REDIS_URL, ping: 50) #pings every 50 seconds
349
-
350
- To use Redis authentication, add the password to the URL. i.e.:
351
-
352
- REDIS_URL = "redis://redis:password@localhost:6379/"
353
- Iodine::PubSub::Redis.new(REDIS_URL, ping: 50) #pings every 50 seconds
354
-
355
- The options hash accepts:
356
-
357
- :ping:: the PING interval up to 255 seconds. Default: 0 (~5 minutes).
358
- */
359
- static VALUE iodine_pubsub_redis_new(int argc, VALUE *argv, VALUE self) {
360
- if (!argc) {
361
- rb_raise(rb_eArgError, "Iodine::PubSub::Redis.new(address, opt={}) "
362
- "requires at least 1 argument.");
363
- }
364
- VALUE url = argv[0];
365
- Check_Type(url, T_STRING);
366
- if (RSTRING_LEN(url) > 4096) {
367
- rb_raise(rb_eArgError, "Redis URL too long.");
368
- }
369
- uint8_t ping = 0;
370
-
371
- iodine_pubsub_s *e = iodine_pubsub_CData(self);
372
- if (!e) {
373
- rb_raise(rb_eTypeError, "not a valid engine");
374
- return Qnil;
375
- }
376
-
377
- /* extract options */
378
- if (argc == 2) {
379
- Check_Type(argv[1], T_HASH);
380
- VALUE tmp = rb_hash_aref(argv[1], rb_id2sym(rb_intern2("ping", 4)));
381
- if (tmp != Qnil) {
382
- Check_Type(tmp, T_FIXNUM);
383
- if (NUM2SIZET(tmp) > 255) {
384
- rb_raise(rb_eArgError,
385
- ":ping must be a non-negative integer under 255 seconds.");
386
- }
387
- ping = (uint8_t)NUM2SIZET(tmp);
388
- }
389
- }
390
-
391
- /* parse URL assume redis://redis:password@localhost:6379 */
392
- fio_url_s info = fio_url_parse(RSTRING_PTR(url), RSTRING_LEN(url));
393
-
394
- FIO_LOG_INFO("Initializing Redis engine for address: %.*s",
395
- (int)RSTRING_LEN(url), RSTRING_PTR(url));
396
- /* create engine */
397
- e->engine = redis_engine_create(.address = info.host, .port = info.port,
398
- .auth = info.password, .ping_interval = ping);
399
- if (!e->engine) {
400
- e->engine = &e->do_not_touch;
401
- } else {
402
- e->dealloc = redis_engine_destroy;
403
- }
404
-
405
- if (e->engine == &e->do_not_touch) {
406
- rb_raise(rb_eArgError,
407
- "Error initializing the Redis engine - malformed URL?");
408
- }
409
- return self;
410
- (void)self;
411
- (void)argc;
412
- (void)argv;
413
- }
414
-
415
- struct redis_callback_data {
416
- FIOBJ response;
417
- VALUE block;
418
- };
419
-
420
- /** A callback for Redis commands. */
421
- static void *iodine_pubsub_redis_callback_in_gil(void *data_) {
422
- struct redis_callback_data *d = data_;
423
- VALUE rb = Qnil;
424
- if (!FIOBJ_IS_NULL(d->response)) {
425
- rb = fiobj2rb_deep(d->response, 0);
426
- }
427
- IodineCaller.call2(d->block, call_id, 1, &rb);
428
- IodineStore.remove(rb);
429
- return NULL;
430
- }
431
-
432
- /** A callback for Redis commands. */
433
- static void iodine_pubsub_redis_callback(fio_pubsub_engine_s *e, FIOBJ response,
434
- void *udata) {
435
- struct redis_callback_data d = {.response = response, .block = (VALUE)udata};
436
- if (d.block == Qnil) {
437
- return;
438
- }
439
- IodineCaller.enterGVL(iodine_pubsub_redis_callback_in_gil, &d);
440
- IodineStore.remove(d.block);
441
- (void)e;
442
- }
443
-
444
- // clang-format off
445
- /**
446
- Sends a Redis command. Accepts an optional block that will recieve the response.
447
-
448
- i.e.:
449
-
450
- REDIS_URL = "redis://redis:password@localhost:6379/"
451
- redis = Iodine::PubSub::Redis.new(REDIS_URL, ping: 50) #pings every 50 seconds
452
- Iodine::PubSub.default = redis
453
- redis.cmd("KEYS", "*") {|result| p result
454
- }
455
-
456
-
457
- */
458
- static VALUE iodine_pubsub_redis_cmd(int argc, VALUE *argv, VALUE self) {
459
- // clang-format on
460
- if (argc <= 0) {
461
- rb_raise(rb_eArgError, "Iodine::PubSub::Redis#cmd(command, ...) is missing "
462
- "the required command argument.");
463
- }
464
- iodine_pubsub_s *e = iodine_pubsub_CData(self);
465
- if (!e || !e->engine || e->engine == &e->do_not_touch) {
466
- rb_raise(rb_eTypeError,
467
- "Iodine::PubSub::Redis internal error - obsolete object?");
468
- }
469
- VALUE block = Qnil;
470
- if (rb_block_given_p()) {
471
- block = IodineStore.add(rb_block_proc());
472
- }
473
- FIOBJ data = fiobj_ary_new2((size_t)argc);
474
- for (int i = 0; i < argc; ++i) {
475
- switch (TYPE(argv[i])) {
476
- case T_SYMBOL:
477
- argv[i] = rb_sym2str(argv[i]);
478
- /* overflow */
479
- case T_STRING:
480
- fiobj_ary_push(data,
481
- fiobj_str_new(RSTRING_PTR(argv[i]), RSTRING_LEN(argv[i])));
482
- break;
483
- case T_FIXNUM:
484
- fiobj_ary_push(data, fiobj_num_new(NUM2SSIZET(argv[i])));
485
- break;
486
- case T_FLOAT:
487
- fiobj_ary_push(data, fiobj_float_new(rb_float_value(argv[i])));
488
- break;
489
- case T_NIL:
490
- fiobj_ary_push(data, fiobj_null());
491
- break;
492
- case T_TRUE:
493
- fiobj_ary_push(data, fiobj_true());
494
- break;
495
- case T_FALSE:
496
- fiobj_ary_push(data, fiobj_false());
497
- break;
498
- default:
499
- goto wrong_type;
500
- }
501
- }
502
- if (redis_engine_send(e->engine, data, iodine_pubsub_redis_callback,
503
- (void *)block)) {
504
- iodine_pubsub_redis_callback(e->engine, fiobj_null(), (void *)block);
505
- }
506
- fiobj_free(data);
507
- return self;
508
-
509
- wrong_type:
510
- fiobj_free(data);
511
- rb_raise(rb_eArgError,
512
- "only String, Number (with limits), Symbol, true, false and nil "
513
- "arguments can be used.");
514
- }
515
-
516
- /* *****************************************************************************
517
- Module initialization
518
- ***************************************************************************** */
519
-
520
- /** Initializes the Connection Ruby class. */
521
- void iodine_pubsub_init(void) {
522
- subscribe_id = rb_intern2("subscribe", 9);
523
- unsubscribe_id = rb_intern2("unsubscribe", 11);
524
- publish_id = rb_intern2("publish", 7);
525
- default_id = rb_intern2("default_engine", 14);
526
- redis_id = rb_intern2("redis", 5);
527
- call_id = rb_intern2("call", 4);
528
-
529
- /* Define the PubSub module and it's methods */
530
-
531
- VALUE PubSubModule = rb_define_module_under(IodineModule, "PubSub");
532
- rb_define_module_function(PubSubModule, "default=", iodine_pubsub_default_set,
533
- 1);
534
- rb_define_module_function(PubSubModule, "default", iodine_pubsub_default_get,
535
- 0);
536
- rb_define_module_function(PubSubModule, "attach", iodine_pubsub_attach, 1);
537
- rb_define_module_function(PubSubModule, "detach", iodine_pubsub_detach, 1);
538
- rb_define_module_function(PubSubModule, "reset", iodine_pubsub_reset, 1);
539
-
540
- /* Define the Engine class and it's methods */
541
-
542
- /**
543
- The {Iodine::PubSub::Engine} class is the parent for all engines to inherit
544
- from.
545
-
546
- Engines should inherit this class and override the `subscribe`, `unsubscribe`
547
- and `publish` callbacks (which shall be called by {Iodine}).
548
-
549
- After creation, Engines should attach themselves to Iodine using
550
- {Iodine::PubSub.attach} or their callbacks will never get called.
551
-
552
- Engines can also set themselves to be the default engine using
553
- {Iodine::PubSub.default=}.
554
- */
555
- EngineClass = rb_define_class_under(PubSubModule, "Engine", rb_cObject);
556
- rb_define_alloc_func(EngineClass, iodine_pubsub_data_alloc_c);
557
- rb_define_method(EngineClass, "subscribe", iodine_pubsub_subscribe, 2);
558
- rb_define_method(EngineClass, "unsubscribe", iodine_pubsub_unsubscribe, 2);
559
- rb_define_method(EngineClass, "publish", iodine_pubsub_publish, 2);
560
-
561
- /* Define the CLUSTER and PROCESS engines */
562
-
563
- /* CLUSTER publishes data to all the subscribers in the process cluster. */
564
- rb_define_const(PubSubModule, "CLUSTER",
565
- iodine_pubsub_make_C_engine(FIO_PUBSUB_CLUSTER));
566
- /* PROCESS publishes data to all the subscribers in a single process. */
567
- rb_define_const(PubSubModule, "PROCESS",
568
- iodine_pubsub_make_C_engine(FIO_PUBSUB_PROCESS));
569
- /* SIBLINGS publishes data to all the subscribers in the *other* processes
570
- * process. */
571
- rb_define_const(PubSubModule, "SIBLINGS",
572
- iodine_pubsub_make_C_engine(FIO_PUBSUB_SIBLINGS));
573
- /* PUBLISH2ROOT publishes data only to the root / master process. */
574
- rb_define_const(PubSubModule, "PUBLISH2ROOT",
575
- iodine_pubsub_make_C_engine(FIO_PUBSUB_ROOT));
576
-
577
- VALUE RedisClass = rb_define_class_under(PubSubModule, "Redis", EngineClass);
578
- rb_define_method(RedisClass, "initialize", iodine_pubsub_redis_new, -1);
579
- rb_define_method(RedisClass, "cmd", iodine_pubsub_redis_cmd, -1);
580
- }
@@ -1,26 +0,0 @@
1
- #ifndef H_IODINE_PUBSUB_H
2
- #define H_IODINE_PUBSUB_H
3
-
4
- #include "iodine.h"
5
-
6
- #include "fio.h"
7
-
8
- /** Initializes the PubSub::Engine Ruby class. */
9
- void iodine_pubsub_init(void);
10
-
11
- extern const rb_data_type_t iodine_pubsub_data_type;
12
-
13
- typedef struct {
14
- fio_pubsub_engine_s do_not_touch;
15
- VALUE handler;
16
- fio_pubsub_engine_s *engine;
17
- void (*dealloc)(fio_pubsub_engine_s *engine);
18
- } iodine_pubsub_s;
19
-
20
- static inline iodine_pubsub_s *iodine_pubsub_CData(VALUE obj) {
21
- iodine_pubsub_s *c = NULL;
22
- TypedData_Get_Struct(obj, iodine_pubsub_s, &iodine_pubsub_data_type, c);
23
- return c;
24
- }
25
-
26
- #endif