iodine 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +41 -1
- data/lib/iodine/core.rb +25 -3
- data/lib/iodine/http.rb +20 -8
- data/lib/iodine/http/http1.rb +1 -6
- data/lib/iodine/http/http2.rb +5 -3
- data/lib/iodine/http/rack_support.rb +2 -2
- data/lib/iodine/http/request.rb +1 -1
- data/lib/iodine/http/response.rb +11 -9
- data/lib/iodine/http/session.rb +69 -69
- data/lib/iodine/http/websocket_client.rb +190 -191
- data/lib/iodine/http/websocket_handler.rb +48 -14
- data/lib/iodine/http/websockets.rb +23 -4
- data/lib/iodine/io.rb +12 -27
- data/lib/iodine/logging.rb +7 -1
- data/lib/iodine/protocol.rb +4 -1
- data/lib/iodine/timers.rb +4 -3
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +1 -1
- data/manual tests/hello_world +17 -20
- metadata +2 -2
@@ -1,24 +1,29 @@
|
|
1
1
|
module Iodine
|
2
2
|
class Http < Iodine::Protocol
|
3
3
|
class Websockets < ::Iodine::Protocol
|
4
|
+
# initialize the websocket protocol.
|
4
5
|
def initialize io, handler, request, ws_extentions = nil
|
5
6
|
@handler = handler
|
6
7
|
@ws_extentions = ws_extentions
|
7
8
|
request[:io] = self
|
8
9
|
super(io)
|
9
10
|
end
|
11
|
+
# continue to initialize the websocket protocol.
|
10
12
|
def on_open
|
11
13
|
set_timeout 45
|
12
14
|
@parser = {body: '', stage: 0, step: 0, mask_key: [], len_bytes: []}
|
13
15
|
set_timeout = self.class.default_timeout
|
14
|
-
@handler.on_open
|
16
|
+
@handler.on_open if @handler.respond_to? :on_open
|
15
17
|
end
|
18
|
+
# parse and handle messages.
|
16
19
|
def on_message data
|
17
20
|
extract_message StringIO.new(data)
|
18
21
|
end
|
22
|
+
# handle broadcasts.
|
19
23
|
def on_broadcast data
|
20
24
|
@handler.on_broadcast(data) if @handler.respond_to? :on_broadcast
|
21
25
|
end
|
26
|
+
# cleanup after closing.
|
22
27
|
def on_close
|
23
28
|
@handler.on_close if @handler.respond_to? :on_close
|
24
29
|
if @ws_extentions
|
@@ -27,13 +32,28 @@ module Iodine
|
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
35
|
+
# a politer disconnection.
|
36
|
+
def go_away
|
37
|
+
write CLOSE_FRAME
|
38
|
+
close
|
39
|
+
end
|
40
|
+
|
41
|
+
# a politer disconnection during shutdown.
|
42
|
+
def on_shutdown
|
43
|
+
go_away
|
44
|
+
end
|
45
|
+
|
46
|
+
# allow Http responses to be used for sending Websocket data.
|
30
47
|
def send_response response, finish = false
|
31
48
|
body = response.extract_body
|
32
49
|
send_data body
|
33
50
|
end
|
34
51
|
alias :stream_response :send_response
|
35
52
|
|
36
|
-
#
|
53
|
+
# Sends the data as one (or more) Websocket frames.
|
54
|
+
#
|
55
|
+
# Use THIS method to send data using the Websocket protocol.
|
56
|
+
# Using {Iodine::Protocol#write} will bypass the Websocket data framing and send the raw data, breaking the connection.
|
37
57
|
def send_data data, op_code = nil, fin = true, ext = 0
|
38
58
|
return false if !data || data.empty?
|
39
59
|
return false if @io.closed?
|
@@ -142,8 +162,7 @@ module Iodine
|
|
142
162
|
end
|
143
163
|
response['Sec-WebSocket-Accept'.freeze] = Digest::SHA1.base64digest(request['sec-websocket-key'.freeze] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'.freeze)
|
144
164
|
response.session
|
145
|
-
# Iodine.
|
146
|
-
# request.io.handler.send_response response
|
165
|
+
# Iodine.log "#{@request[:client_ip]} [#{Time.now.utc}] - #{@connection.object_id} Upgraded HTTP to WebSockets.\n"
|
147
166
|
response.finish
|
148
167
|
self.new(io.io, handler, request, ws_extentions)
|
149
168
|
return true
|
data/lib/iodine/io.rb
CHANGED
@@ -102,52 +102,37 @@ module Iodine
|
|
102
102
|
begin
|
103
103
|
@server = ::TCPServer.new(@bind, @port)
|
104
104
|
rescue => e
|
105
|
-
|
106
|
-
|
107
|
-
|
105
|
+
fatal e.message
|
106
|
+
fatal "Running existing tasks and exiting."
|
107
|
+
Process.kill("INT", 0)
|
108
108
|
next
|
109
109
|
end
|
110
110
|
shut_down_proc = Proc.new {|protocol| protocol.on_shutdown ; protocol.close }
|
111
111
|
on_shutdown do
|
112
|
-
|
112
|
+
log "Stopping to listen on port #{@port} and shutting down.\n"
|
113
113
|
@server.close unless @server.closed?
|
114
114
|
@ios.values.each {|p| run p, &shut_down_proc }
|
115
115
|
end
|
116
116
|
::Iodine::Base::Listener.accept(@server, false)
|
117
|
-
|
117
|
+
log "Iodine #{VERSION} is listening on port #{@port}#{ ' to SSL/TLS connections.' if @ssl}\n"
|
118
118
|
if @spawn_count && @spawn_count.to_i > 1 && Process.respond_to?(:fork)
|
119
|
-
|
119
|
+
log "Server will run using #{@spawn_count.to_i} processes - Spawning #{@spawn_count.to_i - 1 } more processes.\n"
|
120
120
|
(@spawn_count.to_i - 1).times do
|
121
121
|
Process.fork do
|
122
|
-
|
123
|
-
on_shutdown {
|
124
|
-
threads = []
|
122
|
+
log "Spawned process: #{Process.pid}.\n"
|
123
|
+
on_shutdown { log "Shutting down process #{Process.pid}.\n" }
|
125
124
|
@queue.clear
|
126
125
|
@queue << REACTOR
|
127
|
-
|
128
|
-
unless @stop
|
129
|
-
old_int_trap = trap('INT') { throw :stop; trap('INT', old_int_trap) if old_int_trap }
|
130
|
-
old_term_trap = trap('TERM') { throw :stop; trap('TERM', old_term_trap) if old_term_trap }
|
131
|
-
catch(:stop) { sleep }
|
132
|
-
@stop = true
|
133
|
-
# setup exit timeout.
|
134
|
-
threads.each {|t| Thread.new {sleep 25; t.kill; t.kill } }
|
135
|
-
end
|
136
|
-
threads.each {|t| t.join rescue true }
|
126
|
+
startup false, true
|
137
127
|
end
|
138
128
|
end
|
139
129
|
|
140
130
|
end
|
141
|
-
|
131
|
+
log "Press ^C to stop the server.\n"
|
142
132
|
else
|
143
|
-
|
144
|
-
|
145
|
-
@logger << "Iodine says goodbye.\n"
|
146
|
-
end
|
147
|
-
@logger << "Press ^C to stop the cycling.\n"
|
133
|
+
log "Iodine #{VERSION} is running.\n"
|
134
|
+
log "Press ^C to stop the cycling.\n"
|
148
135
|
end
|
149
|
-
old_int_trap = trap('INT') { throw :stop; trap('INT', old_int_trap) if old_int_trap }
|
150
|
-
old_term_trap = trap('TERM') { throw :stop; trap('TERM', old_term_trap) if old_term_trap }
|
151
136
|
@queue << REACTOR
|
152
137
|
end
|
153
138
|
end
|
data/lib/iodine/logging.rb
CHANGED
@@ -2,7 +2,7 @@ module Iodine
|
|
2
2
|
public
|
3
3
|
|
4
4
|
# Gets the logging object and allows you to call logging methods (i.e. `Iodine.log.info "Running"`).
|
5
|
-
def logger
|
5
|
+
def logger
|
6
6
|
@logger
|
7
7
|
end
|
8
8
|
|
@@ -36,6 +36,12 @@ module Iodine
|
|
36
36
|
@logger.fatal data, &block if @logger
|
37
37
|
data
|
38
38
|
end
|
39
|
+
# logs a raw text
|
40
|
+
# @return [String] always returns the Object sent to the log.
|
41
|
+
def log raw_text
|
42
|
+
@logger << raw_text if @logger
|
43
|
+
raw_text
|
44
|
+
end
|
39
45
|
|
40
46
|
|
41
47
|
protected
|
data/lib/iodine/protocol.rb
CHANGED
@@ -71,6 +71,9 @@ module Iodine
|
|
71
71
|
nil
|
72
72
|
end
|
73
73
|
alias :disconnect :close
|
74
|
+
def closed?
|
75
|
+
@io.closed?
|
76
|
+
end
|
74
77
|
|
75
78
|
# reads from the IO up to the specified number of bytes (defaults to ~2Mb).
|
76
79
|
def read size = 2_097_152
|
@@ -103,7 +106,7 @@ module Iodine
|
|
103
106
|
#
|
104
107
|
# This can be used locally but not across processes.
|
105
108
|
def id
|
106
|
-
@id ||= @io.to_io.to_s(16)
|
109
|
+
@id ||= @io.to_io.object_id.to_s(16)
|
107
110
|
end
|
108
111
|
|
109
112
|
# returns an [Enumerable](http://ruby-doc.org/core-2.2.3/Enumerable.html) with all the active connections.
|
data/lib/iodine/timers.rb
CHANGED
@@ -12,6 +12,8 @@ module Iodine
|
|
12
12
|
# Sets/gets how many times a timed event repeats.
|
13
13
|
# If set to false or -1, the timed event will repead until the application quits.
|
14
14
|
attr_accessor :repeat_limit
|
15
|
+
# Allows you to acess or change the timer's Proc object.
|
16
|
+
attr_accessor :job
|
15
17
|
|
16
18
|
# Initialize a timed event.
|
17
19
|
def initialize reactor, interval, repeat_limit = -1, args=[], job=nil
|
@@ -68,7 +70,6 @@ module Iodine
|
|
68
70
|
#
|
69
71
|
# accepts:
|
70
72
|
# seconds:: the minimal amount of seconds to wait before calling the handler's `call` method.
|
71
|
-
# limit:: the amount of times the event should repeat itself. The event will repeat every x amount of `seconds`. The event will repeat forever if limit is set to false.
|
72
73
|
# *arg:: any arguments that will be passed to the handler's `call` method.
|
73
74
|
# &block:: the block to execute.
|
74
75
|
#
|
@@ -79,8 +80,8 @@ module Iodine
|
|
79
80
|
# Timed event's time of execution is dependant on the workload and continuous uptime of the process (timed events AREN'T persistent unless you save and reload them yourself).
|
80
81
|
#
|
81
82
|
# @return [Iodine::TimedEvent] returns the new TimedEvent object.
|
82
|
-
def run_every seconds,
|
83
|
-
timed_job seconds,
|
83
|
+
def run_every seconds, *args, &block
|
84
|
+
timed_job seconds, -1, args, block
|
84
85
|
end
|
85
86
|
|
86
87
|
protected
|
data/lib/iodine/version.rb
CHANGED
data/lib/rack/handler/iodine.rb
CHANGED
data/manual tests/hello_world
CHANGED
@@ -20,28 +20,25 @@ require "iodine/http"
|
|
20
20
|
Iodine.protocol.on_http { "Hello World!" }
|
21
21
|
|
22
22
|
|
23
|
-
class WSChatServer
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
def on_close
|
40
|
-
@io.broadcast "#{@nickname} has left the chat!"
|
41
|
-
end
|
23
|
+
class WSChatServer < Iodine::Http::WebsocketHandler
|
24
|
+
def on_open
|
25
|
+
@nickname = request.params[:nickname] || "unknown"
|
26
|
+
broadcast "#{@nickname} has joined the chat!"
|
27
|
+
write "Welcome #{@nickname}, you have joined the chat!"
|
28
|
+
end
|
29
|
+
def on_message data
|
30
|
+
broadcast "#{@nickname} >> #{data}"
|
31
|
+
write ">> #{data}"
|
32
|
+
end
|
33
|
+
def on_broadcast data
|
34
|
+
write data
|
35
|
+
end
|
36
|
+
def on_close
|
37
|
+
broadcast "#{@nickname} has left the chat!"
|
38
|
+
end
|
42
39
|
end
|
43
40
|
|
44
|
-
Iodine::Http.on_websocket
|
41
|
+
Iodine::Http.on_websocket WSChatServer
|
45
42
|
|
46
43
|
Process.fork do
|
47
44
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iodine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|