iodine 0.7.41 → 0.7.45
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/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +24 -0
- data/README.md +2 -2
- data/SPEC-PubSub-Draft.md +89 -47
- data/SPEC-WebSocket-Draft.md +92 -55
- data/examples/async_task.ru +92 -0
- data/ext/iodine/extconf.rb +21 -16
- data/ext/iodine/fio.c +1108 -162
- data/ext/iodine/fio.h +49 -13
- data/ext/iodine/fio_cli.c +1 -1
- data/ext/iodine/fio_tls_missing.c +8 -0
- data/ext/iodine/fio_tls_openssl.c +8 -0
- data/ext/iodine/fio_tmpfile.h +13 -1
- data/ext/iodine/fiobj_data.c +6 -4
- data/ext/iodine/fiobj_data.h +2 -1
- data/ext/iodine/fiobj_hash.c +32 -6
- data/ext/iodine/fiobj_mustache.c +9 -0
- data/ext/iodine/fiobj_numbers.c +86 -8
- data/ext/iodine/fiobj_str.c +24 -11
- data/ext/iodine/fiobject.c +1 -1
- data/ext/iodine/fiobject.h +5 -3
- data/ext/iodine/http.c +66 -10
- data/ext/iodine/http1.c +2 -1
- data/ext/iodine/http1_parser.h +1065 -103
- data/ext/iodine/http_internal.c +1 -0
- data/ext/iodine/http_internal.h +4 -2
- data/ext/iodine/iodine.c +66 -1
- data/ext/iodine/iodine.h +3 -0
- data/ext/iodine/iodine_caller.c +48 -8
- data/ext/iodine/iodine_connection.c +24 -8
- data/ext/iodine/iodine_http.c +32 -8
- data/ext/iodine/iodine_mustache.c +2 -4
- data/ext/iodine/iodine_rack_io.c +21 -0
- data/ext/iodine/iodine_tcp.c +14 -0
- data/ext/iodine/iodine_tls.c +8 -0
- data/ext/iodine/mustache_parser.h +4 -0
- data/ext/iodine/redis_engine.c +14 -11
- data/ext/iodine/websockets.c +7 -3
- data/iodine.gemspec +5 -4
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +6 -0
- metadata +15 -13
@@ -0,0 +1,92 @@
|
|
1
|
+
# This is a task scheduling WebSocket push example application.
|
2
|
+
#
|
3
|
+
# Benchmark HTTPP with `ab` or `wrk` (a 5 seconds benchmark with 2000 concurrent clients):
|
4
|
+
#
|
5
|
+
# ab -c 2000 -t 5 -n 1000000 -k http://127.0.0.1:3000/
|
6
|
+
# wrk -c2000 -d5 -t12 http://localhost:3000/
|
7
|
+
#
|
8
|
+
# Test websocket tasks using the browser. For example:
|
9
|
+
# ws = new WebSocket("ws://localhost:3000/userID"); ws.onmessage = function(e) {console.log(e.data);}; ws.onclose = function(e) {console.log("closed")};
|
10
|
+
# ws.onopen = function(e) {ws.send(JSON.stringify({'task': 'echo', 'data': 'Hello!'}));};
|
11
|
+
require 'iodine'
|
12
|
+
require 'json'
|
13
|
+
|
14
|
+
TASK_PUBLISHING_ENGINE = Iodine::PubSub::PROCESS
|
15
|
+
|
16
|
+
# This module handles tasks and send them back to the frontend
|
17
|
+
module TaskHandler
|
18
|
+
def echo msg
|
19
|
+
msg = Iodine::JSON.parse(msg, symbolize_names: true)
|
20
|
+
publish_to = msg.delete(:from)
|
21
|
+
Iodine.publish(publish_to, msg.to_json, TASK_PUBLISHING_ENGINE) if publish_to
|
22
|
+
puts "performed 'echo' task"
|
23
|
+
rescue => e
|
24
|
+
puts "JSON task message error? #{e.message} - under attack?"
|
25
|
+
end
|
26
|
+
|
27
|
+
def add msg
|
28
|
+
msg = Iodine::JSON.parse(msg, symbolize_names: true)
|
29
|
+
raise "addition task requires an array of numbers" unless msg[:data].is_a?(Array)
|
30
|
+
msg[:data] = msg[:data].inject(0){|sum,x| sum + x }
|
31
|
+
publish_to = msg.delete(:from)
|
32
|
+
Iodine.publish(publish_to, msg.to_json, TASK_PUBLISHING_ENGINE) if publish_to
|
33
|
+
puts "performed 'add' task"
|
34
|
+
rescue => e
|
35
|
+
puts
|
36
|
+
"JSON task message error? #{e.message} - under attack?"
|
37
|
+
end
|
38
|
+
|
39
|
+
def listen2tasks
|
40
|
+
Iodine.subscribe(:echo) {|ch,msg| TaskHandler.echo(msg) }
|
41
|
+
Iodine.subscribe(:add) {|ch,msg| TaskHandler.add(msg) }
|
42
|
+
end
|
43
|
+
|
44
|
+
extend self
|
45
|
+
end
|
46
|
+
|
47
|
+
module WebsocketClient
|
48
|
+
def on_open client
|
49
|
+
# Pub/Sub directly to the client (or use a block to process the messages)
|
50
|
+
client.subscribe client.env['PATH_INFO'.freeze]
|
51
|
+
end
|
52
|
+
def on_message client, data
|
53
|
+
# Strings and symbol channel names are equivalent.
|
54
|
+
msg = Iodine::JSON.parse(data, symbolize_names: true)
|
55
|
+
raise "no valid task" unless ["echo".freeze, "add".freeze].include? msg[:task]
|
56
|
+
msg[:from] = client.env['PATH_INFO'.freeze]
|
57
|
+
client.publish msg[:task], msg.to_json, TASK_PUBLISHING_ENGINE
|
58
|
+
rescue => e
|
59
|
+
puts "JSON message error? #{e.message}\n\t#{data}\n\t#{msg}"
|
60
|
+
end
|
61
|
+
extend self
|
62
|
+
end
|
63
|
+
|
64
|
+
APP = Proc.new do |env|
|
65
|
+
if env['rack.upgrade?'.freeze] == :websocket
|
66
|
+
env['rack.upgrade'.freeze] = WebsocketClient
|
67
|
+
[0,{}, []] # It's possible to set cookies for the response.
|
68
|
+
elsif env['rack.upgrade?'.freeze] == :sse
|
69
|
+
puts "SSE connections can only receive data from the server, the can't write."
|
70
|
+
env['rack.upgrade'.freeze] = WebsocketClient
|
71
|
+
[0,{}, []] # It's possible to set cookies for the response.
|
72
|
+
else
|
73
|
+
[200, {"Content-Type" => "text/plain"}, ["Send messages with WebSockets using JSON.\ni.e.: {\"task\":\"add\", \"data\":[1,2]}"]]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# test automatically for Redis extensions.
|
78
|
+
if(Iodine::PubSub.default.is_a? Iodine::PubSub::Redis)
|
79
|
+
TASK_PUBLISHING_ENGINE = Iodine::PubSub.default
|
80
|
+
if(ARGV.include? "worker")
|
81
|
+
TaskHandler.listen2tasks
|
82
|
+
Iodine.workers = 1
|
83
|
+
Iodine.threads = 16 if Iodine.threads == 0
|
84
|
+
Iodine.start
|
85
|
+
exit(0)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
TaskHandler.listen2tasks
|
89
|
+
end
|
90
|
+
|
91
|
+
# # or in config.ru
|
92
|
+
run APP
|
data/ext/iodine/extconf.rb
CHANGED
@@ -36,7 +36,10 @@ int main(void) {
|
|
36
36
|
EOS
|
37
37
|
|
38
38
|
# Test for manual selection and then TRY_COMPILE with each polling engine
|
39
|
-
if
|
39
|
+
if Gem.win_platform?
|
40
|
+
puts "skipping polling tests, using WSAPOLL on Windows"
|
41
|
+
$defs << "-DFIO_ENGINE_WSAPOLL"
|
42
|
+
elsif ENV['FIO_POLL']
|
40
43
|
puts "skipping polling tests, enforcing manual selection of: poll"
|
41
44
|
$defs << "-DFIO_ENGINE_POLL"
|
42
45
|
elsif ENV['FIO_FORCE_POLL']
|
@@ -64,9 +67,10 @@ end
|
|
64
67
|
|
65
68
|
iodine_test_polling_support()
|
66
69
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
+
unless Gem.win_platform?
|
71
|
+
# Test for OpenSSL version equal to 1.0.0 or greater.
|
72
|
+
unless ENV['NO_SSL'] || ENV['NO_TLS'] || ENV["DISABLE_SSL"]
|
73
|
+
OPENSSL_TEST_CODE = <<EOS
|
70
74
|
\#include <openssl/bio.h>
|
71
75
|
\#include <openssl/err.h>
|
72
76
|
\#include <openssl/ssl.h>
|
@@ -84,18 +88,19 @@ int main(void) {
|
|
84
88
|
}
|
85
89
|
EOS
|
86
90
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
91
|
+
dir_config("openssl")
|
92
|
+
begin
|
93
|
+
require 'openssl'
|
94
|
+
rescue LoadError
|
95
|
+
else
|
96
|
+
if have_library('crypto') && have_library('ssl')
|
97
|
+
puts "detected OpenSSL library, testing for version and required functions."
|
98
|
+
if try_compile(OPENSSL_TEST_CODE)
|
99
|
+
$defs << "-DHAVE_OPENSSL"
|
100
|
+
puts "confirmed OpenSSL to be version 1.1.0 or above (#{OpenSSL::OPENSSL_LIBRARY_VERSION})...\n* compiling with HAVE_OPENSSL."
|
101
|
+
else
|
102
|
+
puts "FAILED: OpenSSL version not supported (#{OpenSSL::OPENSSL_LIBRARY_VERSION} is too old)."
|
103
|
+
end
|
99
104
|
end
|
100
105
|
end
|
101
106
|
end
|