iodine 0.7.60 → 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.
- checksums.yaml +4 -4
- data/.clang-format +15 -0
- data/.rspec +1 -0
- data/.yardopts +1 -3
- data/CHANGELOG.md +132 -12
- data/Gemfile +5 -7
- data/LICENSE.txt +1 -1
- data/README.md +147 -671
- data/Rakefile +9 -16
- data/examples/chatroom.nru +9 -0
- data/examples/client +74 -0
- data/examples/config-hello.nru +9 -0
- data/examples/config-hello.ru +11 -0
- data/examples/config-hijack.ru +13 -0
- data/examples/config-shootout.ru +43 -0
- data/examples/config.nru +120 -0
- data/examples/config.rb +37 -0
- data/examples/config.ru +42 -53
- data/examples/fake +24 -0
- data/examples/hello_neorack +137 -0
- data/examples/routes.nru +29 -0
- data/examples/routes.ru +42 -0
- data/exe/iodine +218 -258
- data/ext/iodine/extconf.rb +27 -100
- data/ext/iodine/fio-stl.h +128336 -0
- data/ext/iodine/fio-stl.md +26396 -0
- data/ext/iodine/iodine.c +213 -1393
- data/ext/iodine/iodine.h +250 -55
- data/ext/iodine/iodine_arg_helper.h +329 -0
- data/ext/iodine/iodine_caller.h +234 -25
- data/ext/iodine/iodine_cli.h +434 -0
- data/ext/iodine/iodine_compression.h +312 -0
- data/ext/iodine/iodine_connection.h +3484 -34
- data/ext/iodine/iodine_core.h +363 -0
- data/ext/iodine/iodine_crypto.h +1441 -0
- data/ext/iodine/iodine_defer.h +225 -4
- data/ext/iodine/iodine_json.h +738 -4
- data/ext/iodine/iodine_listener.h +263 -0
- data/ext/iodine/iodine_log.h +297 -0
- data/ext/iodine/iodine_minimap.h +543 -0
- data/ext/iodine/iodine_mustache.h +461 -4
- data/ext/iodine/iodine_pubsub_eng.h +729 -0
- data/ext/iodine/iodine_pubsub_history.h +547 -0
- data/ext/iodine/iodine_pubsub_msg.h +228 -0
- data/ext/iodine/iodine_redis.h +322 -0
- data/ext/iodine/iodine_store.h +418 -16
- data/ext/iodine/iodine_threads.h +279 -0
- data/ext/iodine/iodine_tls.h +515 -6
- data/ext/iodine/iodine_utils.h +923 -0
- data/iodine.gemspec +37 -42
- data/lib/iodine/benchmark.rb +1690 -0
- data/lib/iodine/documentation.rb +3085 -0
- data/lib/iodine/version.rb +17 -1
- data/lib/iodine.rb +54 -255
- data/logo.svg +36 -0
- data/mustache.md +55 -0
- data/sig/iodine.rbs +4 -0
- metadata +58 -184
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/workflows/ruby.yml +0 -42
- data/.gitignore +0 -21
- data/LIMITS.md +0 -41
- data/SPEC-PubSub-Draft.md +0 -159
- data/SPEC-WebSocket-Draft.md +0 -239
- data/bin/console +0 -22
- data/bin/info.md +0 -353
- data/bin/mustache_bench.rb +0 -100
- data/bin/poc/Gemfile.lock +0 -23
- data/bin/poc/README.md +0 -37
- data/bin/poc/config.ru +0 -66
- data/bin/poc/gemfile +0 -1
- data/bin/poc/www/index.html +0 -57
- data/examples/async_task.ru +0 -92
- data/examples/bates/README.md +0 -3
- data/examples/bates/config.ru +0 -342
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +0 -600
- data/examples/echo.ru +0 -59
- data/examples/etag.ru +0 -16
- data/examples/hello.ru +0 -29
- data/examples/pubsub_engine.ru +0 -81
- data/examples/rack3.ru +0 -12
- data/examples/redis.ru +0 -70
- data/examples/shootout.ru +0 -73
- data/examples/sub-protocols.ru +0 -90
- data/examples/tcp_client.rb +0 -66
- data/examples/x-sendfile.ru +0 -14
- data/ext/iodine/fio.c +0 -11995
- data/ext/iodine/fio.h +0 -6371
- data/ext/iodine/fio_cli.c +0 -431
- data/ext/iodine/fio_cli.h +0 -189
- data/ext/iodine/fio_json_parser.h +0 -688
- data/ext/iodine/fio_siphash.c +0 -157
- data/ext/iodine/fio_siphash.h +0 -37
- data/ext/iodine/fio_tls.h +0 -129
- data/ext/iodine/fio_tls_missing.c +0 -649
- data/ext/iodine/fio_tls_openssl.c +0 -1106
- data/ext/iodine/fio_tmpfile.h +0 -50
- data/ext/iodine/fiobj.h +0 -44
- data/ext/iodine/fiobj4fio.h +0 -21
- data/ext/iodine/fiobj_ary.c +0 -333
- data/ext/iodine/fiobj_ary.h +0 -139
- data/ext/iodine/fiobj_data.c +0 -1187
- data/ext/iodine/fiobj_data.h +0 -167
- data/ext/iodine/fiobj_hash.c +0 -409
- data/ext/iodine/fiobj_hash.h +0 -176
- data/ext/iodine/fiobj_json.c +0 -622
- data/ext/iodine/fiobj_json.h +0 -68
- data/ext/iodine/fiobj_mem.h +0 -71
- data/ext/iodine/fiobj_mustache.c +0 -317
- data/ext/iodine/fiobj_mustache.h +0 -62
- data/ext/iodine/fiobj_numbers.c +0 -344
- data/ext/iodine/fiobj_numbers.h +0 -127
- data/ext/iodine/fiobj_str.c +0 -433
- data/ext/iodine/fiobj_str.h +0 -172
- data/ext/iodine/fiobject.c +0 -620
- data/ext/iodine/fiobject.h +0 -655
- data/ext/iodine/hpack.h +0 -1923
- data/ext/iodine/http.c +0 -2743
- data/ext/iodine/http.h +0 -1002
- data/ext/iodine/http1.c +0 -910
- data/ext/iodine/http1.h +0 -29
- data/ext/iodine/http1_parser.h +0 -878
- data/ext/iodine/http_internal.c +0 -1279
- data/ext/iodine/http_internal.h +0 -237
- data/ext/iodine/http_mime_parser.h +0 -350
- data/ext/iodine/iodine_caller.c +0 -230
- data/ext/iodine/iodine_connection.c +0 -941
- data/ext/iodine/iodine_defer.c +0 -420
- data/ext/iodine/iodine_fiobj2rb.h +0 -120
- data/ext/iodine/iodine_helpers.c +0 -282
- data/ext/iodine/iodine_helpers.h +0 -12
- data/ext/iodine/iodine_http.c +0 -1181
- data/ext/iodine/iodine_http.h +0 -23
- data/ext/iodine/iodine_json.c +0 -302
- data/ext/iodine/iodine_mustache.c +0 -567
- data/ext/iodine/iodine_pubsub.c +0 -580
- data/ext/iodine/iodine_pubsub.h +0 -26
- data/ext/iodine/iodine_rack_io.c +0 -273
- data/ext/iodine/iodine_rack_io.h +0 -20
- data/ext/iodine/iodine_store.c +0 -148
- data/ext/iodine/iodine_tcp.c +0 -346
- data/ext/iodine/iodine_tcp.h +0 -13
- data/ext/iodine/iodine_tls.c +0 -261
- data/ext/iodine/mustache_parser.h +0 -1546
- data/ext/iodine/redis_engine.c +0 -957
- data/ext/iodine/redis_engine.h +0 -79
- data/ext/iodine/resp_parser.h +0 -317
- data/ext/iodine/websocket_parser.h +0 -506
- data/ext/iodine/websockets.c +0 -743
- data/ext/iodine/websockets.h +0 -185
- data/lib/iodine/connection.rb +0 -61
- data/lib/iodine/json.rb +0 -42
- data/lib/iodine/mustache.rb +0 -113
- data/lib/iodine/pubsub.rb +0 -55
- data/lib/iodine/rack_utils.rb +0 -43
- data/lib/iodine/tls.rb +0 -16
- data/lib/rack/handler/iodine.rb +0 -33
- data/logo.png +0 -0
data/ext/iodine/iodine_pubsub.c
DELETED
|
@@ -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
|
-
}
|
data/ext/iodine/iodine_pubsub.h
DELETED
|
@@ -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
|