isomorfeus-iodine 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +0 -1
- data/examples/config.ru +56 -56
- data/exe/iodine +64 -64
- data/ext/iodine_ext/fio.c +7 -7
- data/ext/iodine_ext/fio.h +5 -3
- data/ext/iodine_ext/http.c +1 -1
- data/ext/iodine_ext/redis_engine.c +1 -1
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +35 -35
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1da68cfbc32b4125c4ca8513b8796276b1ea4daa2123517a5fa3ed895ebddf0
|
4
|
+
data.tar.gz: 1cc64c512e725ca4e7fb119c9bc59f2ac6d4edc59ae99e2ca7c4a74beb8fd9de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a04d7a8b0edd83ce7bbb130a43b4655ea0b271ffc99c3d2bd265763899335569ee23abdae992e4082c902989817ded91d5ac529513bb089c5a66e34c984b7daf
|
7
|
+
data.tar.gz: 73dc8cbc81472fb1dacdf38f71cdd75107b8641d64a6f4d0834fa8e7f60126852a767ac64a25d0ca85403cee2d0e80b1fb40f4f24d53210627d1f7c378b3f9a7
|
data/Rakefile
CHANGED
data/examples/config.ru
CHANGED
@@ -1,56 +1,56 @@
|
|
1
|
-
# This is a WebSocket / SSE notification broadcasting application.
|
2
|
-
#
|
3
|
-
# Running this application from the command line is easy with:
|
4
|
-
#
|
5
|
-
# iodine
|
6
|
-
#
|
7
|
-
# Or, in single thread and single process:
|
8
|
-
#
|
9
|
-
# iodine -t 1 -w 1
|
10
|
-
#
|
11
|
-
# Benchmark with `ab` or `wrk` (a 5 seconds benchmark with 2000 concurrent clients):
|
12
|
-
#
|
13
|
-
# ab -c 2000 -t 5 -n 1000000 -k http://127.0.0.1:3000/
|
14
|
-
# wrk -c2000 -d5 -t12 http://localhost:3000/
|
15
|
-
|
16
|
-
|
17
|
-
# A simple router - Checks for Websocket Upgrade and answers HTTP.
|
18
|
-
module MyHTTPRouter
|
19
|
-
# This is the HTTP response object according to the Rack specification.
|
20
|
-
HTTP_RESPONSE = [200, { 'Content-Type' => 'text/html',
|
21
|
-
'Content-Length' => '77' },
|
22
|
-
['Please connect using WebSockets or SSE (send messages only using WebSockets).']]
|
23
|
-
|
24
|
-
WS_RESPONSE = [0, {}, []].freeze
|
25
|
-
|
26
|
-
# this is function will be called by the Rack server (iodine) for every request.
|
27
|
-
def self.call env
|
28
|
-
# check if this is an upgrade request (WebsSocket / SSE).
|
29
|
-
if(env['rack.upgrade?'.freeze])
|
30
|
-
env['rack.upgrade'.freeze] = BroadcastClient
|
31
|
-
return WS_RESPONSE
|
32
|
-
end
|
33
|
-
# simply return the RESPONSE object, no matter what request was received.
|
34
|
-
HTTP_RESPONSE
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# A simple Websocket Callback Object.
|
39
|
-
module BroadcastClient
|
40
|
-
# seng a message to new clients.
|
41
|
-
def on_open client
|
42
|
-
client.subscribe :broadcast
|
43
|
-
end
|
44
|
-
# send a message, letting the client know the server is suggunt down.
|
45
|
-
def on_shutdown client
|
46
|
-
client.write "Server shutting down. Goodbye."
|
47
|
-
end
|
48
|
-
# perform the echo
|
49
|
-
def on_message client, data
|
50
|
-
client.publish :broadcast, data
|
51
|
-
end
|
52
|
-
extend self
|
53
|
-
end
|
54
|
-
|
55
|
-
# this function call links our HelloWorld application with Rack
|
56
|
-
run MyHTTPRouter
|
1
|
+
# This is a WebSocket / SSE notification broadcasting application.
|
2
|
+
#
|
3
|
+
# Running this application from the command line is easy with:
|
4
|
+
#
|
5
|
+
# iodine
|
6
|
+
#
|
7
|
+
# Or, in single thread and single process:
|
8
|
+
#
|
9
|
+
# iodine -t 1 -w 1
|
10
|
+
#
|
11
|
+
# Benchmark with `ab` or `wrk` (a 5 seconds benchmark with 2000 concurrent clients):
|
12
|
+
#
|
13
|
+
# ab -c 2000 -t 5 -n 1000000 -k http://127.0.0.1:3000/
|
14
|
+
# wrk -c2000 -d5 -t12 http://localhost:3000/
|
15
|
+
|
16
|
+
|
17
|
+
# A simple router - Checks for Websocket Upgrade and answers HTTP.
|
18
|
+
module MyHTTPRouter
|
19
|
+
# This is the HTTP response object according to the Rack specification.
|
20
|
+
HTTP_RESPONSE = [200, { 'Content-Type' => 'text/html',
|
21
|
+
'Content-Length' => '77' },
|
22
|
+
['Please connect using WebSockets or SSE (send messages only using WebSockets).']]
|
23
|
+
|
24
|
+
WS_RESPONSE = [0, {}, []].freeze
|
25
|
+
|
26
|
+
# this is function will be called by the Rack server (iodine) for every request.
|
27
|
+
def self.call env
|
28
|
+
# check if this is an upgrade request (WebsSocket / SSE).
|
29
|
+
if(env['rack.upgrade?'.freeze])
|
30
|
+
env['rack.upgrade'.freeze] = BroadcastClient
|
31
|
+
return WS_RESPONSE
|
32
|
+
end
|
33
|
+
# simply return the RESPONSE object, no matter what request was received.
|
34
|
+
HTTP_RESPONSE
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# A simple Websocket Callback Object.
|
39
|
+
module BroadcastClient
|
40
|
+
# seng a message to new clients.
|
41
|
+
def on_open client
|
42
|
+
client.subscribe :broadcast
|
43
|
+
end
|
44
|
+
# send a message, letting the client know the server is suggunt down.
|
45
|
+
def on_shutdown client
|
46
|
+
client.write "Server shutting down. Goodbye."
|
47
|
+
end
|
48
|
+
# perform the echo
|
49
|
+
def on_message client, data
|
50
|
+
client.publish :broadcast, data
|
51
|
+
end
|
52
|
+
extend self
|
53
|
+
end
|
54
|
+
|
55
|
+
# this function call links our HelloWorld application with Rack
|
56
|
+
run MyHTTPRouter
|
data/exe/iodine
CHANGED
@@ -1,64 +1,64 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
IODINE_PARSE_CLI = true
|
4
|
-
require 'iodine'
|
5
|
-
|
6
|
-
# Load Rack if available (assume it will be used)
|
7
|
-
|
8
|
-
require 'rack'
|
9
|
-
|
10
|
-
module Iodine
|
11
|
-
# The Iodine::Base namespace is reserved for internal use and is NOT part of the public API.
|
12
|
-
module Base
|
13
|
-
# Command line interface. The Ruby CLI might be changed in future versions.
|
14
|
-
module CLI
|
15
|
-
|
16
|
-
def self.try_file filename
|
17
|
-
return nil unless File.exist? filename
|
18
|
-
::Rack::Builder.parse_file filename
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.get_app
|
22
|
-
app = nil
|
23
|
-
filename = Iodine::DEFAULT_SETTINGS[:filename_]
|
24
|
-
if filename
|
25
|
-
app = try_file filename
|
26
|
-
app = try_file "#{filename}.ru" unless app
|
27
|
-
unless app
|
28
|
-
puts "* Couldn't find #{filename}\n testing for config.ru\n"
|
29
|
-
app = try_file "config.ru"
|
30
|
-
end
|
31
|
-
else
|
32
|
-
app = try_file "config.ru";
|
33
|
-
end
|
34
|
-
app
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.perform_warmup(app)
|
38
|
-
# load anything marked with `autoload`, since autoload is niether thread safe nor fork friendly.
|
39
|
-
Iodine.on_state(:on_start) do
|
40
|
-
Module.constants.each do |n|
|
41
|
-
begin
|
42
|
-
Object.const_get(n)
|
43
|
-
rescue StandardError => _e
|
44
|
-
end
|
45
|
-
end
|
46
|
-
::Rack::Builder.new(app) do |r|
|
47
|
-
r.warmup do |a|
|
48
|
-
client = ::Rack::MockRequest.new(a)
|
49
|
-
client.get('/')
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.call
|
56
|
-
app = get_app
|
57
|
-
perform_warmup(app) if Iodine::DEFAULT_SETTINGS[:warmup_]
|
58
|
-
Iodine::Rack.run(app)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
Iodine::Base::CLI.call
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
IODINE_PARSE_CLI = true
|
4
|
+
require 'iodine'
|
5
|
+
|
6
|
+
# Load Rack if available (assume it will be used)
|
7
|
+
|
8
|
+
require 'rack'
|
9
|
+
|
10
|
+
module Iodine
|
11
|
+
# The Iodine::Base namespace is reserved for internal use and is NOT part of the public API.
|
12
|
+
module Base
|
13
|
+
# Command line interface. The Ruby CLI might be changed in future versions.
|
14
|
+
module CLI
|
15
|
+
|
16
|
+
def self.try_file filename
|
17
|
+
return nil unless File.exist? filename
|
18
|
+
::Rack::Builder.parse_file filename
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.get_app
|
22
|
+
app = nil
|
23
|
+
filename = Iodine::DEFAULT_SETTINGS[:filename_]
|
24
|
+
if filename
|
25
|
+
app = try_file filename
|
26
|
+
app = try_file "#{filename}.ru" unless app
|
27
|
+
unless app
|
28
|
+
puts "* Couldn't find #{filename}\n testing for config.ru\n"
|
29
|
+
app = try_file "config.ru"
|
30
|
+
end
|
31
|
+
else
|
32
|
+
app = try_file "config.ru";
|
33
|
+
end
|
34
|
+
app
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.perform_warmup(app)
|
38
|
+
# load anything marked with `autoload`, since autoload is niether thread safe nor fork friendly.
|
39
|
+
Iodine.on_state(:on_start) do
|
40
|
+
Module.constants.each do |n|
|
41
|
+
begin
|
42
|
+
Object.const_get(n)
|
43
|
+
rescue StandardError => _e
|
44
|
+
end
|
45
|
+
end
|
46
|
+
::Rack::Builder.new(app) do |r|
|
47
|
+
r.warmup do |a|
|
48
|
+
client = ::Rack::MockRequest.new(a)
|
49
|
+
client.get('/')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.call
|
56
|
+
app = get_app
|
57
|
+
perform_warmup(app) if Iodine::DEFAULT_SETTINGS[:warmup_]
|
58
|
+
Iodine::Rack.run(app)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
Iodine::Base::CLI.call
|
data/ext/iodine_ext/fio.c
CHANGED
@@ -155,7 +155,7 @@ int ioctl (int fd, u_long request, int* argp) {
|
|
155
155
|
else { return 0; }
|
156
156
|
}
|
157
157
|
|
158
|
-
int
|
158
|
+
int fio_kill(int pid, int sig) {
|
159
159
|
/* Credit to Jan Biedermann (GitHub: @janbiedermann) */
|
160
160
|
HANDLE handle;
|
161
161
|
DWORD status;
|
@@ -987,7 +987,7 @@ FIO_FUNC void fio_thread_signal(void) {
|
|
987
987
|
(void)r;
|
988
988
|
} else if (fd == -1) {
|
989
989
|
/* hardly the best way, but there's a thread sleeping on air */
|
990
|
-
|
990
|
+
fio_kill(getpid(), SIGCONT);
|
991
991
|
}
|
992
992
|
#endif
|
993
993
|
}
|
@@ -1654,7 +1654,7 @@ void fio_reap_children(void) {
|
|
1654
1654
|
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
|
1655
1655
|
if (sigaction(SIGCHLD, &sa, &fio_old_sig_chld) == -1) {
|
1656
1656
|
perror("Child reaping initialization failed");
|
1657
|
-
|
1657
|
+
fio_kill(0, SIGINT);
|
1658
1658
|
exit(errno);
|
1659
1659
|
}
|
1660
1660
|
}
|
@@ -4603,7 +4603,7 @@ static void *fio_sentinel_worker_thread(void *arg) {
|
|
4603
4603
|
if (child == -1) {
|
4604
4604
|
FIO_LOG_FATAL("couldn't spawn worker.");
|
4605
4605
|
perror("\n errno");
|
4606
|
-
|
4606
|
+
fio_kill(fio_parent_pid(), SIGINT);
|
4607
4607
|
fio_stop();
|
4608
4608
|
return NULL;
|
4609
4609
|
} else if (child) {
|
@@ -4617,7 +4617,7 @@ static void *fio_sentinel_worker_thread(void *arg) {
|
|
4617
4617
|
} else {
|
4618
4618
|
FIO_LOG_FATAL("Child worker (%d) shutdown. Stopping services.", child);
|
4619
4619
|
}
|
4620
|
-
|
4620
|
+
fio_kill(0, SIGINT);
|
4621
4621
|
}
|
4622
4622
|
#else
|
4623
4623
|
if (fio_data->active) {
|
@@ -6879,7 +6879,7 @@ static void fio_cluster_on_close(intptr_t uuid, fio_protocol_s *pr_) {
|
|
6879
6879
|
#ifndef __MINGW32__
|
6880
6880
|
fio_cluster_data_cleanup(1);
|
6881
6881
|
#endif
|
6882
|
-
|
6882
|
+
fio_kill(getpid(), SIGINT);
|
6883
6883
|
}
|
6884
6884
|
}
|
6885
6885
|
if (c->msg)
|
@@ -7155,7 +7155,7 @@ static void fio_cluster_on_connect(intptr_t uuid, void *udata) {
|
|
7155
7155
|
static void fio_cluster_on_fail(intptr_t uuid, void *udata) {
|
7156
7156
|
FIO_LOG_FATAL("(facil.io) unknown cluster connection error");
|
7157
7157
|
perror(" errno");
|
7158
|
-
|
7158
|
+
fio_kill(fio_parent_pid(), SIGINT);
|
7159
7159
|
fio_stop();
|
7160
7160
|
// exit(errno ? errno : 1);
|
7161
7161
|
(void)udata;
|
data/ext/iodine_ext/fio.h
CHANGED
@@ -263,10 +263,12 @@ Version and helper macros
|
|
263
263
|
#define pipe(fds) _pipe(fds, 65536, _O_BINARY)
|
264
264
|
|
265
265
|
int fork(void);
|
266
|
-
int
|
266
|
+
int fio_kill(int, int);
|
267
267
|
ssize_t pread(int, void*, size_t, off_t);
|
268
268
|
ssize_t pwrite(int, const void *, size_t, off_t);
|
269
269
|
int fio_osffd4fd(unsigned int);
|
270
|
+
#else
|
271
|
+
#define fio_kill kill
|
270
272
|
#endif
|
271
273
|
|
272
274
|
/* *****************************************************************************
|
@@ -523,7 +525,7 @@ FIO_LOG2STDERR(const char *format, ...) {
|
|
523
525
|
if (!(ptr)) { \
|
524
526
|
FIO_LOG_FATAL("memory allocation error "__FILE__ \
|
525
527
|
":" FIO_MACRO2STR(__LINE__)); \
|
526
|
-
|
528
|
+
fio_kill(0, SIGINT); \
|
527
529
|
exit(errno); \
|
528
530
|
}
|
529
531
|
#endif
|
@@ -6048,7 +6050,7 @@ FIO_NAME(_insert_or_overwrite_)(FIO_NAME(s) * set, FIO_SET_HASH_TYPE hash_value,
|
|
6048
6050
|
pos->hash = hash_value;
|
6049
6051
|
pos->pos->hash = hash_value;
|
6050
6052
|
FIO_SET_COPY(pos->pos->obj, obj);
|
6051
|
-
|
6053
|
+
|
6052
6054
|
return pos->pos->obj;
|
6053
6055
|
}
|
6054
6056
|
|
data/ext/iodine_ext/http.c
CHANGED
@@ -922,7 +922,7 @@ intptr_t http_listen(const char *port, const char *binding,
|
|
922
922
|
if (arg_settings.on_request == NULL) {
|
923
923
|
FIO_LOG_ERROR("http_listen requires the .on_request parameter "
|
924
924
|
"to be set\n");
|
925
|
-
|
925
|
+
fio_kill(0, SIGINT);
|
926
926
|
exit(11);
|
927
927
|
}
|
928
928
|
|
@@ -852,7 +852,7 @@ FIO_IGNORE_MACRO(struct redis_engine_create_args args) {
|
|
852
852
|
if (getpid() != fio_parent_pid()) {
|
853
853
|
FIO_LOG_FATAL("(redis) Redis engine initialization can only "
|
854
854
|
"be performed in the Root process.");
|
855
|
-
|
855
|
+
fio_kill(0, SIGINT);
|
856
856
|
fio_stop();
|
857
857
|
return NULL;
|
858
858
|
}
|
data/lib/iodine/version.rb
CHANGED
data/lib/rack/handler/iodine.rb
CHANGED
@@ -1,35 +1,35 @@
|
|
1
|
-
require 'iodine' unless defined?(::Iodine::VERSION)
|
2
|
-
|
3
|
-
module Iodine
|
4
|
-
# Iodine's {Iodine::Rack} module provides a Rack complient interface (connecting Iodine to Rack) for an HTTP and Websocket Server.
|
5
|
-
module Rack
|
6
|
-
|
7
|
-
# Runs a Rack app, as par the Rack handler requirements.
|
8
|
-
def self.run(app, options = {})
|
9
|
-
# nested applications... is that a thing?
|
10
|
-
Iodine.listen(service: :http, handler: app, port: options[:Port], address: options[:Host])
|
11
|
-
|
12
|
-
# start Iodine
|
13
|
-
Iodine.start
|
14
|
-
|
15
|
-
true
|
16
|
-
end
|
17
|
-
|
18
|
-
# patches an assumption by Rack, issue #98 code donated by @Shelvak (Néstor Coppi)
|
19
|
-
def self.shutdown
|
20
|
-
Iodine.stop
|
21
|
-
end
|
22
|
-
|
23
|
-
IODINE_RACK_LOADED = true
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
ENV['RACK_HANDLER'] ||= 'iodine'
|
28
|
-
|
29
|
-
begin
|
30
|
-
if defined?(::Rackup::Handler)
|
31
|
-
::Rackup::Handler.register('iodine', Iodine::Rack)
|
32
|
-
::Rackup::Handler.register('Iodine', Iodine::Rack)
|
33
|
-
end
|
34
|
-
rescue StandardError
|
35
|
-
end
|
1
|
+
require 'iodine' unless defined?(::Iodine::VERSION)
|
2
|
+
|
3
|
+
module Iodine
|
4
|
+
# Iodine's {Iodine::Rack} module provides a Rack complient interface (connecting Iodine to Rack) for an HTTP and Websocket Server.
|
5
|
+
module Rack
|
6
|
+
|
7
|
+
# Runs a Rack app, as par the Rack handler requirements.
|
8
|
+
def self.run(app, options = {})
|
9
|
+
# nested applications... is that a thing?
|
10
|
+
Iodine.listen(service: :http, handler: app, port: options[:Port], address: options[:Host])
|
11
|
+
|
12
|
+
# start Iodine
|
13
|
+
Iodine.start
|
14
|
+
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
# patches an assumption by Rack, issue #98 code donated by @Shelvak (Néstor Coppi)
|
19
|
+
def self.shutdown
|
20
|
+
Iodine.stop
|
21
|
+
end
|
22
|
+
|
23
|
+
IODINE_RACK_LOADED = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
ENV['RACK_HANDLER'] ||= 'iodine'
|
28
|
+
|
29
|
+
begin
|
30
|
+
if defined?(::Rackup::Handler)
|
31
|
+
::Rackup::Handler.register('iodine', Iodine::Rack)
|
32
|
+
::Rackup::Handler.register('Iodine', Iodine::Rack)
|
33
|
+
end
|
34
|
+
rescue StandardError
|
35
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: isomorfeus-iodine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Biedermann
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rackup
|
@@ -275,7 +275,7 @@ metadata:
|
|
275
275
|
github_repo: ssh://github.com/isomorfeus/gems
|
276
276
|
source_code_uri: https://github.com/isomorfeus/isomorfeus-iodine
|
277
277
|
post_install_message: |-
|
278
|
-
Thank you for installing Iodine 0.8.
|
278
|
+
Thank you for installing Iodine 0.8.1.
|
279
279
|
Remember: if iodine supports your business, it's only fair to give value back (code contributions / donations) to Bo, see https://github.com/boazsegev/iodine
|
280
280
|
rdoc_options: []
|
281
281
|
require_paths:
|
@@ -298,7 +298,7 @@ requirements:
|
|
298
298
|
- Ruby >= 2.5.0 recommended.
|
299
299
|
- TLS requires OpenSSL >= 1.1.0.
|
300
300
|
- Or Windows with Ruby >= 3.0.0 build with MingW and MingW as compiler.
|
301
|
-
rubygems_version: 3.
|
301
|
+
rubygems_version: 3.4.0.dev
|
302
302
|
signing_key:
|
303
303
|
specification_version: 4
|
304
304
|
summary: iodine build for Isomorfeus
|