iodine 0.5.0 → 0.5.1
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/CHANGELOG.md +6 -0
- data/README.md +3 -5
- data/examples/info.md +53 -22
- data/ext/iodine/defer.c +5 -2
- data/ext/iodine/extconf.rb +4 -7
- data/ext/iodine/facil.c +23 -2
- data/ext/iodine/fio_mem.c +11 -9
- data/ext/iodine/http.c +21 -0
- data/ext/iodine/iodine.c +6 -3
- data/ext/iodine/iodine_http.c +2 -2
- data/ext/iodine/iodine_pubsub.c +2 -4
- data/ext/iodine/iodine_websockets.c +3 -0
- data/ext/iodine/rb-call.c +1 -0
- data/ext/iodine/rb-defer.c +4 -0
- data/ext/iodine/rb-fiobj2rb.h +4 -3
- data/ext/iodine/sock.c +0 -1
- data/lib/iodine.rb +5 -0
- data/lib/iodine/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0801b0def77514bb565e4330fba285d1a35fc84fb039e8931791f3f49af164f7'
|
4
|
+
data.tar.gz: 2f17d26fbae2495c70f1b4d9f822641ad8501940c872a4cd3e1d7636bbfdb1a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abbb75f0b612e43054d2c1e0725a8bcb7c70815be580fe1b62d6f64ae203a30ac41508f8652b9a005b8d65de17bf0e9f404b9b73a5b6899e2115dfca51bc9d1a
|
7
|
+
data.tar.gz: a1cc7e4f532b93c33e3cdb29040eef2ce02b2c3d6b03d13fb3daa96bbce3bc986dae0132694feb41cbc7b0c5c8d689cfe393b0b44cbce1a93ede3745f6d87219
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,12 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
6
6
|
|
7
7
|
## Changes:
|
8
8
|
|
9
|
+
#### Change log v.0.5.1 (next release)
|
10
|
+
|
11
|
+
**Fix**: fixed compilation issues on OS X version < 10.12 and Alpine Linux. Credit to @jdickey (Jeff Dickey) for opening issue #32.
|
12
|
+
|
13
|
+
**Fix**: fixed some documentation errors. Credit to @janko-m (Janko Marohnić) for catching typos in the README.
|
14
|
+
|
9
15
|
#### Change log v.0.5.0
|
10
16
|
|
11
17
|
Changed... everything. At least all the internal bits and some of the API.
|
data/README.md
CHANGED
@@ -7,8 +7,6 @@
|
|
7
7
|
|
8
8
|
[![Logo](https://github.com/boazsegev/iodine/raw/master/logo.png)](https://github.com/boazsegev/iodine)
|
9
9
|
|
10
|
-
**Notice: *iodine's core library, [facil.io](https://github.com/boazsegev/facil.io) is being re-vamped with many updates and changes. This is a time to ask - what features are important for you? [let me know here](https://github.com/boazsegev/facil.io/issues/24)***.
|
11
|
-
|
12
10
|
Iodine is a fast concurrent web server for real-time Ruby applications, with native support for:
|
13
11
|
|
14
12
|
* Websockets and EventSource (SSE);
|
@@ -25,7 +23,7 @@ Iodine is an **evented** framework with a simple API that builds off the low lev
|
|
25
23
|
|
26
24
|
* Iodine can handle **thousands of concurrent connections** (tested with more then 20K connections)!
|
27
25
|
|
28
|
-
* Iodine supports only **Linux/Unix** based systems (i.e. macOS, Ubuntu, FreeBSD etc'), which are ideal for evented IO (while Windows and Solaris are better at IO *completion* events, which are totally different).
|
26
|
+
* Iodine supports only **Linux/Unix** based systems (i.e. macOS, Ubuntu, FreeBSD etc'), which are ideal for evented IO (while Windows and Solaris are better at IO *completion* events, which are totally different). Currently, macOS support is limited to 10.12 or higher (see [issue #32](https://github.com/boazsegev/iodine/issues/32))
|
29
27
|
|
30
28
|
Iodine is a C extension for Ruby, developed and optimized for Ruby MRI 2.2.2 and up... it should support the whole Ruby 2.0 MRI family, but Rack requires Ruby 2.2.2, and so iodine matches this requirement.
|
31
29
|
|
@@ -145,13 +143,13 @@ Upgrading an HTTP connection can be performed either using iodine's native WebSo
|
|
145
143
|
|
146
144
|
Iodine treats EventSource / SSE connections as if they were a half-duplex WebSocket connection, using the exact same API and callbacks as WebSockets.
|
147
145
|
|
148
|
-
When an EventSource / SSE request is received, iodine will set the Rack Hash's upgrade property to `:sse`, so that: `env[rack.upgrade?] == :sse`.
|
146
|
+
When an EventSource / SSE request is received, iodine will set the Rack Hash's upgrade property to `:sse`, so that: `env['rack.upgrade?'] == :sse`.
|
149
147
|
|
150
148
|
The rest is detailed in the WebSocket support section.
|
151
149
|
|
152
150
|
#### WebSockets
|
153
151
|
|
154
|
-
When a WebSocket connection request is received, iodine will set the Rack Hash's upgrade property to `:websocket`, so that: `env[rack.upgrade?] == :websocket`
|
152
|
+
When a WebSocket connection request is received, iodine will set the Rack Hash's upgrade property to `:websocket`, so that: `env['rack.upgrade?'] == :websocket`
|
155
153
|
|
156
154
|
To "upgrade" the HTTP request to the WebSockets protocol (or SSE), simply provide iodine with a WebSocket Callback Object instance or class: `env['rack.upgrade'] = MyWebsocketClass` or `env['rack.upgrade'] = MyWebsocketClass.new(args)`
|
157
155
|
|
data/examples/info.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Ruby's Rack Push: Decoupling the real-time web application from the web
|
2
2
|
|
3
|
+
![](https://bowild.files.wordpress.com/2018/05/6865783407_84f470ec02_o.jpg)
|
4
|
+
|
3
5
|
Something exciting is coming.
|
4
6
|
|
5
7
|
Everyone is talking about WebSockets and their older cousin EventSource / Server Sent Events (SSE). Faye and ActionCable are all the rage and real-time updates are becoming easier than ever.
|
@@ -56,7 +58,7 @@ Using `require 'faye'` will add WebSockets to your application, but it will take
|
|
56
58
|
|
57
59
|
On the other hand, using the `agoo` or `iodine` HTTP servers will add both WebScokets and SSE to your application without any extra memory consumption.
|
58
60
|
|
59
|
-
To be more specific, using `iodine` will consume about 2Mb of memory, less than Puma, while providing both HTTP and real-time capabilities.
|
61
|
+
To be more specific, using `iodine` will consume about 2Mb of memory, marginally less than Puma, while providing both HTTP and real-time capabilities.
|
60
62
|
|
61
63
|
### The hidden `hijack` price
|
62
64
|
|
@@ -111,7 +113,7 @@ To set a callback object, the `env['rack.upgrade']` is introduced (notice the mi
|
|
111
113
|
Now the design might look like this:
|
112
114
|
|
113
115
|
```ruby
|
114
|
-
#
|
116
|
+
# Place in config.ru
|
115
117
|
RESPONSE = [200, { 'Content-Type' => 'text/html',
|
116
118
|
'Content-Length' => '12' }, [ 'Hello World!' ] ]
|
117
119
|
# a Callback class
|
@@ -130,7 +132,7 @@ end
|
|
130
132
|
APP = Proc.new do |env|
|
131
133
|
if(env['rack.upgrade?'])
|
132
134
|
env['rack.upgrade'] = MyCallbacks.new
|
133
|
-
[
|
135
|
+
[200, {}, []]
|
134
136
|
else
|
135
137
|
RESPONSE
|
136
138
|
end
|
@@ -150,7 +152,7 @@ gem install iodine
|
|
150
152
|
iodine -t 1
|
151
153
|
```
|
152
154
|
|
153
|
-
Now open the browser, visit [localhost:3000](http://localhost:3000) and open the browser console to test some
|
155
|
+
Now open the browser, visit [localhost:3000](http://localhost:3000) and open the browser console to test some JavaScript.
|
154
156
|
|
155
157
|
First try an EventSource (SSE) connection (run in browser console):
|
156
158
|
|
@@ -198,7 +200,7 @@ So far, it's so simple, it's hard to notice how powerful this is.
|
|
198
200
|
Consider implementing a stock ticker, or in this case, a timer:
|
199
201
|
|
200
202
|
```ruby
|
201
|
-
#
|
203
|
+
# Place in config.ru
|
202
204
|
RESPONSE = [200, { 'Content-Type' => 'text/html',
|
203
205
|
'Content-Length' => '12' }, [ 'Hello World!' ] ]
|
204
206
|
|
@@ -212,10 +214,31 @@ module LiveList
|
|
212
214
|
def self.>>(connection)
|
213
215
|
@lock.synchronize { @list.delete connection }
|
214
216
|
end
|
217
|
+
def any?
|
218
|
+
# remove connection to the "live list"
|
219
|
+
@lock.synchronize { @list.any? }
|
220
|
+
end
|
221
|
+
# this will send a message to all the connections that share the same process.
|
222
|
+
# (in cluster mode we get partial broadcasting only and this doesn't scale)
|
215
223
|
def self.broadcast(data)
|
216
|
-
@lock.synchronize
|
217
|
-
@list.each
|
218
|
-
|
224
|
+
@lock.synchronize do
|
225
|
+
@list.each do |c|
|
226
|
+
begin
|
227
|
+
c.write data
|
228
|
+
rescue IOError => _e
|
229
|
+
# An IOError can occur if the connection was closed during the loop.
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Broadcast the time very second... but...
|
237
|
+
# Threads will BREAK in cluster mode.
|
238
|
+
@thread = Thread.new do
|
239
|
+
while(LiveList.any?) do
|
240
|
+
sleep(1)
|
241
|
+
LiveList.broadcast "The time is: #{Time.now}"
|
219
242
|
end
|
220
243
|
end
|
221
244
|
|
@@ -235,19 +258,11 @@ class MyCallbacks
|
|
235
258
|
end
|
236
259
|
end
|
237
260
|
|
238
|
-
# Broadcast the time very second
|
239
|
-
Thread.new do
|
240
|
-
while(true) do
|
241
|
-
sleep(1)
|
242
|
-
LiveList.broadcast "The time is: #{Time.now}"
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
261
|
# The Rack application
|
247
262
|
APP = Proc.new do |env|
|
248
263
|
if(env['rack.upgrade?'])
|
249
264
|
env['rack.upgrade'] = MyCallbacks.new
|
250
|
-
[
|
265
|
+
[200, {}, []]
|
251
266
|
else
|
252
267
|
RESPONSE
|
253
268
|
end
|
@@ -256,12 +271,22 @@ end
|
|
256
271
|
run APP
|
257
272
|
```
|
258
273
|
|
259
|
-
|
274
|
+
Run the iodine server in single process mode: `iodine -w 1` and the little timer is ticking.
|
275
|
+
|
276
|
+
Honestly, I don't love the code I just wrote for the previous example. It's a little long, it's slightly iffy and we can't use iodine's cluster mode.
|
277
|
+
|
278
|
+
For my next example, I'll author a chat room in 32 lines (including comments).
|
279
|
+
|
280
|
+
I will use Iodine's pub/sub extension API to avoid the LiveList module and the timer thread (I don't need a timer, so I'll skip the [`Iodine.run_every` method](https://www.rubydoc.info/github/boazsegev/iodine/master/Iodine#run_every-class_method)).
|
281
|
+
|
282
|
+
Also, I'll limit the interaction to WebSocket clients. Why? to show I can.
|
283
|
+
|
284
|
+
This will better demonstrate the power offered by the new `env['rack.upgrade']` approach and it will also work in cluster mode.
|
260
285
|
|
261
|
-
|
286
|
+
Sadly, this means that the example won't run on Agoo for now.
|
262
287
|
|
263
288
|
```ruby
|
264
|
-
#
|
289
|
+
# Place in config.ru
|
265
290
|
RESPONSE = [200, { 'Content-Type' => 'text/html',
|
266
291
|
'Content-Length' => '12' }, [ 'Hello World!' ] ]
|
267
292
|
# a Callback class
|
@@ -281,11 +306,11 @@ class MyCallbacks
|
|
281
306
|
publish :chat, "#{@name} left the chat."
|
282
307
|
end
|
283
308
|
end
|
284
|
-
#
|
309
|
+
# The actual Rack application
|
285
310
|
APP = Proc.new do |env|
|
286
311
|
if(env['rack.upgrade?'] == :websocket)
|
287
312
|
env['rack.upgrade'] = MyCallbacks.new(env)
|
288
|
-
[
|
313
|
+
[200, {}, []]
|
289
314
|
else
|
290
315
|
RESPONSE
|
291
316
|
end
|
@@ -294,6 +319,12 @@ end
|
|
294
319
|
run APP
|
295
320
|
```
|
296
321
|
|
322
|
+
Start the application from the command line (in terminal):
|
323
|
+
|
324
|
+
```bash
|
325
|
+
iodine
|
326
|
+
```
|
327
|
+
|
297
328
|
Now try (in the browser console):
|
298
329
|
|
299
330
|
```js
|
data/ext/iodine/defer.c
CHANGED
@@ -278,15 +278,18 @@ error:
|
|
278
278
|
*/
|
279
279
|
#pragma weak defer_free_thread
|
280
280
|
void defer_free_thread(void *p_thr) {
|
281
|
-
|
281
|
+
if (*((pthread_t *)p_thr)) {
|
282
|
+
pthread_detach(*((pthread_t *)p_thr));
|
283
|
+
}
|
282
284
|
free(p_thr);
|
283
285
|
}
|
284
286
|
|
285
287
|
#pragma weak defer_join_thread
|
286
288
|
int defer_join_thread(void *p_thr) {
|
287
|
-
if (!p_thr)
|
289
|
+
if (!p_thr || !(*((pthread_t *)p_thr)))
|
288
290
|
return -1;
|
289
291
|
pthread_join(*((pthread_t *)p_thr), NULL);
|
292
|
+
*((pthread_t *)p_thr) = NULL;
|
290
293
|
defer_free_thread(p_thr);
|
291
294
|
return 0;
|
292
295
|
}
|
data/ext/iodine/extconf.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
-
def check_for_stdatomics
|
4
|
-
RbConfig::MAKEFILE_CONFIG['CC'] = $CC = ENV['CC'] if ENV['CC']
|
5
|
-
RbConfig::MAKEFILE_CONFIG['CPP'] = $CPP = ENV['CPP'] if ENV['CPP']
|
6
|
-
puts 'Missing support for atomic operations (support for C11) - is your compiler updated?' unless have_header('stdatomic.h')
|
7
|
-
end
|
8
|
-
|
9
3
|
abort 'Missing a Linux/Unix OS evented API (epoll/kqueue).' unless have_func('kevent') || have_func('epoll_ctl')
|
10
4
|
|
11
5
|
if ENV['CC']
|
@@ -16,6 +10,10 @@ elsif find_executable('clang') && puts('testing clang for stdatomic support...')
|
|
16
10
|
$CC = ENV['CC'] = 'clang'
|
17
11
|
$CPP = ENV['CPP'] = 'clang'
|
18
12
|
puts "using clang compiler v. #{`clang -dumpversion`}."
|
13
|
+
elsif find_executable('gcc') && (`gcc -dumpversion 2>&1`.to_i >= 5)
|
14
|
+
$CC = ENV['CC'] = 'gcc'
|
15
|
+
$CPP = ENV['CPP'] = find_executable('g++') ? 'g++' : 'gcc'
|
16
|
+
puts "using gcc #{ `gcc -dumpversion 2>&1`.to_i }"
|
19
17
|
elsif find_executable('gcc-6')
|
20
18
|
$CC = ENV['CC'] = 'gcc-6'
|
21
19
|
$CPP = ENV['CPP'] = find_executable('g++-6') ? 'g++-6' : 'gcc-6'
|
@@ -29,7 +27,6 @@ elsif find_executable('gcc-4.9')
|
|
29
27
|
$CPP = ENV['CPP'] = find_executable('g++-4.9') ? 'g++-4.9' : 'gcc-4.9'
|
30
28
|
puts 'using gcc-4.9 compiler.'
|
31
29
|
else
|
32
|
-
# check_for_stdatomics
|
33
30
|
puts 'using an unknown (old?) compiler... who knows if this will work out... we hope.'
|
34
31
|
end
|
35
32
|
|
data/ext/iodine/facil.c
CHANGED
@@ -27,6 +27,27 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
27
27
|
#define __attribute__(...)
|
28
28
|
#endif
|
29
29
|
|
30
|
+
/* *****************************************************************************
|
31
|
+
Patch for OSX version < 10.12 from https://stackoverflow.com/a/9781275/4025095
|
32
|
+
***************************************************************************** */
|
33
|
+
#if defined(__MACH__) && !defined(CLOCK_REALTIME)
|
34
|
+
#include <sys/time.h>
|
35
|
+
#define CLOCK_REALTIME 0
|
36
|
+
#define clock_gettime patch_clock_gettime
|
37
|
+
// clock_gettime is not implemented on older versions of OS X (< 10.12).
|
38
|
+
// If implemented, CLOCK_REALTIME will have already been defined.
|
39
|
+
static inline int patch_clock_gettime(int clk_id, struct timespec *t) {
|
40
|
+
struct timeval now;
|
41
|
+
int rv = gettimeofday(&now, NULL);
|
42
|
+
if (rv)
|
43
|
+
return rv;
|
44
|
+
t->tv_sec = now.tv_sec;
|
45
|
+
t->tv_nsec = now.tv_usec * 1000;
|
46
|
+
return 0;
|
47
|
+
(void)clk_id;
|
48
|
+
}
|
49
|
+
#endif
|
50
|
+
|
30
51
|
/* *****************************************************************************
|
31
52
|
Data Structures
|
32
53
|
***************************************************************************** */
|
@@ -426,9 +447,9 @@ static void facil_lib_init(void) {
|
|
426
447
|
spn_lock(&facil_libinit_lock);
|
427
448
|
if (facil_data)
|
428
449
|
goto finish;
|
429
|
-
facil_data = mmap(NULL, mem_size, PROT_READ | PROT_WRITE
|
450
|
+
facil_data = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
|
430
451
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
431
|
-
if (!facil_data) {
|
452
|
+
if (!facil_data || facil_data == MAP_FAILED) {
|
432
453
|
perror("ERROR: Couldn't initialize the facil.io library");
|
433
454
|
exit(0);
|
434
455
|
}
|
data/ext/iodine/fio_mem.c
CHANGED
@@ -141,18 +141,17 @@ static inline void *sys_alloc(size_t len, uint8_t is_indi) {
|
|
141
141
|
/* hope for the best? */
|
142
142
|
#ifdef MAP_ALIGNED
|
143
143
|
result = mmap(
|
144
|
-
next_alloc, len, PROT_READ | PROT_WRITE
|
144
|
+
next_alloc, len, PROT_READ | PROT_WRITE,
|
145
145
|
MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED(FIO_MEMORY_BLOCK_SIZE), -1, 0);
|
146
146
|
#else
|
147
|
-
result = mmap(next_alloc, len, PROT_READ | PROT_WRITE
|
147
|
+
result = mmap(next_alloc, len, PROT_READ | PROT_WRITE,
|
148
148
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
149
149
|
#endif
|
150
150
|
if (result == MAP_FAILED)
|
151
151
|
return NULL;
|
152
152
|
if (((uintptr_t)result & FIO_MEMORY_BLOCK_MASK)) {
|
153
153
|
munmap(result, len);
|
154
|
-
result = mmap(NULL, len + FIO_MEMORY_BLOCK_SIZE,
|
155
|
-
PROT_READ | PROT_WRITE | PROT_EXEC,
|
154
|
+
result = mmap(NULL, len + FIO_MEMORY_BLOCK_SIZE, PROT_READ | PROT_WRITE,
|
156
155
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
157
156
|
if (result == MAP_FAILED)
|
158
157
|
return NULL;
|
@@ -180,9 +179,9 @@ static void *sys_realloc(void *mem, size_t prev_len, size_t new_len) {
|
|
180
179
|
if (result == MAP_FAILED)
|
181
180
|
return NULL;
|
182
181
|
#else
|
183
|
-
void *result =
|
184
|
-
|
185
|
-
|
182
|
+
void *result =
|
183
|
+
mmap((void *)((uintptr_t)mem + prev_len), new_len - prev_len,
|
184
|
+
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
186
185
|
if (result == (void *)((uintptr_t)mem + prev_len)) {
|
187
186
|
result = mem;
|
188
187
|
} else {
|
@@ -391,8 +390,11 @@ Non-Block allocations (direct from the system)
|
|
391
390
|
static inline void *big_alloc(size_t size) {
|
392
391
|
size = sys_round_size(size + 16);
|
393
392
|
size_t *mem = sys_alloc(size, 1);
|
394
|
-
|
395
|
-
|
393
|
+
if (mem) { /* likely */
|
394
|
+
*mem = size;
|
395
|
+
return (void *)(((uintptr_t)mem) + 16);
|
396
|
+
}
|
397
|
+
return NULL;
|
396
398
|
}
|
397
399
|
|
398
400
|
static inline void big_free(void *ptr) {
|
data/ext/iodine/http.c
CHANGED
@@ -21,6 +21,27 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
21
21
|
|
22
22
|
#include "fio_mem.h"
|
23
23
|
|
24
|
+
/* *****************************************************************************
|
25
|
+
Patch for OSX version < 10.12 from https://stackoverflow.com/a/9781275/4025095
|
26
|
+
***************************************************************************** */
|
27
|
+
#if defined(__MACH__) && !defined(CLOCK_REALTIME)
|
28
|
+
#include <sys/time.h>
|
29
|
+
#define CLOCK_REALTIME 0
|
30
|
+
#define clock_gettime patch_clock_gettime
|
31
|
+
// clock_gettime is not implemented on older versions of OS X (< 10.12).
|
32
|
+
// If implemented, CLOCK_REALTIME will have already been defined.
|
33
|
+
static inline int patch_clock_gettime(int clk_id, struct timespec *t) {
|
34
|
+
struct timeval now;
|
35
|
+
int rv = gettimeofday(&now, NULL);
|
36
|
+
if (rv)
|
37
|
+
return rv;
|
38
|
+
t->tv_sec = now.tv_sec;
|
39
|
+
t->tv_nsec = now.tv_usec * 1000;
|
40
|
+
return 0;
|
41
|
+
(void)clk_id;
|
42
|
+
}
|
43
|
+
#endif
|
44
|
+
|
24
45
|
/* *****************************************************************************
|
25
46
|
Small Helpers
|
26
47
|
***************************************************************************** */
|
data/ext/iodine/iodine.c
CHANGED
@@ -217,20 +217,23 @@ static void *iodine_io_thread(void *arg) {
|
|
217
217
|
}
|
218
218
|
return NULL;
|
219
219
|
}
|
220
|
-
|
220
|
+
void iodine_start_io_thread(void *a1, void *a2) {
|
221
221
|
(void)a1;
|
222
222
|
(void)a2;
|
223
223
|
pthread_create(&sock_io_pthread, NULL, iodine_io_thread, NULL);
|
224
224
|
}
|
225
225
|
static void iodine_join_io_thread(void) {
|
226
226
|
sock_io_thread = 0;
|
227
|
-
|
227
|
+
if (sock_io_pthread) {
|
228
|
+
pthread_join(sock_io_pthread, NULL);
|
229
|
+
}
|
230
|
+
sock_io_pthread = NULL;
|
228
231
|
}
|
229
232
|
|
230
233
|
static void *srv_start_no_gvl(void *s_) {
|
231
234
|
iodine_start_settings_s *s = s_;
|
232
235
|
sock_io_thread = 1;
|
233
|
-
|
236
|
+
iodine_start_io_thread(NULL, NULL);
|
234
237
|
fprintf(stderr, "\n");
|
235
238
|
if (s->processes == 1 || (s->processes == 0 && s->threads > 0)) {
|
236
239
|
/* single worker */
|
data/ext/iodine/iodine_http.c
CHANGED
@@ -20,7 +20,6 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
20
20
|
/* *****************************************************************************
|
21
21
|
Available Globals
|
22
22
|
***************************************************************************** */
|
23
|
-
static VALUE IodineHTTP;
|
24
23
|
|
25
24
|
typedef struct {
|
26
25
|
VALUE app;
|
@@ -160,7 +159,8 @@ static inline VALUE copy2env(iodine_http_request_handle_s *handle) {
|
|
160
159
|
case IODINE_UPGRADE_SSE:
|
161
160
|
env = rb_hash_dup(env_template_sse);
|
162
161
|
break;
|
163
|
-
case IODINE_UPGRADE_NONE:
|
162
|
+
case IODINE_UPGRADE_NONE: /* fallthrough */
|
163
|
+
default:
|
164
164
|
env = rb_hash_dup(env_template_no_upgrade);
|
165
165
|
break;
|
166
166
|
}
|
data/ext/iodine/iodine_pubsub.c
CHANGED
@@ -795,7 +795,6 @@ engine is used.
|
|
795
795
|
*/
|
796
796
|
VALUE iodine_publish(int argc, VALUE *argv, VALUE self) {
|
797
797
|
VALUE rb_ch, rb_msg, rb_engine = Qnil;
|
798
|
-
uint8_t use_pattern = 0;
|
799
798
|
const pubsub_engine_s *engine = NULL;
|
800
799
|
switch (argc) {
|
801
800
|
case 3:
|
@@ -810,8 +809,7 @@ VALUE iodine_publish(int argc, VALUE *argv, VALUE self) {
|
|
810
809
|
Check_Type(argv[0], T_HASH);
|
811
810
|
rb_ch = rb_hash_aref(argv[0], to_sym_id);
|
812
811
|
if (rb_ch == Qnil || rb_ch == Qfalse) {
|
813
|
-
|
814
|
-
rb_ch = rb_hash_aref(argv[0], match_sym_id);
|
812
|
+
rb_ch = rb_hash_aref(argv[0], channel_sym_id);
|
815
813
|
}
|
816
814
|
rb_msg = rb_hash_aref(argv[0], message_sym_id);
|
817
815
|
rb_engine = rb_hash_aref(argv[0], engine_varid);
|
@@ -826,7 +824,7 @@ VALUE iodine_publish(int argc, VALUE *argv, VALUE self) {
|
|
826
824
|
Check_Type(rb_msg, T_STRING);
|
827
825
|
|
828
826
|
if (rb_ch == Qnil || rb_ch == Qfalse)
|
829
|
-
rb_raise(rb_eArgError, "channel is required .");
|
827
|
+
rb_raise(rb_eArgError, "target / channel is required .");
|
830
828
|
if (TYPE(rb_ch) == T_SYMBOL)
|
831
829
|
rb_ch = rb_sym2str(rb_ch);
|
832
830
|
Check_Type(rb_ch, T_STRING);
|
@@ -209,6 +209,7 @@ static VALUE iodine_defer(int argc, VALUE *argv, VALUE self) {
|
|
209
209
|
return block;
|
210
210
|
}
|
211
211
|
|
212
|
+
#if 0 /* deprecated */
|
212
213
|
/**
|
213
214
|
Schedules a block of code to run for the specified websocket at a later time,
|
214
215
|
(**if** the connection is open). The block will run within the connection's
|
@@ -240,6 +241,8 @@ static VALUE iodine_class_defer(VALUE self, VALUE ws_uuid) {
|
|
240
241
|
return block;
|
241
242
|
}
|
242
243
|
|
244
|
+
#endif
|
245
|
+
|
243
246
|
/* *****************************************************************************
|
244
247
|
Websocket Pub/Sub API
|
245
248
|
***************************************************************************** */
|
data/ext/iodine/rb-call.c
CHANGED
data/ext/iodine/rb-defer.c
CHANGED
@@ -54,6 +54,9 @@ static void *create_ruby_thread_gvl(void *args) {
|
|
54
54
|
return (void *)Registry.add(rb_thread_create(defer_thread_inGVL, args));
|
55
55
|
}
|
56
56
|
|
57
|
+
/* used during fork */
|
58
|
+
void iodine_start_io_thread(void *a1, void *a2);
|
59
|
+
|
57
60
|
static void *fork_using_ruby(void *ignr) {
|
58
61
|
RubyCaller.call(Iodine, rb_intern("before_fork"));
|
59
62
|
const VALUE ProcessClass = rb_const_get(rb_cObject, rb_intern("Process"));
|
@@ -68,6 +71,7 @@ static void *fork_using_ruby(void *ignr) {
|
|
68
71
|
if (!pid) {
|
69
72
|
Registry.on_fork();
|
70
73
|
RubyCaller.call(Iodine, rb_intern("after_fork"));
|
74
|
+
iodine_start_io_thread(NULL, NULL);
|
71
75
|
}
|
72
76
|
return (void *)pid;
|
73
77
|
(void)ignr;
|
data/ext/iodine/rb-fiobj2rb.h
CHANGED
@@ -28,9 +28,6 @@ static inline VALUE fiobj2rb(FIOBJ o, uint8_t str2sym) {
|
|
28
28
|
case FIOBJ_T_NUMBER:
|
29
29
|
rb = LONG2FIX(fiobj_obj2num(o));
|
30
30
|
break;
|
31
|
-
case FIOBJ_T_NULL:
|
32
|
-
rb = Qnil;
|
33
|
-
break;
|
34
31
|
case FIOBJ_T_TRUE:
|
35
32
|
rb = Qtrue;
|
36
33
|
break;
|
@@ -58,6 +55,10 @@ static inline VALUE fiobj2rb(FIOBJ o, uint8_t str2sym) {
|
|
58
55
|
case FIOBJ_T_HASH:
|
59
56
|
rb = rb_hash_new();
|
60
57
|
break;
|
58
|
+
case FIOBJ_T_NULL: /* fallthrough */
|
59
|
+
default:
|
60
|
+
rb = Qnil;
|
61
|
+
break;
|
61
62
|
};
|
62
63
|
return rb;
|
63
64
|
}
|
data/ext/iodine/sock.c
CHANGED
data/lib/iodine.rb
CHANGED
@@ -190,6 +190,7 @@ module Iodine
|
|
190
190
|
|
191
191
|
|
192
192
|
@after_fork_blocks = []
|
193
|
+
# Performs a block of code whenever a new worker process spins up (performed once per worker).
|
193
194
|
def self.after_fork(*args, &block)
|
194
195
|
if(block)
|
195
196
|
@after_fork_blocks << [args, block]
|
@@ -199,6 +200,7 @@ module Iodine
|
|
199
200
|
end
|
200
201
|
|
201
202
|
@before_fork_blocks = []
|
203
|
+
# Performs a block of code just before a new worker process spins up (performed once per worker).
|
202
204
|
def self.before_fork(*args, &block)
|
203
205
|
if(block)
|
204
206
|
@before_fork_blocks << [args, block]
|
@@ -211,16 +213,19 @@ module Iodine
|
|
211
213
|
end
|
212
214
|
|
213
215
|
if(!defined?(after_fork))
|
216
|
+
# Performs a block of code whenever a new worker process spins up (performed once per worker).
|
214
217
|
def after_fork(*args, &block)
|
215
218
|
Iodine.after_fork(*args, &block)
|
216
219
|
end
|
217
220
|
end
|
218
221
|
if(!defined?(on_worker_boot))
|
222
|
+
# Performs a block of code whenever a new worker process spins up (performed once per worker).
|
219
223
|
def on_worker_boot(*args, &block)
|
220
224
|
Iodine.after_fork(*args, &block)
|
221
225
|
end
|
222
226
|
end
|
223
227
|
if(!defined?(before_fork))
|
228
|
+
# Performs a block of code just before a new worker process spins up (performed once per worker).
|
224
229
|
def before_fork(*args, &block)
|
225
230
|
Iodine.before_fork(*args, &block)
|
226
231
|
end
|
data/lib/iodine/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iodine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|