iodine 0.3.6 → 0.4.0
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.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -0
- data/LIMITS.md +25 -0
- data/README.md +39 -80
- data/SPEC-Websocket-Draft.md +129 -4
- data/bin/echo +2 -2
- data/bin/http-hello +1 -0
- data/bin/updated api +113 -0
- data/bin/ws-echo +0 -1
- data/examples/broadcast.ru +56 -0
- data/examples/echo.ru +57 -0
- data/examples/hello.ru +30 -0
- data/examples/redis.ru +69 -0
- data/examples/shootout.ru +53 -0
- data/exe/iodine +2 -80
- data/ext/iodine/defer.c +11 -5
- data/ext/iodine/empty.h +26 -0
- data/ext/iodine/evio.h +1 -1
- data/ext/iodine/facil.c +103 -61
- data/ext/iodine/facil.h +20 -12
- data/ext/iodine/fio_dict.c +446 -0
- data/ext/iodine/fio_dict.h +90 -0
- data/ext/iodine/fio_hash_table.h +370 -0
- data/ext/iodine/fio_list.h +30 -3
- data/ext/iodine/http.c +169 -37
- data/ext/iodine/http.h +33 -10
- data/ext/iodine/http1.c +78 -42
- data/ext/iodine/http_request.c +6 -0
- data/ext/iodine/http_request.h +3 -0
- data/ext/iodine/http_response.c +43 -11
- data/ext/iodine/iodine.c +380 -0
- data/ext/iodine/iodine.h +62 -0
- data/ext/iodine/iodine_helpers.c +235 -0
- data/ext/iodine/iodine_helpers.h +13 -0
- data/ext/iodine/iodine_http.c +409 -241
- data/ext/iodine/iodine_http.h +7 -14
- data/ext/iodine/iodine_protocol.c +626 -0
- data/ext/iodine/iodine_protocol.h +13 -0
- data/ext/iodine/iodine_pubsub.c +646 -0
- data/ext/iodine/iodine_pubsub.h +27 -0
- data/ext/iodine/iodine_websockets.c +796 -0
- data/ext/iodine/iodine_websockets.h +19 -0
- data/ext/iodine/pubsub.c +544 -0
- data/ext/iodine/pubsub.h +215 -0
- data/ext/iodine/random.c +4 -4
- data/ext/iodine/rb-call.c +1 -5
- data/ext/iodine/rb-defer.c +3 -20
- data/ext/iodine/rb-rack-io.c +22 -22
- data/ext/iodine/rb-rack-io.h +3 -4
- data/ext/iodine/rb-registry.c +111 -118
- data/ext/iodine/redis_connection.c +277 -0
- data/ext/iodine/redis_connection.h +77 -0
- data/ext/iodine/redis_engine.c +398 -0
- data/ext/iodine/redis_engine.h +68 -0
- data/ext/iodine/resp.c +842 -0
- data/ext/iodine/resp.h +253 -0
- data/ext/iodine/sock.c +26 -12
- data/ext/iodine/sock.h +14 -3
- data/ext/iodine/spnlock.inc +19 -2
- data/ext/iodine/websockets.c +299 -11
- data/ext/iodine/websockets.h +159 -6
- data/lib/iodine.rb +104 -1
- data/lib/iodine/cli.rb +106 -0
- data/lib/iodine/monkeypatch.rb +40 -0
- data/lib/iodine/pubsub.rb +70 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +12 -0
- data/lib/rack/handler/iodine.rb +33 -7
- metadata +35 -7
- data/ext/iodine/iodine_core.c +0 -760
- data/ext/iodine/iodine_core.h +0 -79
- data/ext/iodine/iodine_websocket.c +0 -551
- data/ext/iodine/iodine_websocket.h +0 -22
- data/lib/iodine/http.rb +0 -4
data/bin/echo
CHANGED
@@ -33,7 +33,7 @@ class EchoProtocol
|
|
33
33
|
# `on_message` has a 1Kb buffer that recycles itself for memory optimization.
|
34
34
|
def on_message(buffer)
|
35
35
|
# writing will never block and will use a buffer written in C when needed.
|
36
|
-
write "Echo: #{buffer}"
|
36
|
+
write! "Echo: #{buffer}"
|
37
37
|
puts buffer.dump
|
38
38
|
close if buffer =~ /^bye[\r\n]/i
|
39
39
|
end
|
@@ -41,6 +41,6 @@ end
|
|
41
41
|
|
42
42
|
# create the server object and setup any settings we might need.
|
43
43
|
Iodine.listen 3000, EchoProtocol
|
44
|
-
|
44
|
+
Iodine.threads = 10
|
45
45
|
# server.processes = 1
|
46
46
|
Iodine.start
|
data/bin/http-hello
CHANGED
@@ -19,6 +19,7 @@ Iodine::Rack.public = '~/Documents/Scratch'
|
|
19
19
|
count = 2
|
20
20
|
Iodine::Rack.app = proc { |_env| [200, { 'Content-Length'.freeze => '12'.freeze }, ['He11o World!'.freeze]] }
|
21
21
|
puts Iodine::Rack.address
|
22
|
+
Iodine::HTTP.listen app: Iodine::Rack.app, port: "3030", public: '~/Documents/Scratch'
|
22
23
|
Iodine.start
|
23
24
|
|
24
25
|
# puts env.to_a.map { |pair| pair.join(': ') } .join("\n").to_s;
|
data/bin/updated api
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
Dir.chdir(File.expand_path(File.join('..', '..'), __FILE__))
|
4
|
+
puts `rake clean`
|
5
|
+
puts `rake compile`
|
6
|
+
|
7
|
+
require 'benchmark'
|
8
|
+
$LOAD_PATH.unshift File.expand_path(File.join('..', '..', 'lib'), __FILE__)
|
9
|
+
require 'bundler/setup'
|
10
|
+
require 'iodine'
|
11
|
+
require 'rack'
|
12
|
+
|
13
|
+
class WSEcho
|
14
|
+
def self.call(env)
|
15
|
+
if env['upgrade.websocket?'.freeze] # && env['HTTP_UPGRADE'.freeze] =~ /websocket/i
|
16
|
+
env['upgrade.websocket'.freeze] = WSEcho
|
17
|
+
return [0, {}, []]
|
18
|
+
end
|
19
|
+
out = "ENV:\r\n#{env.to_a.map { |h| "#{h[0]}: #{h[1]}" } .join "\n"}\n"
|
20
|
+
request = Rack::Request.new(env)
|
21
|
+
out += "\nRequest Path: #{request.path_info}\nParams:\r\n#{request.params.to_a.map { |h| "#{h[0]}: #{h[1]}" } .join "\n"}\n" unless request.params.empty?
|
22
|
+
[200, { 'Content-Length' => out.length, 'Content-Type' => 'text/plain; charset=UTF-8;' }, [out]]
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_open
|
26
|
+
puts 'We have a websocket connection'
|
27
|
+
Iodine::Websocket.defer(uuid) { |ws| puts "This websocket's uuid is #{ws.uuid}" }
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_close
|
31
|
+
puts "Bye Bye... only #{count} left..."
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_shutdown
|
35
|
+
puts "I'm shutting down #{self}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_ready
|
39
|
+
puts "on_ready called for #{self}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_message(data)
|
43
|
+
puts "got message: #{data}"
|
44
|
+
write data
|
45
|
+
write (data * 16_384) if data =~ /^multi me$/
|
46
|
+
end
|
47
|
+
|
48
|
+
def echo(data)
|
49
|
+
write "echo: #{data}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# create the server object and setup any settings we might need.
|
54
|
+
Iodine.threads ||= 4
|
55
|
+
Iodine.processes ||= 1
|
56
|
+
count = 2
|
57
|
+
|
58
|
+
Iodine::HTTP.listen app: WSEcho, log: true, port: 3000
|
59
|
+
Iodine.start
|
60
|
+
# server.on_http= Proc.new do |env|
|
61
|
+
# # [200, {"Content-Length".freeze => "12".freeze}, ["Hello World!".freeze]];
|
62
|
+
# if env["HTTP_UPGRADE".freeze] =~ /websocket/i.freeze
|
63
|
+
# env['iodine.websocket'.freeze] = WSEcho.new
|
64
|
+
# [0,{}, []]
|
65
|
+
# else
|
66
|
+
# req = Rack::Request.new env
|
67
|
+
# res = Rack::Response.new
|
68
|
+
# res.write "Hello World!".freeze
|
69
|
+
# res.to_a
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
|
73
|
+
# server.on_start do
|
74
|
+
# server.run_every(1000) {puts "#{server.connection_count} clients connected."}
|
75
|
+
# end
|
76
|
+
|
77
|
+
# puts "Press enter to start (#{Process.pid})"
|
78
|
+
# gets
|
79
|
+
|
80
|
+
# def nag
|
81
|
+
# puts `ab -n 200000 -c 2000 -k http://127.0.0.1:3000/`
|
82
|
+
# sleep 2
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# nag while true
|
86
|
+
#
|
87
|
+
# def nag
|
88
|
+
# puts `wrk -c2000 -d10 -t4 http://localhost:3000/`
|
89
|
+
# sleep 3
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# nag while true
|
93
|
+
|
94
|
+
# ab -n 100000 -c 200 -k http://127.0.0.1:3000/
|
95
|
+
# ab -n 100000 -c 4000 -k http://127.0.0.1:3000/
|
96
|
+
# ab -n 1000000 -c 20000 -k http://127.0.0.1:3000/
|
97
|
+
# ~/ruby/wrk/wrk -c400 -d10 -t12 http://localhost:3000/
|
98
|
+
# wrk -c200 -d4 -t12 http://localhost:3000/
|
99
|
+
# ab -n 2000 -c 20 -H "Connection: close" http://127.0.0.1:3000/
|
100
|
+
# RACK_ENV="production" rackup -p 3000 -s iodine
|
101
|
+
|
102
|
+
# thor --amount 5000 ws://localhost:3000/echo
|
103
|
+
# thor --amount 5000 ws://localhost:3000/broadcast
|
104
|
+
|
105
|
+
# ws = new WebSocket("ws://localhost:3000"); ws.onmessage = function(e) {console.log("Got message!"); console.log(e.data);}; ws.onclose = function(e) {console.log("closed")}; ws.onopen = function(e) {ws.send("hi");};
|
106
|
+
# for(i = 0; i< 256; i++) {
|
107
|
+
# ws = new WebSocket("ws://localhost:3000");
|
108
|
+
# ws.onmessage = function(e) {console.log("Got message!"); console.log(e.data); e.target.close(); };
|
109
|
+
# ws.onclose = function(e) {console.log("closed")};
|
110
|
+
# ws.onopen = function(e) {e.target.send("hi");};
|
111
|
+
# };
|
112
|
+
# ws = new WebSocket("ws://localhost:3000"); ws.onmessage = function(e) {console.log("Got message " + e.data.length + " bytes long"); for(var i = 0; i < e.data.length ; i += 4) {if (e.data.slice(i, i+4) != "text") {console.log( "incoming message corrupted? ", e.data.slice(i, i+4) ); return;};}; }; ws.onclose = function(e) {console.log("closed")}; ws.onopen = function(e) {ws.send("hi");};
|
113
|
+
# str = "text"; function size_test() { if(ws.readyState != 1) return; if(str.length > 4194304) {console.log("str reached 4MiB!"); str = "test"; return;}; ws.send(str); str = str + str; window.setTimeout(size_test, 150); }; size_test();
|
data/bin/ws-echo
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
# This is a Websocket echo application.
|
2
|
+
#
|
3
|
+
# Running this application from the command line is eacy with:
|
4
|
+
#
|
5
|
+
# iodine hello.ru
|
6
|
+
#
|
7
|
+
# Or, in single thread and single process:
|
8
|
+
#
|
9
|
+
# iodine -t 1 -w 1 hello.ru
|
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' => '32' },
|
22
|
+
['Please connect 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.
|
29
|
+
if(env['upgrade.websocket?'.freeze])
|
30
|
+
env['upgrade.websocket'.freeze] = WebsocketBroadcast
|
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
|
+
class WebsocketBroadcast
|
40
|
+
# seng a message to new clients.
|
41
|
+
def on_open
|
42
|
+
puts self
|
43
|
+
write "Welcome to our echo service!"
|
44
|
+
end
|
45
|
+
# send a message, letting the client know the server is suggunt down.
|
46
|
+
def on_shutdown
|
47
|
+
write "Server shutting down. Goodbye."
|
48
|
+
end
|
49
|
+
# perform the echo
|
50
|
+
def on_message data
|
51
|
+
write data
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# this function call links our HelloWorld application with Rack
|
56
|
+
run MyHTTPRouter
|
data/examples/echo.ru
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# This is a Websocket echo application.
|
2
|
+
#
|
3
|
+
# Running this application from the command line is eacy with:
|
4
|
+
#
|
5
|
+
# iodine hello.ru
|
6
|
+
#
|
7
|
+
# Or, in single thread and single process:
|
8
|
+
#
|
9
|
+
# iodine -t 1 -w 1 hello.ru
|
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' => '32' },
|
22
|
+
['Please connect 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.
|
29
|
+
if(env['upgrade.websocket?'.freeze])
|
30
|
+
env['upgrade.websocket'.freeze] = WebsocketEcho
|
31
|
+
return [0, {}, []]
|
32
|
+
return WS_RESPONSE
|
33
|
+
end
|
34
|
+
# simply return the RESPONSE object, no matter what request was received.
|
35
|
+
HTTP_RESPONSE
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# A simple Websocket Callback Object.
|
40
|
+
class WebsocketEcho
|
41
|
+
# seng a message to new clients.
|
42
|
+
def on_open
|
43
|
+
p self
|
44
|
+
write "Welcome to our echo service!"
|
45
|
+
end
|
46
|
+
# send a message, letting the client know the server is suggunt down.
|
47
|
+
def on_shutdown
|
48
|
+
write "Server shutting down. Goodbye."
|
49
|
+
end
|
50
|
+
# perform the echo
|
51
|
+
def on_message data
|
52
|
+
write data
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# this function call links our HelloWorld application with Rack
|
57
|
+
run MyHTTPRouter
|
data/examples/hello.ru
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# This is a simple Hello World Rack application
|
2
|
+
#
|
3
|
+
# Running this application from the command line is eacy with:
|
4
|
+
#
|
5
|
+
# iodine hello.ru
|
6
|
+
#
|
7
|
+
# Or, in single thread and single process:
|
8
|
+
#
|
9
|
+
# iodine -t 1 -w 1 hello.ru
|
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
|
+
module HelloWorld
|
17
|
+
# This is the HTTP response object according to the Rack specification.
|
18
|
+
RESPONSE = [200, { 'Content-Type' => 'text/html',
|
19
|
+
'Content-Length' => '32' },
|
20
|
+
['Please connect using websockets.']]
|
21
|
+
|
22
|
+
# this is function will be called by the Rack server (iodine) for every request.
|
23
|
+
def self.call env
|
24
|
+
# simply return the RESPONSE object, no matter what request was received.
|
25
|
+
RESPONSE
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# this function call links our HelloWorld application with Rack
|
30
|
+
run HelloWorld
|
data/examples/redis.ru
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# This example implements a Redis pub/sub engine according to the Iodine::PubSub::Engine specifications.
|
2
|
+
#
|
3
|
+
# The engine code is locates at examples/redis_pubsub.rb and it requires the hiredis gem.
|
4
|
+
#
|
5
|
+
# Run this applications on two ports, in two terminals to see the synchronization is action
|
6
|
+
#
|
7
|
+
# REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3000 redis.ru
|
8
|
+
# REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3030 redis.ru
|
9
|
+
#
|
10
|
+
require 'uri'
|
11
|
+
# initialize the Redis engine for each Iodine process by using `Iodine.run`
|
12
|
+
if ENV["REDIS_URL"]
|
13
|
+
uri = URI(ENV["REDIS_URL"])
|
14
|
+
Iodine.default_pubsub = Iodine::PubSub::RedisEngine.new(uri.host, uri.port, 0, uri.password)
|
15
|
+
else
|
16
|
+
puts "* No Redis! pub/sub is limited to the process cluster."
|
17
|
+
end
|
18
|
+
puts "The default Pub/Sub engine is:", Iodine.default_pubsub
|
19
|
+
|
20
|
+
# A simple router - Checks for Websocket Upgrade and answers HTTP.
|
21
|
+
module MyHTTPRouter
|
22
|
+
# This is the HTTP response object according to the Rack specification.
|
23
|
+
HTTP_RESPONSE = [200, { 'Content-Type' => 'text/html',
|
24
|
+
'Content-Length' => '32' },
|
25
|
+
['Please connect using websockets.']]
|
26
|
+
|
27
|
+
WS_RESPONSE = [0, {}, []]
|
28
|
+
|
29
|
+
# this is function will be called by the Rack server (iodine) for every request.
|
30
|
+
def self.call env
|
31
|
+
# check if this is an upgrade request.
|
32
|
+
if(env['upgrade.websocket?'.freeze])
|
33
|
+
env['upgrade.websocket'.freeze] = WS_RedisPubSub.new(env['PATH_INFO'] ? env['PATH_INFO'][1..-1] : "guest")
|
34
|
+
return [0, {}, []]
|
35
|
+
return WS_RESPONSE
|
36
|
+
end
|
37
|
+
# simply return the RESPONSE object, no matter what request was received.
|
38
|
+
HTTP_RESPONSE
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# A simple Websocket Callback Object.
|
43
|
+
class WS_RedisPubSub
|
44
|
+
def initialize name
|
45
|
+
@name = name
|
46
|
+
end
|
47
|
+
# seng a message to new clients.
|
48
|
+
def on_open
|
49
|
+
subscribe channel: "chat"
|
50
|
+
# let everyone know we arrived
|
51
|
+
# publish channel: "chat", message: "#{@name} entered the chat."
|
52
|
+
end
|
53
|
+
# send a message, letting the client know the server is suggunt down.
|
54
|
+
def on_shutdown
|
55
|
+
write "Server shutting down. Goodbye."
|
56
|
+
end
|
57
|
+
# perform the echo
|
58
|
+
def on_message data
|
59
|
+
publish channel: "chat", message: "#{@name}: #{data}"
|
60
|
+
end
|
61
|
+
def on_close
|
62
|
+
# let everyone know we left
|
63
|
+
publish channel: "chat", message: "#{@name} left the chat."
|
64
|
+
# we don't need to unsubscribe, subscriptions are cleared automatically once the connection is closed.
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# this function call links our HelloWorld application with Rack
|
69
|
+
run MyHTTPRouter
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'iodine'
|
2
|
+
|
3
|
+
# ON_IDLE = proc { Iodine::Base.db_print_registry ; Iodine.on_idle(&ON_IDLE) }
|
4
|
+
# ON_IDLE.call
|
5
|
+
|
6
|
+
class ShootoutApp
|
7
|
+
# the default HTTP response
|
8
|
+
def self.call(env)
|
9
|
+
if env['upgrade.websocket?'.freeze] # && env['HTTP_UPGRADE'.freeze] =~ /websocket/i
|
10
|
+
env['upgrade.websocket'.freeze] = ShootoutApp.new
|
11
|
+
return [0, {}, []]
|
12
|
+
end
|
13
|
+
out = "ENV:\r\n#{env.to_a.map { |h| "#{h[0]}: #{h[1]}" } .join "\n"}\n"
|
14
|
+
request = Rack::Request.new(env)
|
15
|
+
out += "\nRequest Path: #{request.path_info}\nParams:\r\n#{request.params.to_a.map { |h| "#{h[0]}: #{h[1]}" } .join "\n"}\n" unless request.params.empty?
|
16
|
+
[200, { 'Content-Length' => out.length, 'Content-Type' => 'text/plain; charset=UTF-8;' }, [out]]
|
17
|
+
end
|
18
|
+
# We'll base the shootout on the internal Pub/Sub service.
|
19
|
+
# It's slower than writing to every socket a pre-parsed message, but it's closer
|
20
|
+
# to real-life implementations.
|
21
|
+
def on_open
|
22
|
+
subscribe channel: "shootout"
|
23
|
+
end
|
24
|
+
def on_message data
|
25
|
+
if data[0] == 'b' # binary
|
26
|
+
publish(channel: "shootout", message: data)
|
27
|
+
data[0] = 'r'
|
28
|
+
write data
|
29
|
+
return
|
30
|
+
end
|
31
|
+
cmd, payload = JSON(data).values_at('type', 'payload')
|
32
|
+
if cmd == 'echo'
|
33
|
+
write({type: 'echo', payload: payload}.to_json)
|
34
|
+
else
|
35
|
+
# data = {type: 'broadcast', payload: payload}.to_json
|
36
|
+
# broadcast :push2client, data
|
37
|
+
publish(channel: "shootout", message: ({type: 'broadcast', payload: payload}.to_json))
|
38
|
+
write({type: "broadcastResult", payload: payload}.to_json)
|
39
|
+
end
|
40
|
+
rescue
|
41
|
+
puts "Incoming message format error - not JSON?"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
run ShootoutApp
|
46
|
+
#
|
47
|
+
# def cycle
|
48
|
+
# puts `websocket-bench broadcast ws://127.0.0.1:3000/ --concurrent 10 --sample-size 100 --server-type binary --step-size 1000 --limit-percentile 95 --limit-rtt 250ms --initial-clients 1000`
|
49
|
+
# sleep(2)
|
50
|
+
# puts `wrk -c4000 -d15 -t12 http://localhost:3000/`
|
51
|
+
# true
|
52
|
+
# end
|
53
|
+
# sleep(10) while cycle
|
data/exe/iodine
CHANGED
@@ -1,83 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'iodine'
|
4
|
-
require 'rack'
|
3
|
+
require 'iodine/cli'
|
5
4
|
|
6
|
-
|
7
|
-
puts <<-EOS
|
8
|
-
|
9
|
-
Iodine's HTTP/Websocket server version #{Iodine::VERSION}
|
10
|
-
|
11
|
-
Use:
|
12
|
-
|
13
|
-
iodine <options> <filename>
|
14
|
-
|
15
|
-
Both <options> and <filename> are optional.
|
16
|
-
|
17
|
-
Available options:
|
18
|
-
-p Port number. Default: 3000.
|
19
|
-
-t Number of threads. Default: half of the CPU core count.
|
20
|
-
-w Number of worker processes. half of the CPU core count.
|
21
|
-
-www Public folder for static file serving. Default: nil (none).
|
22
|
-
-v Log responses.
|
23
|
-
-q Never log responses.
|
24
|
-
-warmup Warmup invokes autoloading (lazy loading) during server startup.
|
25
|
-
-tout HTTP inactivity connection timeout. Default: 5.
|
26
|
-
-maxbd Maximum Mb per HTTP message (max body size). Default: 50Mib.
|
27
|
-
-maxms Maximum Bytes per Websocket message. Default: 250Kib.
|
28
|
-
-ping Websocket ping interval in seconds. Default: 40 seconds.
|
29
|
-
<filename> Defaults to: config.ru
|
30
|
-
|
31
|
-
Example:
|
32
|
-
|
33
|
-
iodine -p 80
|
34
|
-
|
35
|
-
iodine -p 8080 path/to/app/conf.ru
|
36
|
-
|
37
|
-
iodine -p 8080 -w 4 -t 16
|
38
|
-
|
39
|
-
EOS
|
40
|
-
exit(0)
|
41
|
-
end
|
42
|
-
|
43
|
-
app, opt = nil, nil
|
44
|
-
filename = (ARGV[-2].to_s[0] != '-' && ARGV[-1].to_s[0] != '-' && ARGV[-1]) || 'config.ru'
|
45
|
-
|
46
|
-
begin
|
47
|
-
app, opt = Rack::Builder.parse_file filename
|
48
|
-
rescue
|
49
|
-
if ARGV.index('-www') && ARGV[ARGV.index('-www') + 1]
|
50
|
-
puts "WARNING: Ruby application not found - missing #{filename}?"
|
51
|
-
puts " Running only static file service."
|
52
|
-
app = Rack::Builder.new do
|
53
|
-
run lambda { |env| [404, {'Content-Type' => 'text/plain', 'Content-Length'.freeze => '21'.freeze}, ['Error 404 - Not Found']] }
|
54
|
-
end
|
55
|
-
opt = Rack::Server::Options.new.parse!([])
|
56
|
-
p app, opt
|
57
|
-
else
|
58
|
-
puts "ERROR: Ruby application not found - missing #{filename}? For help run:"
|
59
|
-
puts " iodine -?"
|
60
|
-
exit(0)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
if ARGV.index('-maxbd') && ARGV[ARGV.index('-maxbd') + 1]
|
65
|
-
Iodine::Rack.max_body_size = ARGV[ARGV.index('-maxbd') + 1].to_i
|
66
|
-
end
|
67
|
-
if ARGV.index('-maxms') && ARGV[ARGV.index('-maxms') + 1]
|
68
|
-
Iodine::Rack.max_msg_size = ARGV[ARGV.index('-maxms') + 1].to_i
|
69
|
-
end
|
70
|
-
if ARGV.index('-ping') && ARGV[ARGV.index('-ping') + 1]
|
71
|
-
Iodine::Rack.ws_timeout = ARGV[ARGV.index('-ping') + 1].to_i
|
72
|
-
end
|
73
|
-
if ARGV.index('-www') && ARGV[ARGV.index('-www') + 1]
|
74
|
-
Iodine::Rack.public = ARGV[ARGV.index('-www') + 1]
|
75
|
-
end
|
76
|
-
if ARGV.index('-tout') && ARGV[ARGV.index('-tout') + 1]
|
77
|
-
Iodine::Rack.timeout = ARGV[ARGV.index('-tout') + 1].to_i
|
78
|
-
puts "WARNNING: Iodine::Rack.timeout set to 0 (ignored, timeout will be ~5 minutes)."
|
79
|
-
end
|
80
|
-
Iodine::Rack.log = true if ARGV.index('-v')
|
81
|
-
Iodine::Rack.log = false if ARGV.index('-q')
|
82
|
-
Iodine.warmup if ARGV.index('-warmup')
|
83
|
-
Iodine::Rack.run(app, opt)
|
5
|
+
Iodine::Base::CLI.call
|