iodine 0.4.19 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +22 -0
- data/LIMITS.md +19 -9
- data/README.md +92 -77
- data/SPEC-PubSub-Draft.md +113 -0
- data/SPEC-Websocket-Draft.md +127 -143
- data/bin/http-hello +0 -1
- data/bin/raw-rbhttp +1 -1
- data/bin/raw_broadcast +8 -10
- data/bin/updated api +2 -2
- data/bin/ws-broadcast +2 -4
- data/bin/ws-echo +2 -2
- data/examples/config.ru +13 -13
- data/examples/echo.ru +5 -6
- data/examples/hello.ru +2 -3
- data/examples/info.md +316 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/redis.ru +9 -9
- data/examples/shootout.ru +45 -11
- data/ext/iodine/defer.c +194 -297
- data/ext/iodine/defer.h +61 -53
- data/ext/iodine/evio.c +0 -260
- data/ext/iodine/evio.h +50 -22
- data/ext/iodine/evio_callbacks.c +26 -0
- data/ext/iodine/evio_epoll.c +251 -0
- data/ext/iodine/evio_kqueue.c +193 -0
- data/ext/iodine/extconf.rb +1 -1
- data/ext/iodine/facil.c +1420 -542
- data/ext/iodine/facil.h +151 -64
- data/ext/iodine/fio_ary.h +418 -0
- data/ext/iodine/{base64.c → fio_base64.c} +33 -24
- data/ext/iodine/{base64.h → fio_base64.h} +6 -7
- data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
- data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
- data/ext/iodine/fio_hashmap.h +759 -0
- data/ext/iodine/fio_json_parser.h +651 -0
- data/ext/iodine/fio_llist.h +257 -0
- data/ext/iodine/fio_mem.c +672 -0
- data/ext/iodine/fio_mem.h +140 -0
- data/ext/iodine/fio_random.c +248 -0
- data/ext/iodine/{random.h → fio_random.h} +11 -14
- data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
- data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
- data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
- data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
- data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
- data/ext/iodine/fio_siphash.h +18 -0
- data/ext/iodine/fio_tmpfile.h +38 -0
- data/ext/iodine/fiobj.h +24 -7
- data/ext/iodine/fiobj4sock.h +23 -0
- data/ext/iodine/fiobj_ary.c +143 -226
- data/ext/iodine/fiobj_ary.h +17 -16
- data/ext/iodine/fiobj_data.c +1160 -0
- data/ext/iodine/fiobj_data.h +164 -0
- data/ext/iodine/fiobj_hash.c +298 -406
- data/ext/iodine/fiobj_hash.h +101 -54
- data/ext/iodine/fiobj_json.c +478 -601
- data/ext/iodine/fiobj_json.h +34 -9
- data/ext/iodine/fiobj_numbers.c +383 -51
- data/ext/iodine/fiobj_numbers.h +87 -11
- data/ext/iodine/fiobj_str.c +423 -184
- data/ext/iodine/fiobj_str.h +81 -32
- data/ext/iodine/fiobject.c +273 -522
- data/ext/iodine/fiobject.h +477 -112
- data/ext/iodine/http.c +2243 -83
- data/ext/iodine/http.h +842 -121
- data/ext/iodine/http1.c +810 -385
- data/ext/iodine/http1.h +16 -39
- data/ext/iodine/http1_parser.c +146 -74
- data/ext/iodine/http1_parser.h +15 -4
- data/ext/iodine/http_internal.c +1258 -0
- data/ext/iodine/http_internal.h +226 -0
- data/ext/iodine/http_mime_parser.h +341 -0
- data/ext/iodine/iodine.c +86 -68
- data/ext/iodine/iodine.h +26 -11
- data/ext/iodine/iodine_helpers.c +8 -7
- data/ext/iodine/iodine_http.c +487 -324
- data/ext/iodine/iodine_json.c +304 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_protocol.c +107 -45
- data/ext/iodine/iodine_pubsub.c +526 -225
- data/ext/iodine/iodine_pubsub.h +10 -0
- data/ext/iodine/iodine_websockets.c +268 -510
- data/ext/iodine/iodine_websockets.h +2 -4
- data/ext/iodine/pubsub.c +726 -432
- data/ext/iodine/pubsub.h +85 -103
- data/ext/iodine/rb-call.c +4 -4
- data/ext/iodine/rb-defer.c +46 -22
- data/ext/iodine/rb-fiobj2rb.h +117 -0
- data/ext/iodine/rb-rack-io.c +73 -238
- data/ext/iodine/rb-rack-io.h +2 -2
- data/ext/iodine/rb-registry.c +35 -93
- data/ext/iodine/rb-registry.h +1 -0
- data/ext/iodine/redis_engine.c +742 -304
- data/ext/iodine/redis_engine.h +42 -39
- data/ext/iodine/resp_parser.h +311 -0
- data/ext/iodine/sock.c +627 -490
- data/ext/iodine/sock.h +345 -297
- data/ext/iodine/spnlock.inc +15 -4
- data/ext/iodine/websocket_parser.h +16 -20
- data/ext/iodine/websockets.c +188 -257
- data/ext/iodine/websockets.h +24 -133
- data/lib/iodine.rb +52 -7
- data/lib/iodine/cli.rb +6 -24
- data/lib/iodine/json.rb +40 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +5 -3
- data/lib/rack/handler/iodine.rb +58 -13
- metadata +38 -48
- data/bin/ws-shootout +0 -107
- data/examples/broadcast.ru +0 -56
- data/ext/iodine/bscrypt-common.h +0 -116
- data/ext/iodine/bscrypt.h +0 -49
- data/ext/iodine/fio2resp.c +0 -60
- data/ext/iodine/fio2resp.h +0 -51
- data/ext/iodine/fio_dict.c +0 -446
- data/ext/iodine/fio_dict.h +0 -99
- data/ext/iodine/fio_hash_table.h +0 -370
- data/ext/iodine/fio_list.h +0 -111
- data/ext/iodine/fiobj_internal.h +0 -280
- data/ext/iodine/fiobj_primitives.c +0 -131
- data/ext/iodine/fiobj_primitives.h +0 -55
- data/ext/iodine/fiobj_sym.c +0 -135
- data/ext/iodine/fiobj_sym.h +0 -60
- data/ext/iodine/hex.c +0 -124
- data/ext/iodine/hex.h +0 -70
- data/ext/iodine/http1_request.c +0 -81
- data/ext/iodine/http1_request.h +0 -58
- data/ext/iodine/http1_response.c +0 -417
- data/ext/iodine/http1_response.h +0 -95
- data/ext/iodine/http_request.c +0 -111
- data/ext/iodine/http_request.h +0 -102
- data/ext/iodine/http_response.c +0 -1703
- data/ext/iodine/http_response.h +0 -250
- data/ext/iodine/misc.c +0 -182
- data/ext/iodine/misc.h +0 -74
- data/ext/iodine/random.c +0 -208
- data/ext/iodine/redis_connection.c +0 -278
- data/ext/iodine/redis_connection.h +0 -86
- data/ext/iodine/resp.c +0 -842
- data/ext/iodine/resp.h +0 -261
- data/ext/iodine/siphash.c +0 -154
- data/ext/iodine/siphash.h +0 -22
- data/ext/iodine/xor-crypt.c +0 -193
- data/ext/iodine/xor-crypt.h +0 -107
data/ext/iodine/iodine_pubsub.c
CHANGED
@@ -8,20 +8,31 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
8
8
|
#include "rb-call.h"
|
9
9
|
|
10
10
|
#include "pubsub.h"
|
11
|
+
#include "rb-fiobj2rb.h"
|
11
12
|
#include "redis_engine.h"
|
13
|
+
#include "websockets.h"
|
12
14
|
|
13
15
|
VALUE IodineEngine;
|
16
|
+
ID iodine_engine_pubid;
|
14
17
|
|
15
18
|
static VALUE IodinePubSub;
|
19
|
+
static VALUE IodinePubSubSubscription;
|
16
20
|
static ID engine_varid;
|
17
21
|
static ID engine_subid;
|
18
|
-
static ID engine_pubid;
|
19
22
|
static ID engine_unsubid;
|
20
23
|
static ID default_pubsubid;
|
21
24
|
|
22
|
-
static
|
23
|
-
|
24
|
-
static VALUE
|
25
|
+
static ID to_str_shadow_id;
|
26
|
+
|
27
|
+
static VALUE as_sym_id;
|
28
|
+
static VALUE binary_sym_id;
|
29
|
+
static VALUE handler_sym_id;
|
30
|
+
static VALUE match_sym_id;
|
31
|
+
static VALUE message_sym_id;
|
32
|
+
static VALUE redis_sym_id;
|
33
|
+
static VALUE text_sym_id;
|
34
|
+
static VALUE to_sym_id;
|
35
|
+
static VALUE channel_sym_id;
|
25
36
|
|
26
37
|
/* *****************************************************************************
|
27
38
|
Mock Functions
|
@@ -52,66 +63,188 @@ call this function from your own code / application.
|
|
52
63
|
|
53
64
|
The function should return `true` on success and `nil` or `false` on failure.
|
54
65
|
*/
|
55
|
-
static VALUE engine_pub_placeholder(VALUE self, VALUE channel, VALUE msg
|
56
|
-
|
66
|
+
static VALUE engine_pub_placeholder(VALUE self, VALUE channel, VALUE msg) {
|
67
|
+
{ /* test for built-in C engines */
|
68
|
+
iodine_engine_s *engine;
|
69
|
+
Data_Get_Struct(self, iodine_engine_s, engine);
|
70
|
+
if (engine->p != &engine->engine) {
|
71
|
+
FIOBJ ch = fiobj_str_new(RSTRING_PTR(channel), RSTRING_LEN(channel));
|
72
|
+
FIOBJ m = fiobj_str_new(RSTRING_PTR(msg), RSTRING_LEN(msg));
|
73
|
+
pubsub_publish(.engine = engine->p, .channel = ch, .message = m);
|
74
|
+
fiobj_free(ch);
|
75
|
+
fiobj_free(msg);
|
76
|
+
return Qtrue;
|
77
|
+
}
|
78
|
+
}
|
57
79
|
return Qnil;
|
58
80
|
(void)self;
|
59
81
|
(void)msg;
|
60
82
|
(void)channel;
|
61
|
-
(void)use_pattern;
|
62
83
|
}
|
63
84
|
|
64
85
|
/* *****************************************************************************
|
65
|
-
|
86
|
+
Engine registration and resetting
|
66
87
|
***************************************************************************** */
|
67
88
|
|
68
|
-
/**
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
89
|
+
/**
|
90
|
+
This method adds the engine to the pub/sub system, allowing it to recieve system
|
91
|
+
wide notifications.
|
92
|
+
*/
|
93
|
+
static VALUE iodine_engine_register2(VALUE self, VALUE engine) {
|
94
|
+
iodine_engine_s *e;
|
95
|
+
Registry.add(engine);
|
96
|
+
Data_Get_Struct(engine, iodine_engine_s, e);
|
97
|
+
if (e->p) {
|
98
|
+
e->handler = engine;
|
99
|
+
pubsub_engine_register(e->p);
|
100
|
+
return Qtrue;
|
101
|
+
}
|
102
|
+
return Qfalse;
|
103
|
+
(void)self;
|
104
|
+
(void)engine;
|
105
|
+
}
|
78
106
|
|
79
|
-
|
107
|
+
/**
|
108
|
+
This method adds the engine to the pub/sub system, allowing it to recieve system
|
109
|
+
wide notifications.
|
110
|
+
*/
|
111
|
+
static VALUE iodine_engine_register(VALUE self) {
|
112
|
+
return iodine_engine_register2(self, self);
|
113
|
+
}
|
80
114
|
|
81
|
-
|
82
|
-
|
115
|
+
/**
|
116
|
+
This method removes the engine from the pub/sub system.
|
117
|
+
*/
|
118
|
+
static VALUE iodine_engine_deregister2(VALUE self, VALUE engine) {
|
119
|
+
iodine_engine_s *e;
|
120
|
+
Data_Get_Struct(engine, iodine_engine_s, e);
|
121
|
+
if (e->p) {
|
122
|
+
pubsub_engine_deregister(e->p);
|
123
|
+
Registry.remove(engine);
|
124
|
+
return Qtrue;
|
125
|
+
}
|
126
|
+
Registry.remove(engine);
|
127
|
+
return Qfalse;
|
128
|
+
(void)self;
|
129
|
+
(void)engine;
|
130
|
+
}
|
83
131
|
|
84
|
-
|
132
|
+
/**
|
133
|
+
This method removes the engine from the pub/sub system.
|
134
|
+
*/
|
135
|
+
static VALUE iodine_engine_deregister(VALUE self) {
|
136
|
+
return iodine_engine_deregister2(self, self);
|
137
|
+
}
|
85
138
|
|
86
|
-
|
87
|
-
|
139
|
+
/**
|
140
|
+
This method resets the engine, (re)sending all the current subscription data as
|
141
|
+
if the {register} method was just called.
|
142
|
+
*/
|
143
|
+
static VALUE iodine_engine_reset2(VALUE self, VALUE engine) {
|
144
|
+
iodine_engine_s *e;
|
145
|
+
Data_Get_Struct(engine, iodine_engine_s, e);
|
146
|
+
if (e->p) {
|
147
|
+
e->handler = engine;
|
148
|
+
pubsub_engine_resubscribe(e->p);
|
149
|
+
return Qtrue;
|
150
|
+
}
|
151
|
+
return Qfalse;
|
152
|
+
(void)self;
|
153
|
+
(void)engine;
|
154
|
+
}
|
88
155
|
|
89
|
-
|
90
|
-
|
156
|
+
/**
|
157
|
+
This method resets the engine, (re)sending all the current subscription data as
|
158
|
+
if the {register} method was just called.
|
91
159
|
*/
|
92
|
-
static VALUE
|
93
|
-
|
94
|
-
|
95
|
-
"wrong number of arguments (given %d, expected 2..3).", argc);
|
96
|
-
VALUE channel = argv[0];
|
97
|
-
VALUE msg = argv[1];
|
98
|
-
VALUE pattern = argc >= 3 ? argv[2] : Qnil;
|
99
|
-
Check_Type(channel, T_STRING);
|
100
|
-
Check_Type(msg, T_STRING);
|
160
|
+
static VALUE iodine_engine_reset(VALUE self) {
|
161
|
+
return iodine_engine_reset2(self, self);
|
162
|
+
}
|
101
163
|
|
102
|
-
|
103
|
-
|
164
|
+
/* *****************************************************************************
|
165
|
+
Ruby Subscription Object
|
166
|
+
***************************************************************************** */
|
167
|
+
typedef struct {
|
168
|
+
uintptr_t subscription;
|
169
|
+
intptr_t uuid;
|
170
|
+
void *owner;
|
171
|
+
iodine_pubsub_type_e type;
|
172
|
+
} iodine_subscription_s;
|
173
|
+
|
174
|
+
static inline iodine_subscription_s subscription_data(VALUE self) {
|
175
|
+
iodine_subscription_s data = {.uuid = iodine_get_fd(self)};
|
176
|
+
if (data.uuid && !sock_isvalid(data.uuid)) {
|
177
|
+
iodine_set_fd(self, -1);
|
178
|
+
data.uuid = -1;
|
179
|
+
return data;
|
180
|
+
}
|
181
|
+
|
182
|
+
data.subscription =
|
183
|
+
((uintptr_t)NUM2LL(rb_ivar_get(self, iodine_timeout_var_id)));
|
184
|
+
data.owner = iodine_get_cdata(self);
|
185
|
+
if (!data.owner) {
|
186
|
+
data.type = IODINE_PUBSUB_GLOBAL;
|
187
|
+
} else if ((uintptr_t)data.owner & 1) {
|
188
|
+
data.owner = (void *)((uintptr_t)data.owner & (~(uintptr_t)1));
|
189
|
+
data.type = IODINE_PUBSUB_SSE;
|
190
|
+
} else {
|
191
|
+
data.type = IODINE_PUBSUB_WEBSOCKET;
|
192
|
+
}
|
193
|
+
return data;
|
194
|
+
}
|
104
195
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
196
|
+
static inline VALUE subscription_initialize(uintptr_t sub, intptr_t uuid,
|
197
|
+
void *owner,
|
198
|
+
iodine_pubsub_type_e type,
|
199
|
+
VALUE channel) {
|
200
|
+
VALUE self = RubyCaller.call(IodinePubSubSubscription, iodine_new_func_id);
|
201
|
+
if (type == IODINE_PUBSUB_SSE)
|
202
|
+
owner = (void *)((uintptr_t)owner | (uintptr_t)1);
|
203
|
+
iodine_set_cdata(self, owner);
|
204
|
+
iodine_set_fd(self, uuid);
|
205
|
+
rb_ivar_set(self, to_str_shadow_id, channel);
|
206
|
+
rb_ivar_set(self, iodine_timeout_var_id, ULL2NUM(sub));
|
112
207
|
return self;
|
113
208
|
}
|
114
209
|
|
210
|
+
// static void set_subscription(VALUE self, pubsub_sub_pt sub) {
|
211
|
+
// iodine_set_cdata(self, sub);
|
212
|
+
// }
|
213
|
+
|
214
|
+
/** Closes (cancels) a subscription. */
|
215
|
+
static VALUE close_subscription(VALUE self) {
|
216
|
+
iodine_subscription_s data = subscription_data(self);
|
217
|
+
if (!data.subscription)
|
218
|
+
return Qnil;
|
219
|
+
switch (data.type) {
|
220
|
+
case IODINE_PUBSUB_GLOBAL:
|
221
|
+
pubsub_unsubscribe((pubsub_sub_pt)data.subscription);
|
222
|
+
break;
|
223
|
+
case IODINE_PUBSUB_WEBSOCKET:
|
224
|
+
websocket_unsubscribe(data.owner, data.subscription);
|
225
|
+
break;
|
226
|
+
case IODINE_PUBSUB_SSE:
|
227
|
+
http_sse_unsubscribe(data.owner, data.subscription);
|
228
|
+
break;
|
229
|
+
}
|
230
|
+
rb_ivar_set(self, iodine_timeout_var_id, ULL2NUM(0));
|
231
|
+
return Qnil;
|
232
|
+
}
|
233
|
+
|
234
|
+
/** Test if the subscription's target is equal to String. */
|
235
|
+
static VALUE subscription_eq_s(VALUE self, VALUE str) {
|
236
|
+
return rb_str_equal(rb_attr_get(self, to_str_shadow_id), str);
|
237
|
+
}
|
238
|
+
|
239
|
+
/** Returns the target stream / channel / pattern as a String object. */
|
240
|
+
static VALUE subscription_to_s(VALUE self) {
|
241
|
+
return rb_attr_get(self, to_str_shadow_id);
|
242
|
+
}
|
243
|
+
|
244
|
+
/* *****************************************************************************
|
245
|
+
Ruby API
|
246
|
+
***************************************************************************** */
|
247
|
+
|
115
248
|
pubsub_engine_s *iodine_engine_ruby2facil(VALUE ruby_engine) {
|
116
249
|
if (ruby_engine == Qnil || ruby_engine == Qfalse)
|
117
250
|
return NULL;
|
@@ -128,73 +261,77 @@ C => Ruby Bridge
|
|
128
261
|
|
129
262
|
struct engine_gvl_args_s {
|
130
263
|
const pubsub_engine_s *eng;
|
131
|
-
|
132
|
-
|
133
|
-
const char *msg;
|
134
|
-
size_t msg_len;
|
264
|
+
FIOBJ ch;
|
265
|
+
FIOBJ msg;
|
135
266
|
uint8_t use_pattern;
|
136
267
|
};
|
137
268
|
|
138
269
|
static void *engine_subscribe_inGVL(void *a_) {
|
139
270
|
struct engine_gvl_args_s *args = a_;
|
271
|
+
VALUE eng = ((iodine_engine_s *)args->eng)->handler;
|
272
|
+
if (!eng || eng == Qnil || eng == Qfalse)
|
273
|
+
return NULL;
|
140
274
|
VALUE data[2];
|
141
|
-
|
275
|
+
fio_cstr_s tmp = fiobj_obj2cstr(args->ch);
|
142
276
|
data[1] = args->use_pattern ? Qtrue : Qnil;
|
143
|
-
|
277
|
+
data[0] = rb_str_new(tmp.data, tmp.len);
|
144
278
|
eng = RubyCaller.call2(eng, engine_subid, 2, data);
|
145
|
-
return
|
279
|
+
return NULL;
|
146
280
|
}
|
147
281
|
|
148
282
|
/* Should return 0 on success and -1 on failure. */
|
149
|
-
static
|
150
|
-
|
283
|
+
static void engine_subscribe(const pubsub_engine_s *eng, FIOBJ ch,
|
284
|
+
uint8_t use_pattern) {
|
151
285
|
struct engine_gvl_args_s args = {
|
152
|
-
.eng = eng, .ch = ch, .
|
286
|
+
.eng = eng, .ch = ch, .use_pattern = use_pattern,
|
153
287
|
};
|
154
|
-
|
288
|
+
RubyCaller.call_c(engine_subscribe_inGVL, &args);
|
155
289
|
}
|
156
290
|
|
157
291
|
static void *engine_unsubscribe_inGVL(void *a_) {
|
158
292
|
struct engine_gvl_args_s *args = a_;
|
293
|
+
VALUE eng = ((iodine_engine_s *)args->eng)->handler;
|
294
|
+
if (!eng || eng == Qnil || eng == Qfalse)
|
295
|
+
return NULL;
|
159
296
|
VALUE data[2];
|
160
|
-
|
297
|
+
fio_cstr_s tmp = fiobj_obj2cstr(args->ch);
|
161
298
|
data[1] = args->use_pattern ? Qtrue : Qnil;
|
162
|
-
|
299
|
+
data[0] = rb_str_new(tmp.data, tmp.len);
|
163
300
|
RubyCaller.call2(eng, engine_unsubid, 2, data);
|
164
301
|
return NULL;
|
165
302
|
}
|
166
303
|
|
167
304
|
/* Return value is ignored - nothing should be returned. */
|
168
|
-
static void engine_unsubscribe(const pubsub_engine_s *eng,
|
169
|
-
|
305
|
+
static void engine_unsubscribe(const pubsub_engine_s *eng, FIOBJ ch,
|
306
|
+
uint8_t use_pattern) {
|
170
307
|
struct engine_gvl_args_s args = {
|
171
|
-
.eng = eng, .ch = ch, .
|
308
|
+
.eng = eng, .ch = ch, .use_pattern = use_pattern,
|
172
309
|
};
|
173
310
|
RubyCaller.call_c(engine_unsubscribe_inGVL, &args);
|
174
311
|
}
|
175
312
|
|
176
313
|
static void *engine_publish_inGVL(void *a_) {
|
177
314
|
struct engine_gvl_args_s *args = a_;
|
178
|
-
VALUE data[3];
|
179
|
-
data[0] = rb_str_new(args->ch, args->ch_len);
|
180
|
-
data[1] = rb_str_new(args->msg, args->msg_len);
|
181
|
-
data[2] = args->use_pattern ? Qtrue : Qnil;
|
182
315
|
VALUE eng = ((iodine_engine_s *)args->eng)->handler;
|
183
|
-
eng
|
316
|
+
if (!eng || eng == Qnil || eng == Qfalse)
|
317
|
+
return NULL;
|
318
|
+
VALUE data[2];
|
319
|
+
fio_cstr_s tmp = fiobj_obj2cstr(args->ch);
|
320
|
+
data[0] = rb_str_new(tmp.data, tmp.len);
|
321
|
+
Registry.add(data[0]);
|
322
|
+
tmp = fiobj_obj2cstr(args->msg);
|
323
|
+
data[1] = rb_str_new(tmp.data, tmp.len);
|
324
|
+
Registry.add(data[1]);
|
325
|
+
eng = RubyCaller.call2(eng, iodine_engine_pubid, 2, data);
|
326
|
+
Registry.remove(data[0]);
|
327
|
+
Registry.remove(data[1]);
|
184
328
|
return ((eng == Qfalse || eng == Qnil) ? (void *)-1 : 0);
|
185
329
|
}
|
186
330
|
|
187
331
|
/* Should return 0 on success and -1 on failure. */
|
188
|
-
static int engine_publish(const pubsub_engine_s *eng,
|
189
|
-
size_t ch_len, const char *msg, size_t msg_len,
|
190
|
-
uint8_t use_pattern) {
|
332
|
+
static int engine_publish(const pubsub_engine_s *eng, FIOBJ ch, FIOBJ msg) {
|
191
333
|
struct engine_gvl_args_s args = {
|
192
|
-
.eng = eng,
|
193
|
-
.ch = ch,
|
194
|
-
.ch_len = ch_len,
|
195
|
-
.msg = msg,
|
196
|
-
.msg_len = msg_len,
|
197
|
-
.use_pattern = use_pattern,
|
334
|
+
.eng = eng, .ch = ch, .msg = msg,
|
198
335
|
};
|
199
336
|
return RubyCaller.call_c(engine_publish_inGVL, &args) ? 0 : -1;
|
200
337
|
}
|
@@ -216,12 +353,12 @@ static void engine_free(void *eng_) {
|
|
216
353
|
free(eng);
|
217
354
|
}
|
218
355
|
|
219
|
-
/*
|
356
|
+
/* Iodine::PubSub::Engine.allocate */
|
220
357
|
static VALUE engine_alloc_c(VALUE self) {
|
221
358
|
iodine_engine_s *eng = malloc(sizeof(*eng));
|
222
359
|
if (TYPE(self) == T_CLASS)
|
223
360
|
*eng = (iodine_engine_s){
|
224
|
-
.handler =
|
361
|
+
.handler = (VALUE)0,
|
225
362
|
.engine =
|
226
363
|
{
|
227
364
|
.subscribe = engine_subscribe,
|
@@ -237,6 +374,9 @@ static VALUE engine_alloc_c(VALUE self) {
|
|
237
374
|
static VALUE engine_initialize(VALUE self) {
|
238
375
|
iodine_engine_s *engine;
|
239
376
|
Data_Get_Struct(self, iodine_engine_s, engine);
|
377
|
+
if (TYPE(self) == T_CLASS) {
|
378
|
+
fprintf(stderr, "This sucks...\n");
|
379
|
+
}
|
240
380
|
engine->handler = self;
|
241
381
|
return self;
|
242
382
|
}
|
@@ -246,56 +386,29 @@ Redis
|
|
246
386
|
***************************************************************************** */
|
247
387
|
|
248
388
|
struct redis_callback_data {
|
249
|
-
|
389
|
+
FIOBJ msg;
|
250
390
|
VALUE block;
|
251
391
|
};
|
252
392
|
|
253
|
-
/*
|
254
|
-
populate
|
255
|
-
*/
|
256
|
-
int populate_redis_callback_reply(resp_parser_pt p, resp_object_s *o,
|
257
|
-
void *rep) {
|
258
|
-
switch (o->type) {
|
259
|
-
case RESP_ARRAY:
|
260
|
-
case RESP_PUBSUB:
|
261
|
-
break;
|
262
|
-
case RESP_NULL:
|
263
|
-
rb_ary_push((VALUE)rep, Qnil);
|
264
|
-
break;
|
265
|
-
case RESP_NUMBER:
|
266
|
-
rb_ary_push((VALUE)rep, LONG2FIX(resp_obj2num(o)->number));
|
267
|
-
break;
|
268
|
-
case RESP_ERR:
|
269
|
-
case RESP_STRING:
|
270
|
-
rb_ary_push((VALUE)rep, rb_str_new((char *)resp_obj2str(o)->string,
|
271
|
-
resp_obj2str(o)->len));
|
272
|
-
break;
|
273
|
-
case RESP_OK:
|
274
|
-
rb_ary_push((VALUE)rep, rb_str_new("OK", 2));
|
275
|
-
break;
|
276
|
-
}
|
277
|
-
return 0;
|
278
|
-
(void)p;
|
279
|
-
}
|
280
393
|
/*
|
281
394
|
Perform a Redis message callback in the GVL
|
282
395
|
*/
|
283
396
|
static void *perform_redis_callback_inGVL(void *data) {
|
284
397
|
struct redis_callback_data *a = data;
|
285
|
-
VALUE reply =
|
286
|
-
|
398
|
+
VALUE reply = fiobj2rb_deep(a->msg, 1);
|
399
|
+
Registry.add(reply);
|
287
400
|
rb_funcallv(a->block, iodine_call_proc_id, 1, &reply);
|
288
401
|
Registry.remove(a->block);
|
402
|
+
Registry.remove(reply);
|
289
403
|
return NULL;
|
290
404
|
}
|
291
405
|
|
292
406
|
/*
|
293
407
|
Redis message callback
|
294
408
|
*/
|
295
|
-
static void redis_callback(pubsub_engine_s *e,
|
296
|
-
void *block) {
|
409
|
+
static void redis_callback(pubsub_engine_s *e, FIOBJ reply, void *block) {
|
297
410
|
struct redis_callback_data d = {
|
298
|
-
.msg =
|
411
|
+
.msg = reply, .block = (VALUE)block,
|
299
412
|
};
|
300
413
|
RubyCaller.call_c(perform_redis_callback_inGVL, &d);
|
301
414
|
(void)e;
|
@@ -318,46 +431,40 @@ static VALUE redis_send(int argc, VALUE *argv, VALUE self) {
|
|
318
431
|
rb_raise(rb_eArgError,
|
319
432
|
"wrong number of arguments (given %d, expected at least 1).",
|
320
433
|
argc);
|
321
|
-
resp_object_s *cmd = NULL;
|
322
434
|
Check_Type(argv[0], T_STRING);
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
default:
|
340
|
-
goto error;
|
341
|
-
break;
|
435
|
+
FIOBJ data = FIOBJ_INVALID;
|
436
|
+
FIOBJ cmd = FIOBJ_INVALID;
|
437
|
+
if (argc > 1) {
|
438
|
+
for (int i = 0; i < argc; ++i) {
|
439
|
+
if (TYPE(argv[i]) == T_SYMBOL)
|
440
|
+
argv[i] = rb_sym2str(argv[i]);
|
441
|
+
if (TYPE(argv[i]) != T_FIXNUM)
|
442
|
+
Check_Type(argv[i], T_STRING);
|
443
|
+
}
|
444
|
+
data = fiobj_ary_new();
|
445
|
+
for (int i = 0; i < argc; ++i) {
|
446
|
+
if (TYPE(argv[i]) == T_FIXNUM)
|
447
|
+
fiobj_ary_push(data, fiobj_num_new(FIX2LONG(argv[i])));
|
448
|
+
else
|
449
|
+
fiobj_ary_push(
|
450
|
+
data, fiobj_str_new(RSTRING_PTR(argv[i]), RSTRING_LEN(argv[i])));
|
342
451
|
}
|
343
452
|
}
|
453
|
+
cmd = fiobj_str_new(RSTRING_PTR(argv[0]), RSTRING_LEN(argv[0]));
|
454
|
+
iodine_engine_s *e;
|
455
|
+
Data_Get_Struct(self, iodine_engine_s, e);
|
344
456
|
|
345
457
|
if (rb_block_given_p()) {
|
346
458
|
VALUE block = rb_block_proc();
|
347
459
|
Registry.add(block);
|
348
|
-
redis_engine_send(e->p, cmd, redis_callback, (void *)block);
|
460
|
+
redis_engine_send(e->p, cmd, data, redis_callback, (void *)block);
|
349
461
|
return block;
|
350
462
|
} else {
|
351
|
-
redis_engine_send(e->p, cmd, NULL, NULL);
|
463
|
+
redis_engine_send(e->p, cmd, data, NULL, NULL);
|
352
464
|
}
|
465
|
+
fiobj_free(cmd);
|
466
|
+
fiobj_free(data);
|
353
467
|
return Qtrue;
|
354
|
-
error:
|
355
|
-
if (cmd)
|
356
|
-
resp_free_object(cmd);
|
357
|
-
rb_raise(rb_eArgError, "Arguments can only include Strings, Symbols and "
|
358
|
-
"Integers - no arrays or hashes or other objects can "
|
359
|
-
"be sent.");
|
360
|
-
return self;
|
361
468
|
}
|
362
469
|
|
363
470
|
/**
|
@@ -371,7 +478,7 @@ Accepts:
|
|
371
478
|
|
372
479
|
address:: the Redis server's address. Required.
|
373
480
|
port:: the Redis Server port. Default: 6379
|
374
|
-
ping:: the PING interval. Default: 0 (~5 minutes).
|
481
|
+
ping:: the PING interval up to 255 seconds. Default: 0 (~5 minutes).
|
375
482
|
auth:: authentication password. Default: none.
|
376
483
|
*/
|
377
484
|
static VALUE redis_engine_initialize(int argc, VALUE *argv, VALUE self) {
|
@@ -407,9 +514,9 @@ static VALUE redis_engine_initialize(int argc, VALUE *argv, VALUE self) {
|
|
407
514
|
.ping_interval = iping,
|
408
515
|
.auth = (auth == Qnil ? NULL : StringValueCStr(auth)),
|
409
516
|
.auth_len = (auth == Qnil ? 0 : RSTRING_LEN(auth)));
|
517
|
+
engine->dealloc = redis_engine_destroy;
|
410
518
|
if (!engine->p)
|
411
519
|
rb_raise(rb_eRuntimeError, "unknown error, can't initialize RedisEngine.");
|
412
|
-
engine->dealloc = redis_engine_destroy;
|
413
520
|
return self;
|
414
521
|
}
|
415
522
|
|
@@ -429,9 +536,17 @@ static VALUE ips_set_default(VALUE self, VALUE en) {
|
|
429
536
|
rb_raise(rb_eArgError, "deafult engine must be an Iodine::PubSub::Engine.");
|
430
537
|
if (!e->p)
|
431
538
|
rb_raise(rb_eArgError, "This Iodine::PubSub::Engine is broken.");
|
432
|
-
rb_ivar_set(
|
539
|
+
rb_ivar_set(Iodine, default_pubsubid, en);
|
433
540
|
PUBSUB_DEFAULT_ENGINE = e->p;
|
434
541
|
return en;
|
542
|
+
(void)self;
|
543
|
+
}
|
544
|
+
|
545
|
+
/** Deprecated. Use {Iodine::PubSub.default_engine=}. */
|
546
|
+
static VALUE ips_set_default_dep(VALUE self, VALUE en) {
|
547
|
+
fprintf(stderr, "WARNING: Iodine.default_pubsub is deprecated. Use "
|
548
|
+
"Iodine::PubSub.default_engine.\n");
|
549
|
+
return ips_set_default(self, en);
|
435
550
|
}
|
436
551
|
|
437
552
|
/**
|
@@ -440,7 +555,17 @@ Returns the default Pub/Sub engine (if any).
|
|
440
555
|
See {Iodine::PubSub} and {Iodine::PubSub::Engine} for more details.
|
441
556
|
*/
|
442
557
|
static VALUE ips_get_default(VALUE self) {
|
443
|
-
return rb_ivar_get(
|
558
|
+
return rb_ivar_get(Iodine, default_pubsubid);
|
559
|
+
(void)self;
|
560
|
+
}
|
561
|
+
|
562
|
+
/**
|
563
|
+
Deprecated. Use {Iodine::PubSub.default_engine}.
|
564
|
+
*/
|
565
|
+
static VALUE ips_get_default_dep(VALUE self) {
|
566
|
+
fprintf(stderr, "WARNING: Iodine.default_pubsub is deprecated. Use "
|
567
|
+
"Iodine::PubSub.default_engine.\n");
|
568
|
+
return ips_get_default(self);
|
444
569
|
}
|
445
570
|
|
446
571
|
/* *****************************************************************************
|
@@ -455,9 +580,11 @@ static void iodine_on_unsubscribe(void *u1, void *u2) {
|
|
455
580
|
|
456
581
|
static void *on_pubsub_notificationinGVL(pubsub_message_s *n) {
|
457
582
|
VALUE rbn[2];
|
458
|
-
|
583
|
+
fio_cstr_s tmp = fiobj_obj2cstr(n->channel);
|
584
|
+
rbn[0] = rb_str_new(tmp.data, tmp.len);
|
459
585
|
Registry.add(rbn[0]);
|
460
|
-
|
586
|
+
tmp = fiobj_obj2cstr(n->message);
|
587
|
+
rbn[1] = rb_str_new(tmp.data, tmp.len);
|
461
588
|
Registry.add(rbn[1]);
|
462
589
|
RubyCaller.call2((VALUE)n->udata1, iodine_call_proc_id, 2, rbn);
|
463
590
|
Registry.remove(rbn[0]);
|
@@ -469,116 +596,256 @@ static void on_pubsub_notificationin(pubsub_message_s *n) {
|
|
469
596
|
RubyCaller.call_c((void *(*)(void *))on_pubsub_notificationinGVL, n);
|
470
597
|
}
|
471
598
|
|
472
|
-
|
473
|
-
|
474
|
-
(
|
475
|
-
|
476
|
-
The function accepts a single argument (a Hash) and a required block.
|
599
|
+
static void iodine_on_unsubscribe_ws(void *u) {
|
600
|
+
if (u && (VALUE)u != Qnil && u != (VALUE)Qfalse)
|
601
|
+
Registry.remove((VALUE)u);
|
602
|
+
}
|
477
603
|
|
478
|
-
|
604
|
+
static void *
|
605
|
+
on_pubsub_notificationinGVL_ws(websocket_pubsub_notification_s *n) {
|
606
|
+
VALUE rbn[2];
|
607
|
+
fio_cstr_s tmp = fiobj_obj2cstr(n->channel);
|
608
|
+
rbn[0] = rb_str_new(tmp.data, tmp.len);
|
609
|
+
Registry.add(rbn[0]);
|
610
|
+
tmp = fiobj_obj2cstr(n->message);
|
611
|
+
rbn[1] = rb_str_new(tmp.data, tmp.len);
|
612
|
+
Registry.add(rbn[1]);
|
613
|
+
RubyCaller.call2((VALUE)n->udata, iodine_call_proc_id, 2, rbn);
|
614
|
+
Registry.remove(rbn[0]);
|
615
|
+
Registry.remove(rbn[1]);
|
616
|
+
return NULL;
|
617
|
+
}
|
479
618
|
|
480
|
-
|
481
|
-
|
619
|
+
static void on_pubsub_notificationin_ws(websocket_pubsub_notification_s n) {
|
620
|
+
RubyCaller.call_c((void *(*)(void *))on_pubsub_notificationinGVL_ws, &n);
|
621
|
+
}
|
482
622
|
|
483
|
-
|
623
|
+
static void on_pubsub_notificationin_sse(http_sse_s *sse, FIOBJ channel,
|
624
|
+
FIOBJ message, void *udata) {
|
625
|
+
websocket_pubsub_notification_s n = {
|
626
|
+
.channel = channel, .message = message, .udata = udata};
|
627
|
+
RubyCaller.call_c((void *(*)(void *))on_pubsub_notificationinGVL, &n);
|
628
|
+
(void)sse;
|
629
|
+
}
|
484
630
|
|
485
|
-
|
631
|
+
/** Subscribes to a Pub/Sub channel - internal implementation */
|
632
|
+
VALUE iodine_subscribe(int argc, VALUE *argv, void *owner,
|
633
|
+
iodine_pubsub_type_e type) {
|
486
634
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
635
|
+
VALUE rb_ch = Qnil;
|
636
|
+
VALUE rb_opt = 0;
|
637
|
+
VALUE block = 0;
|
638
|
+
uint8_t use_pattern = 0, force_text = 1, force_binary = 0;
|
639
|
+
intptr_t uuid = 0;
|
491
640
|
|
492
|
-
|
641
|
+
switch (argc) {
|
642
|
+
case 2:
|
643
|
+
rb_ch = argv[0];
|
644
|
+
rb_opt = argv[1];
|
645
|
+
break;
|
646
|
+
case 1:
|
647
|
+
/* single argument must be a Hash / channel name */
|
648
|
+
if (TYPE(argv[0]) == T_HASH) {
|
649
|
+
rb_opt = argv[0];
|
650
|
+
rb_ch = rb_hash_aref(argv[0], to_sym_id);
|
651
|
+
if (rb_ch == Qnil || rb_ch == Qfalse) {
|
652
|
+
/* temporary backport support */
|
653
|
+
rb_ch = rb_hash_aref(argv[0], channel_sym_id);
|
654
|
+
if (rb_ch) {
|
655
|
+
fprintf(stderr,
|
656
|
+
"WARNING: use of :channel in subscribe is deprecated.\n");
|
657
|
+
}
|
658
|
+
}
|
659
|
+
} else {
|
660
|
+
rb_ch = argv[0];
|
661
|
+
}
|
662
|
+
break;
|
663
|
+
default:
|
664
|
+
rb_raise(rb_eArgError, "method accepts 1 or 2 arguments.");
|
665
|
+
return Qnil;
|
666
|
+
}
|
493
667
|
|
494
|
-
VALUE rb_ch = rb_hash_aref(args, channel_var_id);
|
495
668
|
if (rb_ch == Qnil || rb_ch == Qfalse) {
|
496
|
-
|
497
|
-
|
498
|
-
if (rb_ch == Qnil || rb_ch == Qfalse)
|
499
|
-
rb_raise(rb_eArgError, "a channel is required for pub/sub methods.");
|
669
|
+
rb_raise(rb_eArgError,
|
670
|
+
"a target (:to) subject / stream / channel is required.");
|
500
671
|
}
|
672
|
+
|
501
673
|
if (TYPE(rb_ch) == T_SYMBOL)
|
502
674
|
rb_ch = rb_sym2str(rb_ch);
|
503
675
|
Check_Type(rb_ch, T_STRING);
|
504
676
|
|
505
|
-
|
506
|
-
|
677
|
+
if (rb_opt) {
|
678
|
+
if (type == IODINE_PUBSUB_WEBSOCKET &&
|
679
|
+
rb_hash_aref(rb_opt, as_sym_id) == binary_sym_id) {
|
680
|
+
force_text = 0;
|
681
|
+
force_binary = 1;
|
682
|
+
}
|
683
|
+
if (rb_hash_aref(rb_opt, match_sym_id) == redis_sym_id) {
|
684
|
+
use_pattern = 1;
|
685
|
+
}
|
686
|
+
block = rb_hash_aref(rb_opt, handler_sym_id);
|
687
|
+
if (block != Qnil)
|
688
|
+
Registry.add(block);
|
689
|
+
}
|
690
|
+
|
691
|
+
if (block == Qnil) {
|
692
|
+
if (rb_block_given_p()) {
|
693
|
+
block = rb_block_proc();
|
694
|
+
Registry.add(block);
|
695
|
+
} else if (type == IODINE_PUBSUB_GLOBAL) {
|
696
|
+
rb_need_block();
|
697
|
+
return Qnil;
|
698
|
+
}
|
699
|
+
}
|
700
|
+
if (block == Qnil)
|
701
|
+
block = 0;
|
702
|
+
|
703
|
+
FIOBJ ch = fiobj_str_new(RSTRING_PTR(rb_ch), RSTRING_LEN(rb_ch));
|
704
|
+
|
705
|
+
uintptr_t sub = 0;
|
706
|
+
switch (type) {
|
707
|
+
case IODINE_PUBSUB_GLOBAL:
|
708
|
+
sub = (uintptr_t)pubsub_subscribe(.channel = ch, .use_pattern = use_pattern,
|
709
|
+
.on_message = on_pubsub_notificationin,
|
710
|
+
.on_unsubscribe = iodine_on_unsubscribe,
|
711
|
+
.udata1 = (void *)block);
|
712
|
+
break;
|
713
|
+
case IODINE_PUBSUB_WEBSOCKET:
|
714
|
+
uuid = websocket_uuid(owner);
|
715
|
+
sub = websocket_subscribe(
|
716
|
+
owner, .channel = ch, .use_pattern = use_pattern,
|
717
|
+
.force_text = force_text, .force_binary = force_binary,
|
718
|
+
.on_message = (block ? on_pubsub_notificationin_ws : NULL),
|
719
|
+
.on_unsubscribe = (block ? iodine_on_unsubscribe_ws : NULL),
|
720
|
+
.udata = (void *)block);
|
721
|
+
break;
|
722
|
+
case IODINE_PUBSUB_SSE:
|
723
|
+
uuid = http_sse2uuid(owner);
|
724
|
+
sub = http_sse_subscribe(
|
725
|
+
owner, .channel = ch, .use_pattern = use_pattern,
|
726
|
+
.on_message = (block ? on_pubsub_notificationin_sse : NULL),
|
727
|
+
.on_unsubscribe = (block ? iodine_on_unsubscribe_ws : NULL),
|
728
|
+
.udata = (void *)block);
|
507
729
|
|
508
|
-
|
509
|
-
|
730
|
+
break;
|
731
|
+
}
|
510
732
|
|
511
|
-
|
512
|
-
|
513
|
-
.channel.len = RSTRING_LEN(rb_ch),
|
514
|
-
.engine = engine, .use_pattern = use_pattern,
|
515
|
-
.on_message = on_pubsub_notificationin,
|
516
|
-
.on_unsubscribe = iodine_on_unsubscribe,
|
517
|
-
.udata1 = (void *)block);
|
518
|
-
if (!subid)
|
733
|
+
fiobj_free(ch);
|
734
|
+
if (!sub)
|
519
735
|
return Qnil;
|
520
|
-
return
|
521
|
-
(void)self;
|
736
|
+
return subscription_initialize(sub, uuid, owner, type, rb_ch);
|
522
737
|
}
|
523
738
|
|
739
|
+
// clang-format off
|
524
740
|
/**
|
525
|
-
|
741
|
+
Subscribes to a Pub/Sub channel.
|
742
|
+
|
743
|
+
The method accepts 1-2 arguments and an optional block. These are all valid ways
|
744
|
+
to call the method:
|
745
|
+
|
746
|
+
subscribe("my_stream") {|from, msg| p msg }
|
747
|
+
subscribe("my_stream", match: :redis) {|from, msg| p msg }
|
748
|
+
subscribe(to: "my_stream") {|from, msg| p msg }
|
749
|
+
subscribe to: "my_stream", match: :redis, handler: MyProc
|
750
|
+
|
751
|
+
The first argument must be either a String or a Hash.
|
752
|
+
|
753
|
+
The second, optional, argument must be a Hash (if given).
|
754
|
+
|
755
|
+
The options Hash supports the following possible keys (other keys are ignored, all keys are Symbols):
|
756
|
+
|
757
|
+
: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.
|
758
|
+
|
759
|
+
:to :: The channel / subject to subscribe to.
|
760
|
+
|
761
|
+
Returns an {Iodine::PubSub::Subscription} object that answers to:
|
762
|
+
|
763
|
+
close :: closes the connection.
|
764
|
+
to_s :: returns the subscription's target (stream / channel / subject).
|
765
|
+
==(str) :: returns true if the string is an exact match for the target (even if the target itself is a pattern).
|
766
|
+
|
526
767
|
*/
|
527
|
-
static VALUE
|
528
|
-
|
529
|
-
|
530
|
-
Check_Type(sub_id, T_FIXNUM);
|
531
|
-
pubsub_unsubscribe((pubsub_sub_pt)NUM2LONG(sub_id));
|
532
|
-
return Qnil;
|
768
|
+
static VALUE iodine_subscribe_global(int argc, VALUE *argv, VALUE self) {
|
769
|
+
// clang-format on
|
770
|
+
return iodine_subscribe(argc, argv, NULL, IODINE_PUBSUB_GLOBAL);
|
533
771
|
(void)self;
|
534
772
|
}
|
535
773
|
|
536
774
|
/**
|
537
775
|
Publishes a message to a channel.
|
538
776
|
|
539
|
-
|
777
|
+
Can be used using two Strings:
|
778
|
+
|
779
|
+
publish(to, message)
|
780
|
+
|
781
|
+
The method accepts an optional `engine` argument:
|
782
|
+
|
783
|
+
publish(to, message, my_pubsub_engine)
|
540
784
|
|
541
|
-
:engine :: If provided, the engine to use for pub/sub. Otherwise the default
|
542
|
-
engine is used.
|
543
785
|
|
544
|
-
|
786
|
+
Alternatively, accepts the following named arguments:
|
545
787
|
|
546
|
-
:
|
547
|
-
|
788
|
+
:to :: The channel to publish to (required).
|
789
|
+
|
790
|
+
:message :: The message to be published (required).
|
791
|
+
|
792
|
+
:engine :: If provided, the engine to use for pub/sub. Otherwise the default
|
793
|
+
engine is used.
|
548
794
|
|
549
|
-
:message :: REQUIRED. The message to be published.
|
550
|
-
:
|
551
795
|
*/
|
552
|
-
|
553
|
-
|
796
|
+
VALUE iodine_publish(int argc, VALUE *argv, VALUE self) {
|
797
|
+
VALUE rb_ch, rb_msg, rb_engine = Qnil;
|
554
798
|
uint8_t use_pattern = 0;
|
799
|
+
const pubsub_engine_s *engine = NULL;
|
800
|
+
switch (argc) {
|
801
|
+
case 3:
|
802
|
+
/* fallthrough */
|
803
|
+
rb_engine = argv[2];
|
804
|
+
case 2:
|
805
|
+
rb_ch = argv[0];
|
806
|
+
rb_msg = argv[1];
|
807
|
+
break;
|
808
|
+
case 1: {
|
809
|
+
/* single argument must be a Hash */
|
810
|
+
Check_Type(argv[0], T_HASH);
|
811
|
+
rb_ch = rb_hash_aref(argv[0], to_sym_id);
|
812
|
+
if (rb_ch == Qnil || rb_ch == Qfalse) {
|
813
|
+
use_pattern = 1;
|
814
|
+
rb_ch = rb_hash_aref(argv[0], match_sym_id);
|
815
|
+
}
|
816
|
+
rb_msg = rb_hash_aref(argv[0], message_sym_id);
|
817
|
+
rb_engine = rb_hash_aref(argv[0], engine_varid);
|
818
|
+
} break;
|
819
|
+
default:
|
820
|
+
rb_raise(rb_eArgError, "method accepts 1-3 arguments.");
|
821
|
+
}
|
555
822
|
|
556
|
-
|
557
|
-
|
558
|
-
use_pattern = 1;
|
559
|
-
rb_ch = rb_hash_aref(args, pattern_var_id);
|
560
|
-
if (rb_ch == Qnil || rb_ch == Qfalse)
|
561
|
-
rb_raise(rb_eArgError, "channel is required for pub/sub methods.");
|
823
|
+
if (rb_msg == Qnil || rb_msg == Qfalse) {
|
824
|
+
rb_raise(rb_eArgError, "message is required.");
|
562
825
|
}
|
826
|
+
Check_Type(rb_msg, T_STRING);
|
827
|
+
|
828
|
+
if (rb_ch == Qnil || rb_ch == Qfalse)
|
829
|
+
rb_raise(rb_eArgError, "channel is required .");
|
563
830
|
if (TYPE(rb_ch) == T_SYMBOL)
|
564
831
|
rb_ch = rb_sym2str(rb_ch);
|
565
832
|
Check_Type(rb_ch, T_STRING);
|
566
833
|
|
567
|
-
|
568
|
-
|
569
|
-
|
834
|
+
if (rb_engine == Qfalse) {
|
835
|
+
engine = PUBSUB_PROCESS_ENGINE;
|
836
|
+
} else if (rb_engine == Qnil) {
|
837
|
+
engine = NULL;
|
838
|
+
} else {
|
839
|
+
engine = iodine_engine_ruby2facil(rb_engine);
|
570
840
|
}
|
571
|
-
Check_Type(rb_msg, T_STRING);
|
572
841
|
|
573
|
-
|
574
|
-
|
842
|
+
FIOBJ ch = fiobj_str_new(RSTRING_PTR(rb_ch), RSTRING_LEN(rb_ch));
|
843
|
+
FIOBJ msg = fiobj_str_new(RSTRING_PTR(rb_msg), RSTRING_LEN(rb_msg));
|
575
844
|
|
576
845
|
intptr_t ret =
|
577
|
-
pubsub_publish(.engine = engine, .channel.
|
578
|
-
|
579
|
-
|
580
|
-
.msg.len = (RSTRING_LEN(rb_msg)),
|
581
|
-
.use_pattern = use_pattern);
|
846
|
+
pubsub_publish(.engine = engine, .channel = ch, .message = msg);
|
847
|
+
fiobj_free(ch);
|
848
|
+
fiobj_free(msg);
|
582
849
|
if (!ret)
|
583
850
|
return Qfalse;
|
584
851
|
return Qtrue;
|
@@ -589,32 +856,64 @@ static VALUE iodine_publish(VALUE self, VALUE args) {
|
|
589
856
|
Initialization
|
590
857
|
***************************************************************************** */
|
591
858
|
void Iodine_init_pubsub(void) {
|
592
|
-
|
859
|
+
default_pubsubid = rb_intern("default_pubsub");
|
593
860
|
engine_subid = rb_intern("subscribe");
|
594
861
|
engine_unsubid = rb_intern("unsubscribe");
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
862
|
+
engine_varid = rb_intern("engine");
|
863
|
+
iodine_engine_pubid = rb_intern("publish");
|
864
|
+
to_str_shadow_id = rb_intern("@to_s");
|
865
|
+
|
866
|
+
as_sym_id = ID2SYM(rb_intern("as"));
|
867
|
+
binary_sym_id = ID2SYM(rb_intern("binary"));
|
868
|
+
handler_sym_id = ID2SYM(rb_intern("handler"));
|
869
|
+
match_sym_id = ID2SYM(rb_intern("match"));
|
870
|
+
message_sym_id = ID2SYM(rb_intern("message"));
|
871
|
+
redis_sym_id = ID2SYM(rb_intern("redis"));
|
872
|
+
text_sym_id = ID2SYM(rb_intern("text"));
|
873
|
+
to_sym_id = ID2SYM(rb_intern("to"));
|
874
|
+
|
875
|
+
channel_sym_id = ID2SYM(rb_intern("channel")); /* bawards compatibility */
|
600
876
|
|
601
877
|
IodinePubSub = rb_define_module_under(Iodine, "PubSub");
|
602
878
|
IodineEngine = rb_define_class_under(IodinePubSub, "Engine", rb_cObject);
|
879
|
+
IodinePubSubSubscription =
|
880
|
+
rb_define_class_under(IodinePubSub, "Subscription", rb_cObject);
|
881
|
+
|
882
|
+
rb_define_method(IodinePubSubSubscription, "close", close_subscription, 0);
|
883
|
+
rb_define_method(IodinePubSubSubscription, "==", subscription_eq_s, 1);
|
884
|
+
rb_attr(IodinePubSubSubscription, rb_intern("to_s"), 1, 0, 1);
|
885
|
+
rb_define_method(IodinePubSubSubscription, "to_s", subscription_to_s, 1);
|
603
886
|
|
604
887
|
rb_define_alloc_func(IodineEngine, engine_alloc_c);
|
605
888
|
rb_define_method(IodineEngine, "initialize", engine_initialize, 0);
|
606
889
|
|
607
|
-
rb_define_method(IodineEngine, "distribute", engine_distribute, -1);
|
608
890
|
rb_define_method(IodineEngine, "subscribe", engine_sub_placeholder, 2);
|
609
891
|
rb_define_method(IodineEngine, "unsubscribe", engine_sub_placeholder, 2);
|
610
|
-
rb_define_method(IodineEngine, "publish", engine_pub_placeholder,
|
892
|
+
rb_define_method(IodineEngine, "publish", engine_pub_placeholder, 2);
|
893
|
+
rb_define_method(IodineEngine, "register", iodine_engine_register, 0);
|
894
|
+
rb_define_method(IodineEngine, "deregister", iodine_engine_deregister, 0);
|
895
|
+
rb_define_method(IodineEngine, "reset", iodine_engine_reset, 0);
|
611
896
|
|
612
|
-
rb_define_module_function(Iodine, "
|
613
|
-
rb_define_module_function(Iodine, "
|
897
|
+
rb_define_module_function(Iodine, "subscribe", iodine_subscribe_global, -1);
|
898
|
+
rb_define_module_function(Iodine, "publish", iodine_publish, -1);
|
899
|
+
rb_define_module_function(Iodine, "default_engine=", ips_set_default, 1);
|
900
|
+
rb_define_module_function(Iodine, "default_engine", ips_get_default, 0);
|
614
901
|
|
615
|
-
rb_define_module_function(
|
616
|
-
|
617
|
-
rb_define_module_function(
|
902
|
+
rb_define_module_function(IodinePubSub, "default_engine=", ips_set_default,
|
903
|
+
1);
|
904
|
+
rb_define_module_function(IodinePubSub, "default_engine", ips_get_default, 0);
|
905
|
+
rb_define_method(IodinePubSub, "register", iodine_engine_register2, 1);
|
906
|
+
rb_define_method(IodinePubSub, "deregister", iodine_engine_deregister2, 1);
|
907
|
+
rb_define_method(IodinePubSub, "reset", iodine_engine_reset2, 1);
|
908
|
+
|
909
|
+
rb_define_module_function(IodinePubSub, "subscribe", iodine_subscribe_global,
|
910
|
+
-1);
|
911
|
+
rb_define_module_function(IodinePubSub, "publish", iodine_publish, -1);
|
912
|
+
|
913
|
+
/* deprecated */
|
914
|
+
|
915
|
+
rb_define_module_function(Iodine, "default_pubsub=", ips_set_default_dep, 1);
|
916
|
+
rb_define_module_function(Iodine, "default_pubsub", ips_get_default_dep, 0);
|
618
917
|
|
619
918
|
/* *************************
|
620
919
|
Initialize C pubsub engines
|
@@ -629,6 +928,7 @@ void Iodine_init_pubsub(void) {
|
|
629
928
|
/** This is the (currently) default pub/sub engine. It will distribute
|
630
929
|
* messages to all subscribers in the process cluster. */
|
631
930
|
rb_define_const(IodinePubSub, "CLUSTER", engine_in_c);
|
931
|
+
|
632
932
|
// rb_const_set(IodineEngine, rb_intern("CLUSTER"), e);
|
633
933
|
|
634
934
|
engine_in_c = rb_funcallv(IodineEngine, iodine_new_func_id, 0, NULL);
|
@@ -638,6 +938,7 @@ void Iodine_init_pubsub(void) {
|
|
638
938
|
/** This is a single process pub/sub engine. It will distribute messages to
|
639
939
|
* all subscribers sharing the same process. */
|
640
940
|
rb_define_const(IodinePubSub, "SINGLE_PROCESS", engine_in_c);
|
941
|
+
|
641
942
|
// rb_const_set(IodineEngine, rb_intern("SINGLE_PROCESS"), e);
|
642
943
|
|
643
944
|
engine_in_c =
|