iodine 0.1.21 → 0.2.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/.gitignore +3 -2
- data/.travis.yml +23 -2
- data/CHANGELOG.md +9 -2
- data/README.md +232 -179
- data/Rakefile +13 -1
- data/bin/config.ru +63 -0
- data/bin/console +6 -0
- data/bin/echo +42 -32
- data/bin/http-hello +62 -0
- data/bin/http-playground +124 -0
- data/bin/playground +62 -0
- data/bin/poc/Gemfile.lock +23 -0
- data/bin/poc/README.md +37 -0
- data/bin/poc/config.ru +66 -0
- data/bin/poc/gemfile +1 -0
- data/bin/poc/www/index.html +57 -0
- data/bin/raw-rbhttp +35 -0
- data/bin/raw_broadcast +66 -0
- data/bin/test_with_faye +40 -0
- data/bin/ws-broadcast +108 -0
- data/bin/ws-echo +108 -0
- data/exe/iodine +59 -0
- data/ext/iodine/base64.c +264 -0
- data/ext/iodine/base64.h +72 -0
- data/ext/iodine/bscrypt-common.h +109 -0
- data/ext/iodine/bscrypt.h +49 -0
- data/ext/iodine/extconf.rb +41 -0
- data/ext/iodine/hex.c +123 -0
- data/ext/iodine/hex.h +70 -0
- data/ext/iodine/http.c +200 -0
- data/ext/iodine/http.h +128 -0
- data/ext/iodine/http1.c +402 -0
- data/ext/iodine/http1.h +56 -0
- data/ext/iodine/http1_simple_parser.c +473 -0
- data/ext/iodine/http1_simple_parser.h +59 -0
- data/ext/iodine/http_request.h +128 -0
- data/ext/iodine/http_response.c +1606 -0
- data/ext/iodine/http_response.h +393 -0
- data/ext/iodine/http_response_http1.h +374 -0
- data/ext/iodine/iodine_core.c +641 -0
- data/ext/iodine/iodine_core.h +70 -0
- data/ext/iodine/iodine_http.c +615 -0
- data/ext/iodine/iodine_http.h +19 -0
- data/ext/iodine/iodine_websocket.c +430 -0
- data/ext/iodine/iodine_websocket.h +21 -0
- data/ext/iodine/libasync.c +552 -0
- data/ext/iodine/libasync.h +117 -0
- data/ext/iodine/libreact.c +347 -0
- data/ext/iodine/libreact.h +244 -0
- data/ext/iodine/libserver.c +912 -0
- data/ext/iodine/libserver.h +435 -0
- data/ext/iodine/libsock.c +950 -0
- data/ext/iodine/libsock.h +478 -0
- data/ext/iodine/misc.c +181 -0
- data/ext/iodine/misc.h +76 -0
- data/ext/iodine/random.c +193 -0
- data/ext/iodine/random.h +48 -0
- data/ext/iodine/rb-call.c +127 -0
- data/ext/iodine/rb-call.h +60 -0
- data/ext/iodine/rb-libasync.h +79 -0
- data/ext/iodine/rb-rack-io.c +389 -0
- data/ext/iodine/rb-rack-io.h +17 -0
- data/ext/iodine/rb-registry.c +213 -0
- data/ext/iodine/rb-registry.h +33 -0
- data/ext/iodine/sha1.c +359 -0
- data/ext/iodine/sha1.h +85 -0
- data/ext/iodine/sha2.c +825 -0
- data/ext/iodine/sha2.h +138 -0
- data/ext/iodine/siphash.c +136 -0
- data/ext/iodine/siphash.h +15 -0
- data/ext/iodine/spnlock.h +235 -0
- data/ext/iodine/websockets.c +696 -0
- data/ext/iodine/websockets.h +120 -0
- data/ext/iodine/xor-crypt.c +189 -0
- data/ext/iodine/xor-crypt.h +107 -0
- data/iodine.gemspec +25 -18
- data/lib/iodine.rb +57 -58
- data/lib/iodine/http.rb +0 -189
- data/lib/iodine/protocol.rb +36 -245
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +145 -2
- metadata +115 -37
- data/bin/core_http_test +0 -51
- data/bin/em playground +0 -56
- data/bin/hello_world +0 -75
- data/bin/setup +0 -7
- data/lib/iodine/client.rb +0 -5
- data/lib/iodine/core.rb +0 -102
- data/lib/iodine/core_init.rb +0 -143
- data/lib/iodine/http/hpack.rb +0 -553
- data/lib/iodine/http/http1.rb +0 -251
- data/lib/iodine/http/http2.rb +0 -507
- data/lib/iodine/http/rack_support.rb +0 -108
- data/lib/iodine/http/request.rb +0 -462
- data/lib/iodine/http/response.rb +0 -474
- data/lib/iodine/http/session.rb +0 -143
- data/lib/iodine/http/websocket_client.rb +0 -335
- data/lib/iodine/http/websocket_handler.rb +0 -101
- data/lib/iodine/http/websockets.rb +0 -336
- data/lib/iodine/io.rb +0 -56
- data/lib/iodine/logging.rb +0 -46
- data/lib/iodine/settings.rb +0 -158
- data/lib/iodine/ssl_connector.rb +0 -48
- data/lib/iodine/timers.rb +0 -95
@@ -0,0 +1,19 @@
|
|
1
|
+
#ifndef IODINE_HTTP_H
|
2
|
+
#define IODINE_HTTP_H
|
3
|
+
#include "iodine_core.h"
|
4
|
+
#include "rb-rack-io.h"
|
5
|
+
|
6
|
+
/* the Iodine::Rack HTTP server class*/
|
7
|
+
extern VALUE IodineHttp;
|
8
|
+
/* these three are used also by rb-rack-io.c */
|
9
|
+
extern VALUE R_HIJACK;
|
10
|
+
extern VALUE R_HIJACK_IO;
|
11
|
+
extern VALUE R_HIJACK_CB;
|
12
|
+
|
13
|
+
/* Initializes the HTTP library */
|
14
|
+
void Init_iodine_http(void);
|
15
|
+
|
16
|
+
/* Reviews the HTTP settngs and initiates an HTTP service if required */
|
17
|
+
int iodine_http_review(void);
|
18
|
+
|
19
|
+
#endif
|
@@ -0,0 +1,430 @@
|
|
1
|
+
#include "iodine_core.h"
|
2
|
+
#include "iodine_http.h"
|
3
|
+
#include "iodine_websocket.h"
|
4
|
+
#include "rb-call.h"
|
5
|
+
#include "rb-registry.h"
|
6
|
+
#include <ruby/io.h>
|
7
|
+
#include <arpa/inet.h>
|
8
|
+
|
9
|
+
/* *****************************************************************************
|
10
|
+
Core helpers and data
|
11
|
+
*/
|
12
|
+
|
13
|
+
static VALUE rWebsocket; // The Iodine::Http::Websocket class
|
14
|
+
static VALUE rWebsocketClass; // The Iodine::Http::Websocket class
|
15
|
+
static ID ws_var_id; // id for websocket pointer
|
16
|
+
static ID dup_func_id; // id for the buffer.dup method
|
17
|
+
|
18
|
+
size_t iodine_websocket_max_msg_size = 0;
|
19
|
+
uint8_t iodine_websocket_timeout = 0;
|
20
|
+
|
21
|
+
#define set_uuid(object, request) \
|
22
|
+
rb_ivar_set((object), fd_var_id, ULONG2NUM((request)->metadata.fd))
|
23
|
+
|
24
|
+
inline static intptr_t get_uuid(VALUE obj) {
|
25
|
+
VALUE i = rb_ivar_get(obj, fd_var_id);
|
26
|
+
return i != Qnil ? (intptr_t)FIX2ULONG(i) : 0;
|
27
|
+
}
|
28
|
+
|
29
|
+
#define set_ws(object, ws) \
|
30
|
+
rb_ivar_set((object), ws_var_id, ULONG2NUM(((VALUE)(ws))))
|
31
|
+
|
32
|
+
inline static ws_s *get_ws(VALUE obj) {
|
33
|
+
VALUE i = rb_ivar_get(obj, ws_var_id);
|
34
|
+
return (ws_s *)FIX2ULONG(i);
|
35
|
+
}
|
36
|
+
|
37
|
+
#define set_handler(ws, handler) websocket_set_udata((ws), (VALUE)handler)
|
38
|
+
#define get_handler(ws) ((VALUE)websocket_get_udata((ws_s *)(ws)))
|
39
|
+
|
40
|
+
/*******************************************************************************
|
41
|
+
Buffer management - update to change the way the buffer is handled.
|
42
|
+
*/
|
43
|
+
struct buffer_s {
|
44
|
+
void *data;
|
45
|
+
size_t size;
|
46
|
+
};
|
47
|
+
|
48
|
+
/** returns a buffer_s struct, with a buffer (at least) `size` long. */
|
49
|
+
struct buffer_s create_ws_buffer(ws_s *owner);
|
50
|
+
|
51
|
+
/** returns a buffer_s struct, with a buffer (at least) `size` long. */
|
52
|
+
struct buffer_s resize_ws_buffer(ws_s *owner, struct buffer_s);
|
53
|
+
|
54
|
+
/** releases an existing buffer. */
|
55
|
+
void free_ws_buffer(ws_s *owner, struct buffer_s);
|
56
|
+
|
57
|
+
/** Sets the initial buffer size. (16Kb)*/
|
58
|
+
#define WS_INITIAL_BUFFER_SIZE 16384
|
59
|
+
|
60
|
+
// buffer increments by 4,096 Bytes (4Kb)
|
61
|
+
#define round_up_buffer_size(size) ((((size) >> 12) + 1) << 12)
|
62
|
+
|
63
|
+
struct buffer_args {
|
64
|
+
struct buffer_s buffer;
|
65
|
+
ws_s *ws;
|
66
|
+
};
|
67
|
+
|
68
|
+
void *ruby_land_buffer(void *_buf) {
|
69
|
+
#define args ((struct buffer_args *)(_buf))
|
70
|
+
if (args->buffer.data == NULL) {
|
71
|
+
VALUE rbbuff = rb_str_buf_new(WS_INITIAL_BUFFER_SIZE);
|
72
|
+
rb_ivar_set(get_handler(args->ws), buff_var_id, rbbuff);
|
73
|
+
rb_str_set_len(rbbuff, 0);
|
74
|
+
rb_enc_associate(rbbuff, BinaryEncoding);
|
75
|
+
args->buffer.data = RSTRING_PTR(rbbuff);
|
76
|
+
args->buffer.size = WS_INITIAL_BUFFER_SIZE;
|
77
|
+
|
78
|
+
} else {
|
79
|
+
VALUE rbbuff = rb_ivar_get(get_handler(args->ws), buff_var_id);
|
80
|
+
rb_str_modify(rbbuff);
|
81
|
+
rb_str_resize(rbbuff, args->buffer.size);
|
82
|
+
args->buffer.data = RSTRING_PTR(rbbuff);
|
83
|
+
args->buffer.size = rb_str_capacity(rbbuff);
|
84
|
+
}
|
85
|
+
return NULL;
|
86
|
+
#undef args
|
87
|
+
}
|
88
|
+
|
89
|
+
struct buffer_s create_ws_buffer(ws_s *owner) {
|
90
|
+
struct buffer_args args = {.ws = owner};
|
91
|
+
RubyCaller.call_c(ruby_land_buffer, &args);
|
92
|
+
return args.buffer;
|
93
|
+
}
|
94
|
+
|
95
|
+
struct buffer_s resize_ws_buffer(ws_s *owner, struct buffer_s buffer) {
|
96
|
+
buffer.size = round_up_buffer_size(buffer.size);
|
97
|
+
struct buffer_args args = {.ws = owner, .buffer = buffer};
|
98
|
+
RubyCaller.call_c(ruby_land_buffer, &args);
|
99
|
+
return args.buffer;
|
100
|
+
}
|
101
|
+
void free_ws_buffer(ws_s *owner, struct buffer_s buff) {}
|
102
|
+
|
103
|
+
#undef round_up_buffer_size
|
104
|
+
|
105
|
+
/* *****************************************************************************
|
106
|
+
Websocket Ruby API
|
107
|
+
*/
|
108
|
+
|
109
|
+
/** Closes the websocket connection. The connection is only closed after
|
110
|
+
* existing data in the outgoing buffer is sent. */
|
111
|
+
static VALUE iodine_ws_close(VALUE self) {
|
112
|
+
ws_s *ws = get_ws(self);
|
113
|
+
if (((protocol_s *)ws)->service != WEBSOCKET_ID_STR)
|
114
|
+
return Qfalse;
|
115
|
+
websocket_close(ws);
|
116
|
+
return self;
|
117
|
+
}
|
118
|
+
|
119
|
+
/** Writes data to the websocket. Returns `self` (the websocket object). */
|
120
|
+
static VALUE iodine_ws_write(VALUE self, VALUE data) {
|
121
|
+
ws_s *ws = get_ws(self);
|
122
|
+
if (((protocol_s *)ws)->service != WEBSOCKET_ID_STR)
|
123
|
+
return Qfalse;
|
124
|
+
websocket_write(ws, RSTRING_PTR(data), RSTRING_LEN(data),
|
125
|
+
rb_enc_get(data) == UTF8Encoding);
|
126
|
+
return self;
|
127
|
+
}
|
128
|
+
|
129
|
+
/** Returns the number of active websocket connections (including connections
|
130
|
+
* that are in the process of closing down). */
|
131
|
+
static VALUE iodine_ws_count(VALUE self) {
|
132
|
+
ws_s *ws = get_ws(self);
|
133
|
+
return LONG2FIX(websocket_count(ws));
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
Returns a connection's UUID which is valid for **this process** (not a machine
|
138
|
+
or internet unique value).
|
139
|
+
|
140
|
+
This can be used together with a true process wide UUID to uniquely identify a
|
141
|
+
connection across the internet.
|
142
|
+
*/
|
143
|
+
static VALUE iodine_ws_uuid(VALUE self) {
|
144
|
+
intptr_t uuid = get_uuid(self);
|
145
|
+
return LONG2FIX(uuid);
|
146
|
+
}
|
147
|
+
|
148
|
+
/* *****************************************************************************
|
149
|
+
Websocket defer
|
150
|
+
*/
|
151
|
+
|
152
|
+
static void iodine_perform_defer(intptr_t uuid, protocol_s *protocol,
|
153
|
+
void *arg) {
|
154
|
+
VALUE obj = protocol->service == WEBSOCKET_ID_STR
|
155
|
+
? get_handler(protocol)
|
156
|
+
: dyn_prot(protocol)->handler;
|
157
|
+
RubyCaller.call2((VALUE)arg, call_proc_id, 1, &obj);
|
158
|
+
Registry.remove((VALUE)arg);
|
159
|
+
}
|
160
|
+
static void iodine_defer_fallback(intptr_t uuid, void *arg) {
|
161
|
+
Registry.remove((VALUE)arg);
|
162
|
+
};
|
163
|
+
|
164
|
+
/**
|
165
|
+
Schedules a block of code to execute at a later time, **if** the connection is
|
166
|
+
still
|
167
|
+
open and while preventing concurent code from running for the same connection
|
168
|
+
object.
|
169
|
+
|
170
|
+
An optional `uuid` argument can be passed along, so that the block of code will
|
171
|
+
run for the requested connection rather then this connection.
|
172
|
+
|
173
|
+
**Careful**: as this might cause this connection's object to run code
|
174
|
+
concurrently when data owned by this connection is accessed from within the
|
175
|
+
block of code.
|
176
|
+
|
177
|
+
On success returns the block, otherwise (connection invalid) returns `false`. A
|
178
|
+
sucessful event registration doesn't guaranty that the block will be called (the
|
179
|
+
connection might close between the event registration and the execution).
|
180
|
+
*/
|
181
|
+
static VALUE iodine_defer(int argc, VALUE *argv, VALUE self) {
|
182
|
+
intptr_t fd;
|
183
|
+
// check arguments.
|
184
|
+
if (argc > 1)
|
185
|
+
rb_raise(rb_eArgError, "this function expects no more then 1 (optional) "
|
186
|
+
"argument.");
|
187
|
+
else if (argc == 1) {
|
188
|
+
Check_Type(*argv, T_FIXNUM);
|
189
|
+
fd = FIX2LONG(*argv);
|
190
|
+
if (!sock_isvalid(fd))
|
191
|
+
return Qfalse;
|
192
|
+
} else
|
193
|
+
fd = iodine_get_fd(self);
|
194
|
+
// requires a block to be passed
|
195
|
+
rb_need_block();
|
196
|
+
VALUE block = rb_block_proc();
|
197
|
+
if (block == Qnil)
|
198
|
+
return Qfalse;
|
199
|
+
Registry.add(block);
|
200
|
+
|
201
|
+
server_task(fd, iodine_perform_defer, (void *)block, iodine_defer_fallback);
|
202
|
+
return block;
|
203
|
+
}
|
204
|
+
|
205
|
+
/* *****************************************************************************
|
206
|
+
Websocket task performance
|
207
|
+
*/
|
208
|
+
|
209
|
+
static void iodine_ws_perform_each_task(intptr_t fd, protocol_s *protocol,
|
210
|
+
void *data) {
|
211
|
+
VALUE handler = get_handler(protocol);
|
212
|
+
if (handler)
|
213
|
+
RubyCaller.call2((VALUE)data, call_proc_id, 1, &handler);
|
214
|
+
}
|
215
|
+
static void iodine_ws_finish_each_task(intptr_t fd, protocol_s *protocol,
|
216
|
+
void *data) {
|
217
|
+
Registry.remove((VALUE)data);
|
218
|
+
}
|
219
|
+
|
220
|
+
inline static void iodine_ws_run_each(intptr_t origin, VALUE block) {
|
221
|
+
server_each(origin, WEBSOCKET_ID_STR, iodine_ws_perform_each_task,
|
222
|
+
(void *)block, iodine_ws_finish_each_task);
|
223
|
+
}
|
224
|
+
|
225
|
+
/** Performs a block of code for each websocket connection. The function returns
|
226
|
+
the block of code.
|
227
|
+
|
228
|
+
The block of code should accept a single variable which is the websocket
|
229
|
+
connection.
|
230
|
+
|
231
|
+
i.e.:
|
232
|
+
|
233
|
+
def on_message data
|
234
|
+
msg = data.dup; # data will be overwritten once the function exists.
|
235
|
+
each {|ws| ws.write msg}
|
236
|
+
end
|
237
|
+
*/
|
238
|
+
static VALUE iodine_ws_each(VALUE self) {
|
239
|
+
// requires a block to be passed
|
240
|
+
rb_need_block();
|
241
|
+
VALUE block = rb_block_proc();
|
242
|
+
if (block == Qnil)
|
243
|
+
return Qnil;
|
244
|
+
Registry.add(block);
|
245
|
+
intptr_t fd = get_uuid(self);
|
246
|
+
iodine_ws_run_each(fd, block);
|
247
|
+
return block;
|
248
|
+
}
|
249
|
+
|
250
|
+
/**
|
251
|
+
Runs the required block for each dynamic protocol connection.
|
252
|
+
|
253
|
+
Tasks will be performed within each connections lock, so no connection will have
|
254
|
+
more then one task being performed at the same time (similar to {#defer}).
|
255
|
+
|
256
|
+
Also, unlike {Iodine.run}, the block will **not** be called unless the
|
257
|
+
connection remains open at the time it's execution is scheduled.
|
258
|
+
|
259
|
+
Always returns `self`.
|
260
|
+
*/
|
261
|
+
static VALUE iodine_ws_class_each(VALUE self) {
|
262
|
+
// requires a block to be passed
|
263
|
+
rb_need_block();
|
264
|
+
VALUE block = rb_block_proc();
|
265
|
+
if (block == Qnil)
|
266
|
+
return Qfalse;
|
267
|
+
Registry.add(block);
|
268
|
+
iodine_ws_run_each(-1, block);
|
269
|
+
return self;
|
270
|
+
}
|
271
|
+
|
272
|
+
/**
|
273
|
+
Schedules a block of code to run for the specified connection at a later time,
|
274
|
+
(**if** the connection is open) and while preventing concurent code from running
|
275
|
+
for the same connection object.
|
276
|
+
|
277
|
+
The block of code will receive the connection's object. i.e.
|
278
|
+
|
279
|
+
Iodine::Websocket.defer(uuid) {|ws| ws.write "I'm doing this" }
|
280
|
+
|
281
|
+
On success returns the block, otherwise (connection invalid) returns `false`. A
|
282
|
+
sucessful event registration doesn't guaranty that the block will be called (the
|
283
|
+
connection might close between the event registration and the execution).
|
284
|
+
*/
|
285
|
+
static VALUE iodine_class_defer(VALUE self, VALUE ws_uuid) {
|
286
|
+
intptr_t fd = FIX2LONG(ws_uuid);
|
287
|
+
if (!sock_isvalid(fd))
|
288
|
+
return Qfalse;
|
289
|
+
// requires a block to be passed
|
290
|
+
rb_need_block();
|
291
|
+
VALUE block = rb_block_proc();
|
292
|
+
if (block == Qnil)
|
293
|
+
return Qfalse;
|
294
|
+
Registry.add(block);
|
295
|
+
|
296
|
+
server_task(fd, iodine_perform_defer, (void *)block, iodine_defer_fallback);
|
297
|
+
return block;
|
298
|
+
}
|
299
|
+
|
300
|
+
//////////////////////////////////////
|
301
|
+
// Protocol functions
|
302
|
+
void ws_on_open(ws_s *ws) {
|
303
|
+
VALUE handler = get_handler(ws);
|
304
|
+
if (!handler)
|
305
|
+
return;
|
306
|
+
set_ws(handler, ws);
|
307
|
+
RubyCaller.call(handler, on_open_func_id);
|
308
|
+
}
|
309
|
+
void ws_on_close(ws_s *ws) {
|
310
|
+
VALUE handler = get_handler(ws);
|
311
|
+
if (!handler)
|
312
|
+
return;
|
313
|
+
RubyCaller.call(handler, on_close_func_id);
|
314
|
+
Registry.remove(handler);
|
315
|
+
}
|
316
|
+
void ws_on_shutdown(ws_s *ws) {
|
317
|
+
VALUE handler = get_handler(ws);
|
318
|
+
if (!handler)
|
319
|
+
return;
|
320
|
+
RubyCaller.call(handler, on_shutdown_func_id);
|
321
|
+
}
|
322
|
+
void ws_on_data(ws_s *ws, char *data, size_t length, uint8_t is_text) {
|
323
|
+
VALUE handler = get_handler(ws);
|
324
|
+
if (!handler)
|
325
|
+
return;
|
326
|
+
VALUE buffer = rb_ivar_get(handler, buff_var_id);
|
327
|
+
if (is_text)
|
328
|
+
rb_enc_associate(buffer, UTF8Encoding);
|
329
|
+
else
|
330
|
+
rb_enc_associate(buffer, BinaryEncoding);
|
331
|
+
rb_str_set_len(buffer, length);
|
332
|
+
RubyCaller.call2(handler, on_message_func_id, 1, &buffer);
|
333
|
+
}
|
334
|
+
|
335
|
+
//////////////////////////////////////
|
336
|
+
// Protocol constructor
|
337
|
+
|
338
|
+
void iodine_websocket_upgrade(http_request_s *request,
|
339
|
+
http_response_s *response, VALUE handler) {
|
340
|
+
// make sure we have a valid handler, with the Websocket Protocol mixin.
|
341
|
+
if (handler == Qnil || handler == Qfalse) {
|
342
|
+
response->status = 400;
|
343
|
+
http_response_finish(response);
|
344
|
+
return;
|
345
|
+
}
|
346
|
+
if (TYPE(handler) == T_CLASS) {
|
347
|
+
// include the Protocol module
|
348
|
+
rb_include_module(handler, rWebsocket);
|
349
|
+
rb_extend_object(handler, rWebsocketClass);
|
350
|
+
handler = RubyCaller.call(handler, new_func_id);
|
351
|
+
// check that we created a handler
|
352
|
+
} else {
|
353
|
+
// include the Protocol module in the object's class
|
354
|
+
VALUE p_class = rb_obj_class(handler);
|
355
|
+
rb_include_module(p_class, rWebsocket);
|
356
|
+
rb_extend_object(p_class, rWebsocketClass);
|
357
|
+
}
|
358
|
+
// add the handler to the registry
|
359
|
+
Registry.add(handler);
|
360
|
+
// set the UUID for the connection
|
361
|
+
set_uuid(handler, request);
|
362
|
+
// send upgrade response and set new protocol
|
363
|
+
websocket_upgrade(.request = request, .response = response,
|
364
|
+
.udata = (void *)handler, .on_close = ws_on_close,
|
365
|
+
.on_open = ws_on_open, .on_shutdown = ws_on_shutdown,
|
366
|
+
.on_message = ws_on_data,
|
367
|
+
.max_msg_size = iodine_websocket_max_msg_size,
|
368
|
+
.timeout = iodine_websocket_timeout);
|
369
|
+
}
|
370
|
+
|
371
|
+
//////////////
|
372
|
+
// Empty callbacks for default implementations.
|
373
|
+
|
374
|
+
/** Please implement your own callback for this event.
|
375
|
+
*/
|
376
|
+
static VALUE empty_func(VALUE self) { return Qnil; }
|
377
|
+
// /* The `on_message(data)` callback is the main method for any websocket
|
378
|
+
// implementation. It is the only required callback for a websocket handler
|
379
|
+
// (without this handler, errors will occur).
|
380
|
+
//
|
381
|
+
// <b>NOTICE</b>: the data passed to the `on_message` callback is the actual
|
382
|
+
// recycble network buffer, not a copy! <b>Use `data.dup` before moving the data
|
383
|
+
// out of the function's scope</b> to prevent data corruption (i.e. when
|
384
|
+
// using the data within an `each` block). For example (broadcasting):
|
385
|
+
//
|
386
|
+
// def on_message data
|
387
|
+
// msg = data.dup; # data will be overwritten once the function exists.
|
388
|
+
// each {|ws| ws.write msg}
|
389
|
+
// end
|
390
|
+
//
|
391
|
+
// Please override this method and implement your own callback.
|
392
|
+
// */
|
393
|
+
// static VALUE def_dyn_message(VALUE self, VALUE data) {
|
394
|
+
// fprintf(stderr,
|
395
|
+
// "WARNING: websocket handler on_message override missing or "
|
396
|
+
// "bypassed.\n");
|
397
|
+
// return Qnil;
|
398
|
+
// }
|
399
|
+
|
400
|
+
/////////////////////////////
|
401
|
+
// initialize the class and the whole of the Iodine/http library
|
402
|
+
void Init_iodine_websocket(void) {
|
403
|
+
// get IDs and data that's used often
|
404
|
+
ws_var_id = rb_intern("ws_ptr"); // when upgrading
|
405
|
+
dup_func_id = rb_intern("dup"); // when upgrading
|
406
|
+
|
407
|
+
// the Ruby websockets protocol class.
|
408
|
+
rWebsocket = rb_define_module_under(Iodine, "Websocket");
|
409
|
+
if (rWebsocket == Qfalse)
|
410
|
+
fprintf(stderr, "WTF?!\n"), exit(-1);
|
411
|
+
// // callbacks and handlers
|
412
|
+
rb_define_method(rWebsocket, "on_open", empty_func, 0);
|
413
|
+
// rb_define_method(rWebsocket, "on_message", def_dyn_message, 1);
|
414
|
+
rb_define_method(rWebsocket, "on_shutdown", empty_func, 0);
|
415
|
+
rb_define_method(rWebsocket, "on_close", empty_func, 0);
|
416
|
+
rb_define_method(rWebsocket, "write", iodine_ws_write, 1);
|
417
|
+
rb_define_method(rWebsocket, "close", iodine_ws_close, 0);
|
418
|
+
|
419
|
+
rb_define_method(rWebsocket, "uuid", iodine_ws_uuid, 0);
|
420
|
+
rb_define_method(rWebsocket, "defer", iodine_defer, -1);
|
421
|
+
rb_define_method(rWebsocket, "each", iodine_ws_each, 0);
|
422
|
+
rb_define_method(rWebsocket, "count", iodine_ws_count, 0);
|
423
|
+
|
424
|
+
rb_define_singleton_method(rWebsocket, "each", iodine_ws_class_each, 0);
|
425
|
+
rb_define_singleton_method(rWebsocket, "defer", iodine_class_defer, 1);
|
426
|
+
|
427
|
+
rWebsocketClass = rb_define_module_under(IodineBase, "WebsocketClass");
|
428
|
+
rb_define_method(rWebsocketClass, "each", iodine_ws_class_each, 0);
|
429
|
+
rb_define_method(rWebsocketClass, "defer", iodine_class_defer, 1);
|
430
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
/*
|
2
|
+
copyright: Boaz segev, 2016
|
3
|
+
license: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
7
|
+
#ifndef IODINE_WEBSOCKETS_H
|
8
|
+
#define IODINE_WEBSOCKETS_H
|
9
|
+
|
10
|
+
#include <ruby.h>
|
11
|
+
#include "websockets.h"
|
12
|
+
|
13
|
+
void Init_iodine_websocket(void);
|
14
|
+
|
15
|
+
void iodine_websocket_upgrade(http_request_s *request,
|
16
|
+
http_response_s *response, VALUE handler);
|
17
|
+
|
18
|
+
extern size_t iodine_websocket_max_msg_size;
|
19
|
+
extern uint8_t iodine_websocket_timeout;
|
20
|
+
|
21
|
+
#endif /* IODINE_WEBSOCKETS_H */
|