iodine 0.7.60 → 0.8.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.
- checksums.yaml +4 -4
- data/.clang-format +15 -0
- data/.rspec +1 -0
- data/.yardopts +1 -3
- data/CHANGELOG.md +132 -12
- data/Gemfile +5 -7
- data/LICENSE.txt +1 -1
- data/README.md +147 -671
- data/Rakefile +9 -16
- data/examples/chatroom.nru +9 -0
- data/examples/client +74 -0
- data/examples/config-hello.nru +9 -0
- data/examples/config-hello.ru +11 -0
- data/examples/config-hijack.ru +13 -0
- data/examples/config-shootout.ru +43 -0
- data/examples/config.nru +120 -0
- data/examples/config.rb +37 -0
- data/examples/config.ru +42 -53
- data/examples/fake +24 -0
- data/examples/hello_neorack +137 -0
- data/examples/routes.nru +29 -0
- data/examples/routes.ru +42 -0
- data/exe/iodine +218 -258
- data/ext/iodine/extconf.rb +27 -100
- data/ext/iodine/fio-stl.h +128336 -0
- data/ext/iodine/fio-stl.md +26396 -0
- data/ext/iodine/iodine.c +213 -1393
- data/ext/iodine/iodine.h +250 -55
- data/ext/iodine/iodine_arg_helper.h +329 -0
- data/ext/iodine/iodine_caller.h +234 -25
- data/ext/iodine/iodine_cli.h +434 -0
- data/ext/iodine/iodine_compression.h +312 -0
- data/ext/iodine/iodine_connection.h +3484 -34
- data/ext/iodine/iodine_core.h +363 -0
- data/ext/iodine/iodine_crypto.h +1441 -0
- data/ext/iodine/iodine_defer.h +225 -4
- data/ext/iodine/iodine_json.h +738 -4
- data/ext/iodine/iodine_listener.h +263 -0
- data/ext/iodine/iodine_log.h +297 -0
- data/ext/iodine/iodine_minimap.h +543 -0
- data/ext/iodine/iodine_mustache.h +461 -4
- data/ext/iodine/iodine_pubsub_eng.h +729 -0
- data/ext/iodine/iodine_pubsub_history.h +547 -0
- data/ext/iodine/iodine_pubsub_msg.h +228 -0
- data/ext/iodine/iodine_redis.h +322 -0
- data/ext/iodine/iodine_store.h +418 -16
- data/ext/iodine/iodine_threads.h +279 -0
- data/ext/iodine/iodine_tls.h +515 -6
- data/ext/iodine/iodine_utils.h +923 -0
- data/iodine.gemspec +37 -42
- data/lib/iodine/benchmark.rb +1690 -0
- data/lib/iodine/documentation.rb +3085 -0
- data/lib/iodine/version.rb +17 -1
- data/lib/iodine.rb +54 -255
- data/logo.svg +36 -0
- data/mustache.md +55 -0
- data/sig/iodine.rbs +4 -0
- metadata +58 -184
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/workflows/ruby.yml +0 -42
- data/.gitignore +0 -21
- data/LIMITS.md +0 -41
- data/SPEC-PubSub-Draft.md +0 -159
- data/SPEC-WebSocket-Draft.md +0 -239
- data/bin/console +0 -22
- data/bin/info.md +0 -353
- data/bin/mustache_bench.rb +0 -100
- data/bin/poc/Gemfile.lock +0 -23
- data/bin/poc/README.md +0 -37
- data/bin/poc/config.ru +0 -66
- data/bin/poc/gemfile +0 -1
- data/bin/poc/www/index.html +0 -57
- data/examples/async_task.ru +0 -92
- data/examples/bates/README.md +0 -3
- data/examples/bates/config.ru +0 -342
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +0 -600
- data/examples/echo.ru +0 -59
- data/examples/etag.ru +0 -16
- data/examples/hello.ru +0 -29
- data/examples/pubsub_engine.ru +0 -81
- data/examples/rack3.ru +0 -12
- data/examples/redis.ru +0 -70
- data/examples/shootout.ru +0 -73
- data/examples/sub-protocols.ru +0 -90
- data/examples/tcp_client.rb +0 -66
- data/examples/x-sendfile.ru +0 -14
- data/ext/iodine/fio.c +0 -11995
- data/ext/iodine/fio.h +0 -6371
- data/ext/iodine/fio_cli.c +0 -431
- data/ext/iodine/fio_cli.h +0 -189
- data/ext/iodine/fio_json_parser.h +0 -688
- data/ext/iodine/fio_siphash.c +0 -157
- data/ext/iodine/fio_siphash.h +0 -37
- data/ext/iodine/fio_tls.h +0 -129
- data/ext/iodine/fio_tls_missing.c +0 -649
- data/ext/iodine/fio_tls_openssl.c +0 -1106
- data/ext/iodine/fio_tmpfile.h +0 -50
- data/ext/iodine/fiobj.h +0 -44
- data/ext/iodine/fiobj4fio.h +0 -21
- data/ext/iodine/fiobj_ary.c +0 -333
- data/ext/iodine/fiobj_ary.h +0 -139
- data/ext/iodine/fiobj_data.c +0 -1187
- data/ext/iodine/fiobj_data.h +0 -167
- data/ext/iodine/fiobj_hash.c +0 -409
- data/ext/iodine/fiobj_hash.h +0 -176
- data/ext/iodine/fiobj_json.c +0 -622
- data/ext/iodine/fiobj_json.h +0 -68
- data/ext/iodine/fiobj_mem.h +0 -71
- data/ext/iodine/fiobj_mustache.c +0 -317
- data/ext/iodine/fiobj_mustache.h +0 -62
- data/ext/iodine/fiobj_numbers.c +0 -344
- data/ext/iodine/fiobj_numbers.h +0 -127
- data/ext/iodine/fiobj_str.c +0 -433
- data/ext/iodine/fiobj_str.h +0 -172
- data/ext/iodine/fiobject.c +0 -620
- data/ext/iodine/fiobject.h +0 -655
- data/ext/iodine/hpack.h +0 -1923
- data/ext/iodine/http.c +0 -2743
- data/ext/iodine/http.h +0 -1002
- data/ext/iodine/http1.c +0 -910
- data/ext/iodine/http1.h +0 -29
- data/ext/iodine/http1_parser.h +0 -878
- data/ext/iodine/http_internal.c +0 -1279
- data/ext/iodine/http_internal.h +0 -237
- data/ext/iodine/http_mime_parser.h +0 -350
- data/ext/iodine/iodine_caller.c +0 -230
- data/ext/iodine/iodine_connection.c +0 -941
- data/ext/iodine/iodine_defer.c +0 -420
- data/ext/iodine/iodine_fiobj2rb.h +0 -120
- data/ext/iodine/iodine_helpers.c +0 -282
- data/ext/iodine/iodine_helpers.h +0 -12
- data/ext/iodine/iodine_http.c +0 -1181
- data/ext/iodine/iodine_http.h +0 -23
- data/ext/iodine/iodine_json.c +0 -302
- data/ext/iodine/iodine_mustache.c +0 -567
- data/ext/iodine/iodine_pubsub.c +0 -580
- data/ext/iodine/iodine_pubsub.h +0 -26
- data/ext/iodine/iodine_rack_io.c +0 -273
- data/ext/iodine/iodine_rack_io.h +0 -20
- data/ext/iodine/iodine_store.c +0 -148
- data/ext/iodine/iodine_tcp.c +0 -346
- data/ext/iodine/iodine_tcp.h +0 -13
- data/ext/iodine/iodine_tls.c +0 -261
- data/ext/iodine/mustache_parser.h +0 -1546
- data/ext/iodine/redis_engine.c +0 -957
- data/ext/iodine/redis_engine.h +0 -79
- data/ext/iodine/resp_parser.h +0 -317
- data/ext/iodine/websocket_parser.h +0 -506
- data/ext/iodine/websockets.c +0 -743
- data/ext/iodine/websockets.h +0 -185
- data/lib/iodine/connection.rb +0 -61
- data/lib/iodine/json.rb +0 -42
- data/lib/iodine/mustache.rb +0 -113
- data/lib/iodine/pubsub.rb +0 -55
- data/lib/iodine/rack_utils.rb +0 -43
- data/lib/iodine/tls.rb +0 -16
- data/lib/rack/handler/iodine.rb +0 -33
- data/logo.png +0 -0
data/examples/pubsub_engine.ru
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# This example implements a custom (noop) pub/sub engine according to the Iodine::PubSub::Engine specifications.
|
|
2
|
-
#
|
|
3
|
-
require 'uri'
|
|
4
|
-
require 'iodine'
|
|
5
|
-
|
|
6
|
-
# creates an example Pub/Sub Engine that merely reports any pub/sub events to the system's terminal
|
|
7
|
-
class PubSubReporter < Iodine::PubSub::Engine
|
|
8
|
-
def initialize
|
|
9
|
-
# make sure engine setup is complete
|
|
10
|
-
super
|
|
11
|
-
# register engine and make it into the new default
|
|
12
|
-
@target = Iodine::PubSub.default
|
|
13
|
-
Iodine::PubSub.default = self
|
|
14
|
-
Iodine::PubSub.attach self
|
|
15
|
-
end
|
|
16
|
-
def subscribe to, as = nil
|
|
17
|
-
puts "* Subscribing to \"#{to}\" (#{as || "exact match"})"
|
|
18
|
-
end
|
|
19
|
-
def unsubscribe to, as = nil
|
|
20
|
-
puts "* Unsubscribing to \"#{to}\" (#{as || "exact match"})"
|
|
21
|
-
end
|
|
22
|
-
def publish to, msg
|
|
23
|
-
puts "* Publishing to \"#{to}\": #{msg.to_s[0..12]}..."
|
|
24
|
-
# we need to forward the message to the actual engine (the previous default engine),
|
|
25
|
-
# or it will never be received by any Pub/Sub client.
|
|
26
|
-
@target.publish to, msg
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
PubSubReporter.new
|
|
31
|
-
|
|
32
|
-
# A simple router - Checks for Websocket Upgrade and answers HTTP.
|
|
33
|
-
module MyHTTPRouter
|
|
34
|
-
# This is the HTTP response object according to the Rack specification.
|
|
35
|
-
HTTP_RESPONSE = [200, { 'Content-Type' => 'text/html',
|
|
36
|
-
'Content-Length' => '32' },
|
|
37
|
-
['Please connect using websockets.']]
|
|
38
|
-
|
|
39
|
-
WS_RESPONSE = [0, {}, []]
|
|
40
|
-
|
|
41
|
-
# this is function will be called by the Rack server (iodine) for every request.
|
|
42
|
-
def self.call env
|
|
43
|
-
# check if this is an upgrade request.
|
|
44
|
-
if(env['rack.upgrade?'.freeze])
|
|
45
|
-
puts "SSE connections will not be able te send data, just listen." if(env['rack.upgrade?'.freeze] == :sse)
|
|
46
|
-
env['rack.upgrade'.freeze] = PubSubClient.new(env['PATH_INFO'] && env['PATH_INFO'].length > 1 ? env['PATH_INFO'][1..-1] : "guest")
|
|
47
|
-
return WS_RESPONSE
|
|
48
|
-
end
|
|
49
|
-
# simply return the RESPONSE object, no matter what request was received.
|
|
50
|
-
HTTP_RESPONSE
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# A simple Websocket Callback Object.
|
|
55
|
-
class PubSubClient
|
|
56
|
-
def initialize name
|
|
57
|
-
@name = name
|
|
58
|
-
end
|
|
59
|
-
# seng a message to new clients.
|
|
60
|
-
def on_open(client)
|
|
61
|
-
client.subscribe "chat"
|
|
62
|
-
# let everyone know we arrived
|
|
63
|
-
client.publish "chat", "#{@name} entered the chat."
|
|
64
|
-
end
|
|
65
|
-
# send a message, letting the client know the server is suggunt down.
|
|
66
|
-
def on_shutdown(client)
|
|
67
|
-
client.write "Server shutting down. Goodbye."
|
|
68
|
-
end
|
|
69
|
-
# perform the echo
|
|
70
|
-
def on_message(client, data)
|
|
71
|
-
client.publish "chat", "#{@name}: #{data}"
|
|
72
|
-
end
|
|
73
|
-
def on_close(client)
|
|
74
|
-
# let everyone know we left
|
|
75
|
-
client.publish "chat", "#{@name} left the chat."
|
|
76
|
-
# we don't need to unsubscribe, subscriptions are cleared automatically once the connection is closed.
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# this function call links our HelloWorld application with Rack
|
|
81
|
-
run MyHTTPRouter
|
data/examples/rack3.ru
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
# adjusted from the code suggested by @taku0 (GitHub issue #131)
|
|
4
|
-
require 'rack'
|
|
5
|
-
require 'iodine'
|
|
6
|
-
|
|
7
|
-
run { |env|
|
|
8
|
-
response = Rack::Response.new(nil, 204)
|
|
9
|
-
response.set_cookie('aaa', 'aaa')
|
|
10
|
-
response.set_cookie('bbb', 'bbb')
|
|
11
|
-
response.finish
|
|
12
|
-
}
|
data/examples/redis.ru
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# This example implements a Redis pub/sub engine according to the Iodine::PubSub::Engine specifications.
|
|
2
|
-
#
|
|
3
|
-
# Run this applications on two ports, in two terminals to see the synchronization is action:
|
|
4
|
-
#
|
|
5
|
-
# IODINE_REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3000 redis.ru
|
|
6
|
-
# IODINE_REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3030 redis.ru
|
|
7
|
-
#
|
|
8
|
-
# Or:
|
|
9
|
-
#
|
|
10
|
-
# iodine -t 1 -p 3000 redis.ru -redis redis://localhost:6379/0
|
|
11
|
-
# iodine -t 1 -p 3030 redis.ru -redis redis://localhost:6379/0
|
|
12
|
-
#
|
|
13
|
-
require 'iodine'
|
|
14
|
-
# initialize the Redis engine for each Iodine process.
|
|
15
|
-
if Iodine::DEFAULT_HTTP_ARGS[:redis_]
|
|
16
|
-
puts "* Redis support automatically detected."
|
|
17
|
-
else
|
|
18
|
-
puts "* No Redis, it's okay, pub/sub will support the process cluster."
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# A simple router - Checks for Websocket Upgrade and answers HTTP.
|
|
22
|
-
module MyHTTPRouter
|
|
23
|
-
# This is the HTTP response object according to the Rack specification.
|
|
24
|
-
HTTP_RESPONSE = [200, { 'Content-Type' => 'text/html',
|
|
25
|
-
'Content-Length' => '32' },
|
|
26
|
-
['Please connect using websockets.']]
|
|
27
|
-
|
|
28
|
-
WS_RESPONSE = [0, {}, []]
|
|
29
|
-
|
|
30
|
-
# this is function will be called by the Rack server (iodine) for every request.
|
|
31
|
-
def self.call env
|
|
32
|
-
# check if this is an upgrade request.
|
|
33
|
-
if(env['rack.upgrade?'.freeze])
|
|
34
|
-
puts "SSE connections will not be able te send data, just listen." if(env['rack.upgrade?'.freeze] == :sse)
|
|
35
|
-
env['rack.upgrade'.freeze] = WS_RedisPubSub.new(env['PATH_INFO'] && env['PATH_INFO'].length > 1 ? env['PATH_INFO'][1..-1] : "guest")
|
|
36
|
-
return WS_RESPONSE
|
|
37
|
-
end
|
|
38
|
-
# simply return the RESPONSE object, no matter what request was received.
|
|
39
|
-
HTTP_RESPONSE
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# A simple Websocket Callback Object.
|
|
44
|
-
class WS_RedisPubSub
|
|
45
|
-
def initialize name
|
|
46
|
-
@name = name
|
|
47
|
-
end
|
|
48
|
-
# seng a message to new clients.
|
|
49
|
-
def on_open client
|
|
50
|
-
client.subscribe "chat"
|
|
51
|
-
# let everyone know we arrived
|
|
52
|
-
client.publish "chat", "#{@name} entered the chat."
|
|
53
|
-
end
|
|
54
|
-
# send a message, letting the client know the server is suggunt down.
|
|
55
|
-
def on_shutdown client
|
|
56
|
-
client.write "Server shutting down. Goodbye."
|
|
57
|
-
end
|
|
58
|
-
# perform the echo
|
|
59
|
-
def on_message client, data
|
|
60
|
-
client.publish "chat", "#{@name}: #{data}"
|
|
61
|
-
end
|
|
62
|
-
def on_close client
|
|
63
|
-
# let everyone know we left
|
|
64
|
-
client.publish "chat", "#{@name} left the chat."
|
|
65
|
-
# we don't need to unsubscribe, subscriptions are cleared automatically once the connection is closed.
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# this function call links our HelloWorld application with Rack
|
|
70
|
-
run MyHTTPRouter
|
data/examples/shootout.ru
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
require 'iodine'
|
|
2
|
-
require 'json'
|
|
3
|
-
require 'rack'
|
|
4
|
-
|
|
5
|
-
module ShootoutApp
|
|
6
|
-
# the default HTTP response
|
|
7
|
-
def self.call(env)
|
|
8
|
-
if(env['rack.upgrade?'.freeze] == :websocket)
|
|
9
|
-
env['rack.upgrade'.freeze] = ShootoutApp
|
|
10
|
-
return [0, {}, []]
|
|
11
|
-
end
|
|
12
|
-
out = []
|
|
13
|
-
len = 0
|
|
14
|
-
out << "ENV:\n"
|
|
15
|
-
len += 5
|
|
16
|
-
env.each { |k, v| out << "#{k}: #{v}\n" ; len += out[-1].length }
|
|
17
|
-
request = Rack::Request.new(env)
|
|
18
|
-
out << "\nRequest Path: #{request.path_info}\n"
|
|
19
|
-
len += out[-1].length
|
|
20
|
-
unless request.params.empty?
|
|
21
|
-
out << "Params:\n"
|
|
22
|
-
len += out[-1].length
|
|
23
|
-
request.params.each { |k,v| out << "#{k}: #{v}\n" ; len += out[-1].length }
|
|
24
|
-
end
|
|
25
|
-
if(env['rack.input'])
|
|
26
|
-
env['rack.input'].rewind
|
|
27
|
-
out << "Body\n\n"
|
|
28
|
-
out << env['rack.input'].read
|
|
29
|
-
len += out[-1].length + 6
|
|
30
|
-
out << "\n\nBody Length: #{out[-1].length}\n\n"
|
|
31
|
-
len += out[-1].length
|
|
32
|
-
end
|
|
33
|
-
[200, { 'Content-Length' => len.to_s, 'Content-Type' => 'text/plain; charset=UTF-8;' }, out]
|
|
34
|
-
end
|
|
35
|
-
# We'll base the shootout on the internal Pub/Sub service.
|
|
36
|
-
# It's slower than writing to every socket a pre-parsed message, but it's closer
|
|
37
|
-
# to real-life implementations.
|
|
38
|
-
def self.on_open client
|
|
39
|
-
client.subscribe(:shootout_b, as: :binary) # { |ch, msg| client.write(msg)}
|
|
40
|
-
client.subscribe(:shootout) # { |ch, msg| client.write(msg)}
|
|
41
|
-
end
|
|
42
|
-
def self.on_message client, data
|
|
43
|
-
if data[0] == 'b' # binary
|
|
44
|
-
client.publish :shootout_b, data
|
|
45
|
-
data[0] = 'r'
|
|
46
|
-
client.write data
|
|
47
|
-
return
|
|
48
|
-
end
|
|
49
|
-
cmd, payload = JSON(data).values_at('type', 'payload')
|
|
50
|
-
if cmd == 'echo'
|
|
51
|
-
client.write({type: 'echo', payload: payload}.to_json)
|
|
52
|
-
else
|
|
53
|
-
client.publish :shootout, {type: 'broadcast', payload: payload}.to_json
|
|
54
|
-
client.write({type: "broadcastResult", payload: payload}.to_json)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
run ShootoutApp
|
|
60
|
-
#
|
|
61
|
-
# def cycle
|
|
62
|
-
# 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`
|
|
63
|
-
# sleep(4)
|
|
64
|
-
# puts `wrk -c4000 -d15 -t2 http://localhost:3000/`
|
|
65
|
-
# true
|
|
66
|
-
# end
|
|
67
|
-
# sleep(10) while cycle
|
|
68
|
-
|
|
69
|
-
# # Used when debugging:
|
|
70
|
-
# ON_IDLE = proc { Iodine::Base.db_print_protected_objects ; Iodine.on_idle(&ON_IDLE) }
|
|
71
|
-
# ON_IDLE.call
|
|
72
|
-
# Iodine.on_shutdown { Iodine::Base.db_print_protected_objects }
|
|
73
|
-
|
data/examples/sub-protocols.ru
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# This is a WebSocket / SSE notification example application.
|
|
4
|
-
#
|
|
5
|
-
# In this example, WebSocket sub-protocols are explored.
|
|
6
|
-
#
|
|
7
|
-
# Running this application from the command line is easy with:
|
|
8
|
-
#
|
|
9
|
-
# iodine
|
|
10
|
-
#
|
|
11
|
-
# Or, in a single thread and a single process:
|
|
12
|
-
#
|
|
13
|
-
# iodine -t 1 -w 1
|
|
14
|
-
#
|
|
15
|
-
# Test using:
|
|
16
|
-
#
|
|
17
|
-
# var subprotocol = "echo"; // or "chat"
|
|
18
|
-
# ws = new WebSocket("ws://localhost:3000/Mitchel", subprotocol);
|
|
19
|
-
# ws.onmessage = function(e) { console.log(e.data); };
|
|
20
|
-
# ws.onclose = function(e) { console.log("Closed"); };
|
|
21
|
-
# ws.onopen = function(e) { e.target.send("Yo!"); };
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# Chat clients connect with the "chat" sub-protocol.
|
|
25
|
-
class ChatClient
|
|
26
|
-
def on_open client
|
|
27
|
-
@nickname = client.env['PATH_INFO'].to_s.split('/')[1] || "Guest"
|
|
28
|
-
client.subscribe :chat
|
|
29
|
-
client.publish :chat , "#{@nickname} joined the chat."
|
|
30
|
-
end
|
|
31
|
-
def on_close client
|
|
32
|
-
client.publish :chat , "#{@nickname} left the chat."
|
|
33
|
-
end
|
|
34
|
-
def on_shutdown client
|
|
35
|
-
client.write "Server is shutting down... disconnecting all clients. Goodbye."
|
|
36
|
-
end
|
|
37
|
-
def on_message client, message
|
|
38
|
-
client.publish :chat , "#{@nickname}: #{message}"
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Echo clients connect with the "echo" sub-protocol.
|
|
43
|
-
class EchoClient
|
|
44
|
-
def on_open client
|
|
45
|
-
client.write "You established an echo connection."
|
|
46
|
-
end
|
|
47
|
-
def on_shutdown client
|
|
48
|
-
client.write "Server is shutting down... goodbye."
|
|
49
|
-
end
|
|
50
|
-
def on_message client, message
|
|
51
|
-
client.write message
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Rack application module
|
|
56
|
-
module APP
|
|
57
|
-
# the allowed protocols
|
|
58
|
-
CHAT_PROTOCOL_NAME = "chat"
|
|
59
|
-
ECHO_PROTOCOL_NAME = "echo"
|
|
60
|
-
PROTOCOLS =[CHAT_PROTOCOL_NAME, ECHO_PROTOCOL_NAME]
|
|
61
|
-
|
|
62
|
-
# the Rack application
|
|
63
|
-
def call env
|
|
64
|
-
return [200, {}, ["Hello World"]] unless env["rack.upgrade?"]
|
|
65
|
-
protocol = select_protocol(env)
|
|
66
|
-
case(protocol)
|
|
67
|
-
when CHAT_PROTOCOL_NAME
|
|
68
|
-
env["rack.upgrade"] = ChatClient.new
|
|
69
|
-
[101, { "Sec-Websocket-Protocol" => protocol }, []]
|
|
70
|
-
when ECHO_PROTOCOL_NAME
|
|
71
|
-
env["rack.upgrade"] = EchoClient.new
|
|
72
|
-
[101, { "Sec-Websocket-Protocol" => protocol }, []]
|
|
73
|
-
else
|
|
74
|
-
[400, {}, ["Unsupported protocol specified"]]
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def select_protocol(env)
|
|
79
|
-
request_protocols = env["HTTP_SEC_WEBSOCKET_PROTOCOL"]
|
|
80
|
-
unless request_protocols.nil?
|
|
81
|
-
request_protocols = request_protocols.split(/,\s?/) if request_protocols.is_a?(String)
|
|
82
|
-
request_protocols.detect { |request_protocol| PROTOCOLS.include? request_protocol }
|
|
83
|
-
end # either `nil` or the result of `request_protocols.detect` are returned
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# make functions availble as singleton module
|
|
87
|
-
extend self
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
run APP
|
data/examples/tcp_client.rb
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
#! ruby
|
|
2
|
-
|
|
3
|
-
# A raw TCP/IP client example using iodine.
|
|
4
|
-
#
|
|
5
|
-
# The client will connect to a remote server and send a simple HTTP/1.1 GET request.
|
|
6
|
-
#
|
|
7
|
-
# Once some data was recieved, a delayed closure and shutdown signal will be sent to iodine.
|
|
8
|
-
|
|
9
|
-
# use a secure connection?
|
|
10
|
-
USE_TLS = true
|
|
11
|
-
|
|
12
|
-
# remote server details
|
|
13
|
-
$port = USE_TLS ? 443 : 80
|
|
14
|
-
$address = "google.com"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# require iodine
|
|
18
|
-
require 'iodine'
|
|
19
|
-
|
|
20
|
-
# Iodine runtime settings
|
|
21
|
-
Iodine.threads = 1
|
|
22
|
-
Iodine.workers = 1
|
|
23
|
-
Iodine.verbosity = 3 # warnings only
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# a client callback handler
|
|
27
|
-
module Client
|
|
28
|
-
|
|
29
|
-
def self.on_open(client)
|
|
30
|
-
# Set a connection timeout
|
|
31
|
-
client.timeout = 10
|
|
32
|
-
# subscribe to the chat channel.
|
|
33
|
-
puts "* Sending request..."
|
|
34
|
-
client.write "GET / HTTP/1.1\r\nHost: #{$address}\r\n\r\n"
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def self.on_message(client, data)
|
|
38
|
-
# publish the data we received
|
|
39
|
-
STDOUT.write data
|
|
40
|
-
# close the client after a second... we're not really parsing anything, so it's a guess.
|
|
41
|
-
Iodine.run_after(1000) { client.close }
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def self.on_close(client)
|
|
45
|
-
# stop iodine
|
|
46
|
-
Iodine.stop
|
|
47
|
-
puts "Done."
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# returns the callback object (self).
|
|
51
|
-
def self.call
|
|
52
|
-
self
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if(USE_TLS)
|
|
59
|
-
tls = Iodine::TLS.new
|
|
60
|
-
tls.on_protocol("http/1.1") { Client }
|
|
61
|
-
end
|
|
62
|
-
# we use can both the `handler` keyword or a block, anything that answers #call.
|
|
63
|
-
Iodine.connect(address: $address, port: $port, handler: Client, tls: tls)
|
|
64
|
-
|
|
65
|
-
# start the iodine reactor
|
|
66
|
-
Iodine.start
|
data/examples/x-sendfile.ru
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
app = proc do |env|
|
|
2
|
-
request = Rack::Request.new(env)
|
|
3
|
-
if request.path_info == '/source'.freeze
|
|
4
|
-
[200, { 'X-Sendfile' => File.expand_path(__FILE__), 'Content-Type' => 'text/plain'}, []]
|
|
5
|
-
elsif request.path_info == '/file'.freeze
|
|
6
|
-
[200, { 'X-Header' => 'This was a Rack::Sendfile response sent as text.' }, File.open(__FILE__)]
|
|
7
|
-
else
|
|
8
|
-
[200, { 'Content-Type' => 'text/html',
|
|
9
|
-
'Content-Length' => request.path_info.length.to_s },
|
|
10
|
-
[request.path_info]]
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
run app
|