iodine 0.1.7 → 0.1.8
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/CHANGELOG.md +16 -0
- data/README.md +11 -0
- data/bin/hello_world +8 -0
- data/lib/iodine/core.rb +3 -2
- data/lib/iodine/http/http1.rb +2 -1
- data/lib/iodine/http/rack_support.rb +4 -2
- data/lib/iodine/http/response.rb +2 -1
- data/lib/iodine/http/session.rb +23 -6
- data/lib/iodine/http/websocket_client.rb +2 -2
- data/lib/iodine/http/websockets.rb +1 -1
- data/lib/iodine/protocol.rb +5 -0
- data/lib/iodine/settings.rb +5 -0
- data/lib/iodine/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 015d21e31dd393be87f10ecb19fe9d94f565255c
|
4
|
+
data.tar.gz: 8919757b4d844e02b110496fff6d8e84dc87f60f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6198a6eaa862ce000905693bad9afb670359ab20b80987713f95df11eefe8d1b951f243f761bac2546701eb10c215e5cea157f215eb3fd48f4bc229d50927e6a
|
7
|
+
data.tar.gz: e96c344aad2a559a5af5b4f2f6365f876335ad3fc741f5cf212eede1002ec3a87751dc78f51d3b0228fdf16d729369f05cde90aaa573af521e25315fb5086ff4
|
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,22 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
8
8
|
|
9
9
|
***
|
10
10
|
|
11
|
+
Change log v.0.1.8
|
12
|
+
|
13
|
+
**Fix**: Websocket broadcasts are now correctly executed within the IO's mutex locker. This maintains the idea that only one thread at a time should be executing code on behald of any given Protocol object ("yes" to concurrency between objects but "no" to concurrency within objects).
|
14
|
+
|
15
|
+
**Fix** fixed an issue where manually setting the number of threads for Rack applications (when using Iodine as a Rack server), the setting was mistakenly ignored.
|
16
|
+
|
17
|
+
**Fix** fixed an issue where sometimes extractin the Http response's body would fail (if body is `nil`).
|
18
|
+
|
19
|
+
**Feature**: session objects are now aware of the session id. The seesion id is available by calling `response.session.id`
|
20
|
+
|
21
|
+
**Fix** fixed an issue where Http streaming wasn't chunk encoding after connection error handling update.
|
22
|
+
|
23
|
+
**Fix** fixed an issue where Http streaming would disconnect while still processing. Streaming timeout now extended to 15 seconds between response writes.
|
24
|
+
|
25
|
+
***
|
26
|
+
|
11
27
|
Change log v.0.1.7
|
12
28
|
|
13
29
|
Removed a deprecation notice for blocking API. Client API will remain blocking due to use-case requirements.
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Iodine
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/iodine.svg)](https://badge.fury.io/rb/iodine)
|
3
3
|
[![Inline docs](http://inch-ci.org/github/boazsegev/iodine.svg?branch=master)](http://www.rubydoc.info/github/boazsegev/iodine/master/frames)
|
4
|
+
[![GitHub](https://img.shields.io/badge/GitHub-Open%20Source-blue.svg)](https://github.com/boazsegev/iodine)
|
4
5
|
|
5
6
|
Iodine makes writing Object Oriented evented server applications easy to write.
|
6
7
|
|
@@ -249,6 +250,16 @@ end if Process.respond_to? :fork
|
|
249
250
|
exit
|
250
251
|
```
|
251
252
|
|
253
|
+
## Cuncurrency?
|
254
|
+
|
255
|
+
Iodine maintains the idea of: "yes" to concurrency between objects but "no" to concurrency within objects.
|
256
|
+
|
257
|
+
Iodine applies this concept when running in Task mode (or timer mode), by defaulting to single threaded mode, preventing multi-threading race conditions in an unknown environment. Also, each task runs in a single thread from the thread-pool, so unless it tries to set or manipulate global data, it's safe from race conditions.
|
258
|
+
|
259
|
+
Iodine applies this concept when running in Server mode by locking the Protocol instance whenever Iodine calls for actions related to that Protocol.
|
260
|
+
|
261
|
+
For instance, in Iodine's implementation for the Websocket protocol: Websocket messages to different connections can run concurrently, however multiple messages to the same connection are only executed one at a time, maintaining their order (lately a fix in version 0.1.8 made sure that also websocket broadcasting will be executed within the Protocol lock, preventing concurrency within the same connection).
|
262
|
+
|
252
263
|
## Development
|
253
264
|
|
254
265
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/bin/hello_world
CHANGED
@@ -51,6 +51,14 @@ Process.fork do
|
|
51
51
|
Iodine.ssl = true
|
52
52
|
Iodine.port = 3030
|
53
53
|
Iodine::Http.on_http do |req, res|
|
54
|
+
if req.path == '/stream'
|
55
|
+
res.stream_async { sleep 0.2; res << "I was sleeping..."}
|
56
|
+
next
|
57
|
+
end
|
58
|
+
if req.path == '/stream2'
|
59
|
+
res.stream_async { sleep 2; res << "I was sleeping..."}
|
60
|
+
next
|
61
|
+
end
|
54
62
|
res.session[:count] ||= 0
|
55
63
|
res.session[:count] += 1
|
56
64
|
res['content-type'] = 'text/plain'
|
data/lib/iodine/core.rb
CHANGED
@@ -45,7 +45,8 @@ module Iodine
|
|
45
45
|
@stop = true
|
46
46
|
@done = false
|
47
47
|
@logger = Logger.new(STDOUT)
|
48
|
-
@spawn_count =
|
48
|
+
@spawn_count = 1
|
49
|
+
@thread_count = nil
|
49
50
|
@ios = {}
|
50
51
|
@io_in = Queue.new
|
51
52
|
@io_out = Queue.new
|
@@ -73,7 +74,7 @@ module Iodine
|
|
73
74
|
|
74
75
|
def startup use_rescue = false, hide_message = false
|
75
76
|
threads = []
|
76
|
-
@thread_count.times { threads << Thread.new { cycle } }
|
77
|
+
(@thread_count ||= 1).times { threads << Thread.new { cycle } }
|
77
78
|
unless @stop
|
78
79
|
if use_rescue
|
79
80
|
sleep rescue true
|
data/lib/iodine/http/http1.rb
CHANGED
@@ -122,6 +122,7 @@ module Iodine
|
|
122
122
|
log_finished response
|
123
123
|
end
|
124
124
|
def stream_response response, finish = false
|
125
|
+
timeout = 15
|
125
126
|
unless response.headers.frozen?
|
126
127
|
response['transfer-encoding'.freeze] = 'chunked'
|
127
128
|
response.headers['connection'.freeze] = 'close'.freeze
|
@@ -131,7 +132,7 @@ module Iodine
|
|
131
132
|
return if response.request.head?
|
132
133
|
body = response.extract_body
|
133
134
|
until body.eof?
|
134
|
-
written =
|
135
|
+
written = stream_data(body.read 65_536)
|
135
136
|
return Iodine.warn("Http/1 couldn't send response because connection was lost.") && body.close unless written
|
136
137
|
response.bytes_written += written
|
137
138
|
end if body
|
@@ -7,10 +7,12 @@ module Iodine
|
|
7
7
|
def run(app, options = {})
|
8
8
|
@app = app
|
9
9
|
|
10
|
-
|
10
|
+
puts "reading threads = #{Iodine.threads.to_s}"
|
11
|
+
|
12
|
+
Iodine.threads = 18 unless Iodine.threads
|
11
13
|
Iodine.port = options[:Port]
|
12
14
|
Iodine.protocol ||= Iodine::Http::Http1
|
13
|
-
@pre_rack_handler = Iodine::Http.on_http
|
15
|
+
@pre_rack_handler = Iodine::Http.on_http unless Iodine::Http.on_http == Iodine::Http::NOT_IMPLEMENTED
|
14
16
|
Iodine::Http.on_http self
|
15
17
|
true
|
16
18
|
end
|
data/lib/iodine/http/response.rb
CHANGED
@@ -317,7 +317,8 @@ module Iodine
|
|
317
317
|
elsif @body.is_a?(String)
|
318
318
|
return (@body = nil) if body.empty?
|
319
319
|
StringIO.new @body
|
320
|
-
elsif body.nil?
|
320
|
+
elsif @body.nil?
|
321
|
+
return nil
|
321
322
|
nil
|
322
323
|
elsif @body.is_a?(File) || @body.is_a?(Tempfile) || @body.is_a?(StringIO)
|
323
324
|
@body
|
data/lib/iodine/http/session.rb
CHANGED
@@ -4,9 +4,19 @@ module Iodine
|
|
4
4
|
module SessionManager
|
5
5
|
|
6
6
|
module MemSessionStorage
|
7
|
+
class SessionObject < Hash
|
8
|
+
def initialize id
|
9
|
+
super()
|
10
|
+
self[:__session_id] = id
|
11
|
+
end
|
12
|
+
# returns the session id (the session cookie value).
|
13
|
+
def id
|
14
|
+
self[:__session_id]
|
15
|
+
end
|
16
|
+
end
|
7
17
|
@mem_storage = {}
|
8
18
|
def self.fetch key
|
9
|
-
@mem_storage[key] ||=
|
19
|
+
@mem_storage[key] ||= SessionObject.new(key)
|
10
20
|
end
|
11
21
|
end
|
12
22
|
module FileSessionStorage
|
@@ -15,6 +25,11 @@ module Iodine
|
|
15
25
|
def initialize id
|
16
26
|
@filename = File.join Dir.tmpdir, "iodine_#{Iodine::Http.session_token}_#{id}"
|
17
27
|
@data ||= {}
|
28
|
+
@id = id
|
29
|
+
end
|
30
|
+
# returns the session id (the session cookie value).
|
31
|
+
def id
|
32
|
+
@id
|
18
33
|
end
|
19
34
|
# Get a key from the session data store.
|
20
35
|
#
|
@@ -94,9 +109,8 @@ module Iodine
|
|
94
109
|
# A Session Storage system must answer only one methods:
|
95
110
|
# fetch(id):: returns a Hash like session object with all the session's data or a fresh session object if the session object did not exist before
|
96
111
|
#
|
97
|
-
# The Session Object should update
|
98
|
-
# This is important also because websocket 'session' could exist simultaneously with other HTTP requests and the data should be kept updated at all times.
|
99
|
-
# If there are race conditions that apply for multi-threading / multi processing, the Session Object should manage them as well as possible.
|
112
|
+
# The Session Object should update the storage whenever data is saved to the session Object.
|
113
|
+
# This is important also because a websocket 'session' could exist simultaneously with other HTTP requests (multiple browser windows) and the data should be kept updated at all times.
|
100
114
|
def storage= session_storage = nil
|
101
115
|
case session_storage
|
102
116
|
when :file, nil
|
@@ -116,6 +130,9 @@ module Iodine
|
|
116
130
|
end
|
117
131
|
end
|
118
132
|
# A hash like interface for storing request session data.
|
119
|
-
# The store must implement:
|
133
|
+
# The store must implement:
|
134
|
+
# store(key, value) (aliased as []=);
|
120
135
|
# fetch(key, default = nil) (aliased as []);
|
121
|
-
# delete(key);
|
136
|
+
# delete(key);
|
137
|
+
# clear;
|
138
|
+
# id(); (returns the session id)
|
@@ -96,9 +96,9 @@ module Iodine
|
|
96
96
|
@io.close if @io
|
97
97
|
end
|
98
98
|
|
99
|
-
# checks if the socket is open (if the websocket was terminated abnormally, this might
|
99
|
+
# checks if the socket is open (if the websocket was terminated abnormally, this might return true for a while after it should be false).
|
100
100
|
def closed?
|
101
|
-
@io
|
101
|
+
(@io && @io.io) ? @io.io.closed? : true
|
102
102
|
end
|
103
103
|
|
104
104
|
# checks if this is an SSL websocket connection.
|
@@ -16,7 +16,7 @@ module Iodine
|
|
16
16
|
end
|
17
17
|
# handle broadcasts.
|
18
18
|
def on_broadcast data
|
19
|
-
@handler.on_broadcast(data) if @handler.respond_to? :on_broadcast
|
19
|
+
@locker.synchronize { @handler.on_broadcast(data) if @handler.respond_to? :on_broadcast }
|
20
20
|
end
|
21
21
|
# cleanup after closing.
|
22
22
|
def on_close
|
data/lib/iodine/protocol.rb
CHANGED
@@ -47,6 +47,11 @@ module Iodine
|
|
47
47
|
# the argument or options Hash passed to the initializer as a second argument (the first argument MUST be the IO object).
|
48
48
|
# the value is usually `nil` unless the protocol instance was created by a different protocol while "upgrading" from one protocol to the next.
|
49
49
|
attr_reader :options
|
50
|
+
# The protocol's Mutex locker. It should be locked whenever your code is runing, unless you are
|
51
|
+
# writing asynchronouse code.
|
52
|
+
#
|
53
|
+
# Use with care (or, better yet, don't use).
|
54
|
+
attr_reader :locker
|
50
55
|
|
51
56
|
# Sets the timeout in seconds for IO activity (set timeout within {#on_open}).
|
52
57
|
#
|
data/lib/iodine/settings.rb
CHANGED
@@ -14,6 +14,11 @@ module Iodine
|
|
14
14
|
@thread_count = count
|
15
15
|
end
|
16
16
|
|
17
|
+
# Gets the number of threads in the thread pool used for executing the tasks. Returns `nil` unless previously set or Iodine is running.
|
18
|
+
def threads
|
19
|
+
@thread_count
|
20
|
+
end
|
21
|
+
|
17
22
|
# Sets the number of processes that should be spawned in Server mode. Defaults to 1 (no processes spawned).
|
18
23
|
#
|
19
24
|
# * Forking (spwaning processes) might NOT work on all systems (forking is supported by Ruby on Unix systems).
|
data/lib/iodine/version.rb
CHANGED
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.1.
|
4
|
+
version: 0.1.8
|
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-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|