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/websockets.h
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
/*
|
2
|
-
copyright: Boaz
|
2
|
+
copyright: Boaz Segev, 2016-2018
|
3
3
|
license: MIT
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
7
|
-
#ifndef
|
8
|
-
#define
|
7
|
+
#ifndef H_WEBSOCKETS_H
|
8
|
+
#define H_WEBSOCKETS_H
|
9
9
|
|
10
10
|
#include "http.h"
|
11
11
|
|
@@ -14,109 +14,14 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
14
14
|
extern "C" {
|
15
15
|
#endif
|
16
16
|
|
17
|
-
/* *****************************************************************************
|
18
|
-
Upgrading from HTTP to Websockets
|
19
|
-
***************************************************************************** */
|
20
|
-
|
21
|
-
/**
|
22
|
-
The Websocket type is an opaque type used by the websocket API to provide
|
23
|
-
identify a specific Websocket connection and manage it's internal state.
|
24
|
-
*/
|
25
|
-
typedef struct Websocket ws_s;
|
26
|
-
|
27
17
|
/**
|
28
|
-
The protocol / service identifier
|
18
|
+
The protocol / service identifier.
|
29
19
|
*/
|
30
20
|
extern char *WEBSOCKET_ID_STR;
|
31
|
-
/**
|
32
|
-
The Websocket Handler contains all the settings required for new websocket
|
33
|
-
connections.
|
34
21
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
typedef struct {
|
39
|
-
/**
|
40
|
-
The (optional) on_message callback will be called whenever a websocket message
|
41
|
-
is
|
42
|
-
received for this connection.
|
43
|
-
|
44
|
-
The data received points to the websocket's message buffer and it will be
|
45
|
-
overwritten once the function exits (it cannot be saved for later, but it can
|
46
|
-
be copied).
|
47
|
-
*/
|
48
|
-
void (*on_message)(ws_s *ws, char *data, size_t size, uint8_t is_text);
|
49
|
-
/**
|
50
|
-
The (optional) on_open callback will be called once the websocket connection
|
51
|
-
is established and before is is registered with `facil`, so no `on_message`
|
52
|
-
events are raised before `on_open` returns.
|
53
|
-
*/
|
54
|
-
void (*on_open)(ws_s *ws);
|
55
|
-
/**
|
56
|
-
The (optional) on_ready callback will be after a the underlying socket's
|
57
|
-
buffer changes it's state from full to available.
|
58
|
-
|
59
|
-
If the socket's buffer is never full, the callback is never called.
|
60
|
-
|
61
|
-
It should be noted that `libsock` manages the socket's buffer overflow and
|
62
|
-
implements and augmenting user-land buffer, allowing data to be safely written
|
63
|
-
to the websocket without worrying over the socket's buffer.
|
64
|
-
*/
|
65
|
-
void (*on_ready)(ws_s *ws);
|
66
|
-
/**
|
67
|
-
The (optional) on_shutdown callback will be called if a websocket connection
|
68
|
-
is still open while the server is shutting down (called before `on_close`).
|
69
|
-
*/
|
70
|
-
void (*on_shutdown)(ws_s *ws);
|
71
|
-
/**
|
72
|
-
The (optional) on_close callback will be called once a websocket connection is
|
73
|
-
terminated or failed to be established.
|
74
|
-
*/
|
75
|
-
void (*on_close)(ws_s *ws);
|
76
|
-
/** The `http_request_s` to be converted ("upgraded") to a websocket
|
77
|
-
* connection. Either a request or a response object is required.*/
|
78
|
-
http_request_s *request;
|
79
|
-
/**
|
80
|
-
The (optional) HttpResponse to be used for sending the upgrade response.
|
81
|
-
|
82
|
-
Using this object allows cookies to be set before "upgrading" the connection.
|
83
|
-
|
84
|
-
The ownership of the response object will remain unchanged - so if you have
|
85
|
-
created the response object, you should free it.
|
86
|
-
*/
|
87
|
-
http_response_s *response;
|
88
|
-
/**
|
89
|
-
The maximum websocket message size/buffer (in bytes) for this connection.
|
90
|
-
*/
|
91
|
-
size_t max_msg_size;
|
92
|
-
/** Opaque user data. */
|
93
|
-
void *udata;
|
94
|
-
/**
|
95
|
-
Timeout for the websocket connections, a ping will be sent
|
96
|
-
whenever the timeout is reached. Connections are only closed when a ping
|
97
|
-
cannot be sent (the network layer fails). Pongs aren't reviewed.
|
98
|
-
*/
|
99
|
-
uint8_t timeout;
|
100
|
-
} websocket_settings_s;
|
101
|
-
|
102
|
-
/** This macro allows easy access to the `websocket_upgrade` function. The macro
|
103
|
-
* allows the use of named arguments, using the `websocket_settings_s` struct
|
104
|
-
* members. i.e.:
|
105
|
-
*
|
106
|
-
* on_message(ws_s * ws, char * data, size_t size, int is_text) {
|
107
|
-
* ; // ... this is the websocket on_message callback
|
108
|
-
* websocket_write(ws, data, size, is_text); // a simple echo example
|
109
|
-
* }
|
110
|
-
*
|
111
|
-
* on_request(http_request_s* request) {
|
112
|
-
* websocket_upgrade( .request = request, .on_message = on_message);
|
113
|
-
* }
|
114
|
-
*
|
115
|
-
* Returns 0 on sucess and -1 on failure. A response is always sent.
|
116
|
-
*/
|
117
|
-
ssize_t websocket_upgrade(websocket_settings_s settings);
|
118
|
-
#define websocket_upgrade(...) \
|
119
|
-
websocket_upgrade((websocket_settings_s){__VA_ARGS__})
|
22
|
+
/** used internally: attaches the Websocket protocol to the socket. */
|
23
|
+
void websocket_attach(intptr_t uuid, http_settings_s *http_settings,
|
24
|
+
websocket_settings_s *args, void *data, size_t length);
|
120
25
|
|
121
26
|
/* *****************************************************************************
|
122
27
|
Websocket information
|
@@ -177,22 +82,12 @@ typedef struct pubsub_engine_s pubsub_engine_s;
|
|
177
82
|
typedef struct {
|
178
83
|
/** the websocket receiving the message. */
|
179
84
|
ws_s *ws;
|
180
|
-
/** the pub/sub engine from which where the message originated. */
|
181
|
-
struct pubsub_engine_s *engine;
|
182
85
|
/** the Websocket pub/sub subscription ID. */
|
183
86
|
uintptr_t subscription_id;
|
184
87
|
/** the channel where the message was published. */
|
185
|
-
|
186
|
-
const char *name;
|
187
|
-
size_t len;
|
188
|
-
} channel;
|
88
|
+
FIOBJ channel;
|
189
89
|
/** the published message. */
|
190
|
-
|
191
|
-
const char *data;
|
192
|
-
size_t len;
|
193
|
-
} msg;
|
194
|
-
/** Pattern matching was used for channel subscription. */
|
195
|
-
unsigned use_pattern : 1;
|
90
|
+
FIOBJ message;
|
196
91
|
/** user opaque data. */
|
197
92
|
void *udata;
|
198
93
|
} websocket_pubsub_notification_s;
|
@@ -201,17 +96,8 @@ typedef struct {
|
|
201
96
|
struct websocket_subscribe_s {
|
202
97
|
/** the websocket receiving the message. REQUIRED. */
|
203
98
|
ws_s *ws;
|
204
|
-
/**
|
205
|
-
* The pub/sub engine to use.
|
206
|
-
*
|
207
|
-
* Default: engine will publish messages throughout the facil process cluster.
|
208
|
-
*/
|
209
|
-
struct pubsub_engine_s *engine;
|
210
99
|
/** the channel where the message was published. */
|
211
|
-
|
212
|
-
const char *name;
|
213
|
-
size_t len;
|
214
|
-
} channel;
|
100
|
+
FIOBJ channel;
|
215
101
|
/**
|
216
102
|
* The callback that handles pub/sub notifications.
|
217
103
|
*
|
@@ -288,8 +174,7 @@ void websocket_unsubscribe(ws_s *ws, uintptr_t subscription_id);
|
|
288
174
|
|
289
175
|
/* *****************************************************************************
|
290
176
|
Websocket Tasks - within a single process scope, NOT and entire cluster
|
291
|
-
*****************************************************************************
|
292
|
-
*/
|
177
|
+
***************************************************************************** */
|
293
178
|
|
294
179
|
/** The named arguments for `websocket_each` */
|
295
180
|
struct websocket_each_args_s {
|
@@ -303,17 +188,22 @@ struct websocket_each_args_s {
|
|
303
188
|
void (*on_finish)(ws_s *origin, void *arg);
|
304
189
|
};
|
305
190
|
/**
|
306
|
-
|
307
|
-
|
191
|
+
* DEPRECATION NOTICE: this function will be removed in favor of pub/sub logic.
|
192
|
+
*
|
193
|
+
* Performs a task on each websocket connection that shares the same process
|
194
|
+
* (except the originating `ws_s` connection which is allowed to be NULL).
|
308
195
|
*/
|
309
|
-
void
|
196
|
+
void __attribute__((deprecated))
|
197
|
+
websocket_each(struct websocket_each_args_s args);
|
310
198
|
#define websocket_each(...) \
|
311
199
|
websocket_each((struct websocket_each_args_s){__VA_ARGS__})
|
312
200
|
|
313
201
|
/**
|
314
|
-
|
315
|
-
|
316
|
-
|
202
|
+
* DEPRECATION NOTICE: this function will be removed in favor of pub/sub logic.
|
203
|
+
*
|
204
|
+
* The Arguments passed to the `websocket_write_each` function / macro are
|
205
|
+
* defined here, for convinience of calling the function.
|
206
|
+
*/
|
317
207
|
struct websocket_write_each_args_s {
|
318
208
|
/** The originating websocket client will be excluded from the `write`.
|
319
209
|
* Can be NULL. */
|
@@ -343,7 +233,8 @@ Writes data to each websocket connection that shares the same process
|
|
343
233
|
Accepts a sing `struct websocket_write_each_args_s` argument. See the struct
|
344
234
|
details for possible arguments.
|
345
235
|
*/
|
346
|
-
int
|
236
|
+
int __attribute__((deprecated))
|
237
|
+
websocket_write_each(struct websocket_write_each_args_s args);
|
347
238
|
#define websocket_write_each(...) \
|
348
239
|
websocket_write_each((struct websocket_write_each_args_s){__VA_ARGS__})
|
349
240
|
|
data/lib/iodine.rb
CHANGED
@@ -59,8 +59,6 @@ require 'iodine/iodine'
|
|
59
59
|
# * {Iodine.listen2http} listens to new TCP/IP connections using the buildin HTTP / Websocket Protocol.
|
60
60
|
# * {Iodine.warmup} warms up any HTTP Rack applications.
|
61
61
|
# * {Iodine.count} counts the number of connections (including HTTP / Websocket connections).
|
62
|
-
# * {Iodine::Protocol.each} runs a code of block for every connection sharing the process (except HTTP / Websocket connections).
|
63
|
-
# * {Iodine::Websocket.each} runs a code of block for every existing websocket sharing the process.
|
64
62
|
#
|
65
63
|
# In addition to the top level API, there's also the connection class and connection instance API, as specified in the {Iodine::Protocol} and {Iodine::Websocket} documentation.
|
66
64
|
#
|
@@ -70,12 +68,14 @@ require 'iodine/iodine'
|
|
70
68
|
#
|
71
69
|
# The following methods offect server side Pub/Sub that allows the server code to react to channel event.
|
72
70
|
#
|
73
|
-
# * {Iodine.subscribe}
|
74
|
-
# * {Iodine.publish} publishes a message to a Pub/Sub channel. The message will be sent to all subscribers - connections, other processes in the cluster and
|
75
|
-
# * {Iodine.
|
71
|
+
# * {Iodine.subscribe} subscribes the process to a channel (which might be different than a connection's subscription, see {Iodine::Websocket}).
|
72
|
+
# * {Iodine.publish} publishes a message to a Pub/Sub channel. The message will be sent to all subscribers - connections, other processes in the cluster and possibly other machines (when using an engine such as {Iodine::PubSub::RedisEngine}).
|
73
|
+
# * {Iodine::PubSub.default_engine=}, {Iodine::PubSub.default_engine} sets or gets the default Pub/Sub {Iodine::PubSub::Engine}. i.e., when set to a new {Iodine::PubSub::RedisEngine} instance, all Pub/Sub method calls will use the Redis engine (unless explicitly requiring a different engine).
|
76
74
|
#
|
77
75
|
# {Iodine::Websocket} objects have a seperate Pub/Sub implementation that manages the subscription's lifetime to match the connection's lifetime and allows direct client Pub/Sub (forwards the message to the client directly without invoking the Ruby interpreter).
|
78
76
|
#
|
77
|
+
# Note that {Iodine.subscribe} returns an {Iodine::PubSub::Subscription} object that can be used for closing the subscription.
|
78
|
+
#
|
79
79
|
# == Patching Rack
|
80
80
|
#
|
81
81
|
# Although Iodine offers Rack::Utils optimizations using monkey patching, Iodine does NOT monkey patch Rack automatically.
|
@@ -170,7 +170,8 @@ module Iodine
|
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
173
|
-
|
173
|
+
# Will monkey patch some Rack methods to increase their performance.
|
174
|
+
def self.patch_rack
|
174
175
|
::Rack::Utils.class_eval do
|
175
176
|
Iodine::Base::MonkeyPatch::RackUtils.methods(false).each do |m|
|
176
177
|
::Rack::Utils.define_singleton_method(m,
|
@@ -179,7 +180,51 @@ module Iodine
|
|
179
180
|
end
|
180
181
|
end
|
181
182
|
|
182
|
-
|
183
|
+
# Will monkey patch the default JSON parser to replace the default `JSON.parse` with {Iodine::JSON.parse}.
|
184
|
+
def self.patch_json
|
185
|
+
::JSON.class_eval do
|
186
|
+
::JSON.define_singleton_method(:parse,
|
187
|
+
Iodine::JSON.instance_method(:parse) )
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
@after_fork_blocks = []
|
193
|
+
def self.after_fork(*args, &block)
|
194
|
+
if(block)
|
195
|
+
@after_fork_blocks << [args, block]
|
196
|
+
else
|
197
|
+
@after_fork_blocks.each {|b| b[1].call(b[0]) }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
@before_fork_blocks = []
|
202
|
+
def self.before_fork(*args, &block)
|
203
|
+
if(block)
|
204
|
+
@before_fork_blocks << [args, block]
|
205
|
+
else
|
206
|
+
@before_fork_blocks.each {|b| b[1].call(b[0]) }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
::Iodine::PubSub.default_engine = ::Iodine::PubSub::CLUSTER
|
183
211
|
end
|
184
212
|
|
213
|
+
if(!defined?(after_fork))
|
214
|
+
def after_fork(*args, &block)
|
215
|
+
Iodine.after_fork(*args, &block)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
if(!defined?(on_worker_boot))
|
219
|
+
def on_worker_boot(*args, &block)
|
220
|
+
Iodine.after_fork(*args, &block)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
if(!defined?(before_fork))
|
224
|
+
def before_fork(*args, &block)
|
225
|
+
Iodine.before_fork(*args, &block)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
|
185
230
|
require 'rack/handler/iodine' unless defined? ::Iodine::Rack::IODINE_RACK_LOADED
|
data/lib/iodine/cli.rb
CHANGED
@@ -19,15 +19,17 @@ Use:
|
|
19
19
|
Both <options> and <filename> are optional.
|
20
20
|
|
21
21
|
Available options:
|
22
|
+
-b Binding address. Default: nil (same as 0.0.0.0).
|
22
23
|
-p Port number. Default: 3000.
|
23
24
|
-t Number of threads. Default: CPU core count.
|
24
25
|
-w Number of worker processes. Default: CPU core count.
|
25
26
|
-www Public folder for static file serving. Default: nil (none).
|
26
27
|
-v Log responses. Default: never log responses.
|
27
28
|
-warmup Warmup invokes autoloading (lazy loading) during server startup.
|
28
|
-
-tout HTTP inactivity connection timeout. Default:
|
29
|
-
-
|
30
|
-
-
|
29
|
+
-tout HTTP inactivity connection timeout. Default: 40 seconds.
|
30
|
+
-maxhead Maximum total headers length per HTTP request. Default: 32Kb.
|
31
|
+
-maxbd Maximum Mb per HTTP message (max body size). Default: 50Mb.
|
32
|
+
-maxms Maximum Bytes per Websocket message. Default: 250Kb.
|
31
33
|
-ping Websocket ping interval in seconds. Default: 40 seconds.
|
32
34
|
<filename> Defaults to: config.ru
|
33
35
|
|
@@ -48,15 +50,13 @@ EOS
|
|
48
50
|
return ::Rack::Builder.parse_file filename
|
49
51
|
end
|
50
52
|
|
51
|
-
|
52
|
-
|
53
53
|
def call
|
54
54
|
if ARGV[0] =~ /(\-\?)|(help)|(\?)|(h)|(\-h)$/
|
55
55
|
return print_help
|
56
56
|
end
|
57
57
|
|
58
58
|
app, opt = nil, nil
|
59
|
-
filename = ((ARGV[-2].to_s[0] != '-' || ARGV[-2].to_s == '-warmup') && ARGV[-1].to_s[0] != '-' && ARGV[-1])
|
59
|
+
filename = ((ARGV[-2].to_s[0] != '-' || ARGV[-2].to_s == '-warmup' || ARGV[-2].to_s == '-v' || ARGV[-2].to_s == '-q') && ARGV[-1].to_s[0] != '-' && ARGV[-1])
|
60
60
|
if filename
|
61
61
|
app, opt = try_file filename;
|
62
62
|
unless opt
|
@@ -79,24 +79,6 @@ EOS
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
if ARGV.index('-maxbd') && ARGV[ARGV.index('-maxbd') + 1]
|
83
|
-
Iodine::Rack.max_body_size = ARGV[ARGV.index('-maxbd') + 1].to_i
|
84
|
-
end
|
85
|
-
if ARGV.index('-maxms') && ARGV[ARGV.index('-maxms') + 1]
|
86
|
-
Iodine::Rack.max_msg_size = ARGV[ARGV.index('-maxms') + 1].to_i
|
87
|
-
end
|
88
|
-
if ARGV.index('-ping') && ARGV[ARGV.index('-ping') + 1]
|
89
|
-
Iodine::Rack.ws_timeout = ARGV[ARGV.index('-ping') + 1].to_i
|
90
|
-
end
|
91
|
-
if ARGV.index('-www') && ARGV[ARGV.index('-www') + 1]
|
92
|
-
Iodine::Rack.public = ARGV[ARGV.index('-www') + 1]
|
93
|
-
end
|
94
|
-
if ARGV.index('-tout') && ARGV[ARGV.index('-tout') + 1]
|
95
|
-
Iodine::Rack.timeout = ARGV[ARGV.index('-tout') + 1].to_i
|
96
|
-
puts "WARNNING: Iodine::Rack.timeout set to 0 (ignored, timeout will be ~5 seconds)."
|
97
|
-
end
|
98
|
-
Iodine::Rack.log = true if ARGV.index('-v')
|
99
|
-
Iodine::Rack.log = false if ARGV.index('-q')
|
100
82
|
Iodine.warmup(app) if ARGV.index('-warmup')
|
101
83
|
Iodine::Rack.run(app, opt)
|
102
84
|
end
|
data/lib/iodine/json.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Iodine
|
2
|
+
# Iodine includes a lenient JSON parser that attempts to ignore JSON errors when possible and adds some extensions such as Hex numerical representations and comments.
|
3
|
+
#
|
4
|
+
# On my system, the Iodine JSON parser is more than 40% faster than the native Ruby parser. When using symbols the speed increase is even higher.
|
5
|
+
#
|
6
|
+
# It's easy to monkey-patch the system's `JSON.parse` method (not the `JSON.parse!` method) by using `Iodine.patch_json`.
|
7
|
+
#
|
8
|
+
# You can benchmark the Iodine JSON performance and decide if you wish to monkey-patch the Ruby implementation.
|
9
|
+
#
|
10
|
+
# JSON_FILENAME="foo.json"
|
11
|
+
#
|
12
|
+
# require 'json'
|
13
|
+
# require 'iodine'
|
14
|
+
# TIMES = 100
|
15
|
+
# STR = IO.binread(JSON_FILENAME); nil
|
16
|
+
#
|
17
|
+
# JSON.parse(STR) == Iodine::JSON.parse(STR) # => true
|
18
|
+
# JSON.parse!(STR) == Iodine::JSON.parse!(STR) # => undefined, maybe true maybe false
|
19
|
+
#
|
20
|
+
# # warm-up
|
21
|
+
# TIMES.times { JSON.parse STR }
|
22
|
+
# TIMES.times { Iodine::JSON.parse STR }
|
23
|
+
#
|
24
|
+
# puts ""; Benchmark.bm do |b|
|
25
|
+
# sys = b.report("system") { TIMES.times { JSON.parse STR } }
|
26
|
+
# sys_sym = b.report("system-sym") { TIMES.times { JSON.parse STR, symbolize_names: true } }
|
27
|
+
# iodine = b.report("iodine") { TIMES.times { Iodine::JSON.parse STR } }
|
28
|
+
# iodine_sym = b.report("iodine-sym") { TIMES.times { Iodine::JSON.parse STR, symbolize_names: true } }
|
29
|
+
#
|
30
|
+
# puts "----------------------------"
|
31
|
+
# puts "Iodine::JSON speed as percent of Ruby's native JSON:"
|
32
|
+
# puts "normal: #{sys/iodine}"
|
33
|
+
# puts "symolized: #{sys_sym/iodine_sym}"
|
34
|
+
# end; nil
|
35
|
+
#
|
36
|
+
# Note that the bang(!) method should NOT be used for monkey-patching the default JSON parser, since some important features are unsupported by the Iodine parser.
|
37
|
+
#
|
38
|
+
module JSON
|
39
|
+
end
|
40
|
+
end
|
data/lib/iodine/version.rb
CHANGED
data/lib/iodine/websocket.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
module Iodine
|
2
|
-
# This module lists the available API for
|
2
|
+
# This module lists the available API for WebSocket and EventSource (SSE) connections.
|
3
3
|
#
|
4
|
-
# This module is mixed in (using `extend` and `include`) with the
|
4
|
+
# This module is mixed in (using `extend` and `include`) with the WebSocket Callback Object (as specified by the {file:SPEC-Websocket-Draft.md proposed Rack specification}.
|
5
|
+
#
|
6
|
+
# The server performs `extend` to allow the application to be namespace agnostic (so the server can be replaced without effecting the application).
|
5
7
|
#
|
6
8
|
# The websocket API is divided into three main groups:
|
7
9
|
# * Server <=> Client relations ({Iodine::Websocket#write}, {Iodine::Websocket#close} etc')
|
8
|
-
# * Client <=> Server <=>
|
10
|
+
# * Client <=> Server <=> Pub/Sub relations ({Iodine::Websocket#subscribe}, {Iodine::Websocket#publish}.
|
9
11
|
# * Task scheduling ({Iodine::Websocket.defer}, {Iodine::Websocket#defer}, {Iodine::Websocket.each}).
|
10
12
|
#
|
11
13
|
# Notice that Websocket callback objects (as specified by the {file:SPEC-Websocket-Draft.md proposed Rack specification} *MUST* provide an `on_message(data)` callback.
|
data/lib/rack/handler/iodine.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'iodine' unless defined?(::Iodine::VERSION)
|
2
2
|
|
3
3
|
module Iodine
|
4
|
-
# {Iodine::Rack} provides a Rack complient interface (connecting Iodine to Rack) for an HTTP and Websocket Server.
|
5
|
-
#
|
6
|
-
# {Iodine::Rack} also provides convinient access to the {Iodine::HTTP.listen} function, which powers the {Iodine::Rack} server.
|
4
|
+
# Iodine's {Iodine::Rack} module provides a Rack complient interface (connecting Iodine to Rack) for an HTTP and Websocket Server.
|
7
5
|
module Rack
|
8
6
|
# get/set the Rack application.
|
9
7
|
def self.app=(val)
|
@@ -14,16 +12,18 @@ module Iodine
|
|
14
12
|
def self.app
|
15
13
|
@app
|
16
14
|
end
|
15
|
+
@app = nil
|
17
16
|
|
18
|
-
# get/set the HTTP connection timeout property. Defaults to
|
17
|
+
# get/set the HTTP connection timeout property. Defaults to 40. Limited to a maximum of 255. 0 values are silently ignored.
|
19
18
|
def self.timeout=(t)
|
20
19
|
@timeout = t
|
21
20
|
end
|
22
21
|
|
23
|
-
# get/set the HTTP connection timeout property. Defaults to
|
22
|
+
# get/set the HTTP connection timeout property. Defaults to 40 seconds.
|
24
23
|
def self.timeout
|
25
24
|
@timeout
|
26
25
|
end
|
26
|
+
@timeout = 0
|
27
27
|
|
28
28
|
# get/set the Websocket connection timeout property. Defaults to 40 seconds. Limited to a maximum of 255. 0 values are silently ignored.
|
29
29
|
def self.ws_timeout=(t)
|
@@ -34,14 +34,15 @@ module Iodine
|
|
34
34
|
def self.ws_timeout
|
35
35
|
@ws_timeout
|
36
36
|
end
|
37
|
+
@ws_timeout = 0
|
37
38
|
|
38
|
-
# get/set the HTTP public folder property. Defaults to
|
39
|
+
# get/set the HTTP public folder property. Defaults to the incoming arguments or `nil`.
|
39
40
|
def self.public=(val)
|
40
41
|
@public = val
|
41
42
|
end
|
42
|
-
@public =
|
43
|
+
@public = nil
|
43
44
|
|
44
|
-
# get/set the HTTP public folder property. Defaults to
|
45
|
+
# get/set the HTTP public folder property. Defaults to `nil`.
|
45
46
|
def self.public
|
46
47
|
@public
|
47
48
|
end
|
@@ -55,7 +56,6 @@ module Iodine
|
|
55
56
|
def self.max_body_size
|
56
57
|
@max_body
|
57
58
|
end
|
58
|
-
|
59
59
|
# get/set the maximum HTTP body size for incoming data. Defaults to ~50Mb. 0 values are silently ignored.
|
60
60
|
def self.max_body=(val)
|
61
61
|
@max_body = val
|
@@ -65,6 +65,19 @@ module Iodine
|
|
65
65
|
def self.max_body
|
66
66
|
@max_body
|
67
67
|
end
|
68
|
+
@max_body = 0
|
69
|
+
|
70
|
+
# get/set the maximum HTTP header length for incoming requests. Defaults to ~32Kb. 0 values are silently ignored.
|
71
|
+
def self.max_headers=(val)
|
72
|
+
@max_headers = val
|
73
|
+
end
|
74
|
+
|
75
|
+
# get/set the maximum HTTP header length for incoming requests. Defaults to ~32Kb.
|
76
|
+
def self.max_headers
|
77
|
+
@max_headers
|
78
|
+
end
|
79
|
+
@max_headers = 0
|
80
|
+
|
68
81
|
|
69
82
|
# get/set the maximum Websocket body size for incoming data. Defaults to defaults to ~250KB. 0 values are silently ignored.
|
70
83
|
def self.max_msg_size=(val)
|
@@ -85,6 +98,7 @@ module Iodine
|
|
85
98
|
def self.max_msg
|
86
99
|
@max_msg
|
87
100
|
end
|
101
|
+
@max_msg = 0
|
88
102
|
|
89
103
|
# get/set the HTTP logging value (true / false). Defaults to the incoming argumrnts or `false`.
|
90
104
|
def self.log=(val)
|
@@ -95,8 +109,7 @@ module Iodine
|
|
95
109
|
def self.log
|
96
110
|
@log
|
97
111
|
end
|
98
|
-
@log =
|
99
|
-
@log = false if ARGV.index('-q')
|
112
|
+
@log = false
|
100
113
|
|
101
114
|
# get/set the HTTP listening port. Defaults to 3000.
|
102
115
|
def self.port=(val)
|
@@ -107,8 +120,7 @@ module Iodine
|
|
107
120
|
def self.port
|
108
121
|
@port
|
109
122
|
end
|
110
|
-
@port =
|
111
|
-
@port ||= 3000.to_s
|
123
|
+
@port = 3000.to_s
|
112
124
|
|
113
125
|
# get/set the HTTP socket binding address. Defaults to `nil` (usually best).
|
114
126
|
def self.address=(val)
|
@@ -153,6 +165,38 @@ module Iodine
|
|
153
165
|
end
|
154
166
|
end
|
155
167
|
|
168
|
+
if ARGV.index('-b') && ARGV[ARGV.index('-b') + 1]
|
169
|
+
Iodine::Rack.address = ARGV[ARGV.index('-b') + 1]
|
170
|
+
end
|
171
|
+
if ARGV.index('-p') && ARGV[ARGV.index('-p') + 1]
|
172
|
+
Iodine::Rack.port = ARGV[ARGV.index('-p') + 1]
|
173
|
+
end
|
174
|
+
|
175
|
+
if ARGV.index('-maxbd') && ARGV[ARGV.index('-maxbd') + 1]
|
176
|
+
Iodine::Rack.max_body_size = ARGV[ARGV.index('-maxbd') + 1].to_i
|
177
|
+
end
|
178
|
+
if ARGV.index('-maxms') && ARGV[ARGV.index('-maxms') + 1]
|
179
|
+
Iodine::Rack.max_msg_size = ARGV[ARGV.index('-maxms') + 1].to_i
|
180
|
+
end
|
181
|
+
if ARGV.index('-ping') && ARGV[ARGV.index('-ping') + 1]
|
182
|
+
Iodine::Rack.ws_timeout = ARGV[ARGV.index('-ping') + 1].to_i
|
183
|
+
end
|
184
|
+
if ARGV.index('-www') && ARGV[ARGV.index('-www') + 1]
|
185
|
+
Iodine::Rack.public = ARGV[ARGV.index('-www') + 1]
|
186
|
+
end
|
187
|
+
if ARGV.index('-maxhead') && ARGV[ARGV.index('-maxhead') + 1]
|
188
|
+
Iodine::Rack.max_headers = ARGV[ARGV.index('-maxhead') + 1].to_i
|
189
|
+
end
|
190
|
+
if ARGV.index('-tout') && ARGV[ARGV.index('-tout') + 1]
|
191
|
+
Iodine::Rack.timeout = ARGV[ARGV.index('-tout') + 1].to_i
|
192
|
+
puts "WARNNING: Iodine::Rack.timeout set to 0 (ignored, timeout will be ~5 seconds)."
|
193
|
+
end
|
194
|
+
Iodine::Rack.log = true if ARGV.index('-v')
|
195
|
+
Iodine::Rack.log = false if ARGV.index('-q')
|
196
|
+
|
197
|
+
|
198
|
+
|
199
|
+
|
156
200
|
# Iodine::Rack.app = proc { |env| p env; puts env['rack.input'].read(1024).tap { |s| puts "Got data #{s.length} long, #{s[0].ord}, #{s[1].ord} ... #{s[s.length - 2].ord}, #{s[s.length - 1].ord}:" if s }; env['rack.input'].rewind; [404, {}, []] }
|
157
201
|
|
158
202
|
ENV['RACK_HANDLER'] = 'iodine'
|
@@ -167,6 +211,7 @@ end
|
|
167
211
|
|
168
212
|
begin
|
169
213
|
::Rack::Handler.register('iodine', 'Iodine::Rack') if defined?(::Rack::Handler)
|
214
|
+
::Rack::Handler.register('Iodine', 'Iodine::Rack') if defined?(::Rack::Handler)
|
170
215
|
rescue Exception
|
171
216
|
|
172
217
|
end
|