isomorfeus-iodine 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|