plezi 0.15.1 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/bin/ws_shootout +4 -5
- data/lib/plezi/activation.rb +5 -4
- data/lib/plezi/controller/bridge.rb +43 -0
- data/lib/plezi/controller/controller.rb +66 -16
- data/lib/plezi/controller/controller_class.rb +13 -4
- data/lib/plezi/router/router.rb +1 -1
- data/lib/plezi/version.rb +1 -1
- data/plezi.gemspec +1 -1
- data/resources/client.js +6 -3
- data/resources/config.ru +1 -1
- data/resources/ctrlr.rb +5 -4
- data/resources/mini_app.rb +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09945baaea8ad6231605d6d6b72df2b66d369ca413709de0af5809a21e94d634'
|
4
|
+
data.tar.gz: a1659a6945166b11210cd14bc5ba3d10e00cbae57fe8c5de20b6af6ab92dd876
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 768d697c97ef0eed692f993f1b19bee20021d809d02111aaa310c5b0c6fa67d70f5e64394db7f29889d968e544bae4126994f1b55402ea477815b5440b14219b
|
7
|
+
data.tar.gz: b90e2722ae0b095b41a42769ed2e0d988d6042c41bafa9545e31740cd4316398d415c8dfb64fd6c0d3501687a9f6d494332d1eda0752ad7d9f42882bef38ac70
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,18 @@
|
|
2
2
|
|
3
3
|
***
|
4
4
|
|
5
|
+
Change log v.0.16.0
|
6
|
+
|
7
|
+
**Update**: update gem dependency to utilize `iodine` 0.5.x versions.
|
8
|
+
|
9
|
+
***
|
10
|
+
|
11
|
+
Change log v.0.15.1
|
12
|
+
|
13
|
+
**Fix**: fixed gem dependency to limit the allowed versions of the `iodine` server and protect against changes made to the iodine 0.5.0 pub/sub API.
|
14
|
+
|
15
|
+
***
|
16
|
+
|
5
17
|
Change log v.0.15.0
|
6
18
|
|
7
19
|
**Deprecation**: no more `broadcast`, `unicast`, `multicast` or `write2everyone`... Plezi fully embraced the Pub/Sub design and the [Iodine Extensions to the Rack Websocket Specification Proposal](https://github.com/boazsegev/iodine/blob/master/SPEC-Websocket-Draft.md).
|
data/bin/ws_shootout
CHANGED
@@ -12,17 +12,18 @@ require 'bundler/setup'
|
|
12
12
|
require 'plezi'
|
13
13
|
|
14
14
|
class ShootoutApp
|
15
|
+
CHANNEL = "shootout".freeze
|
15
16
|
# the default HTTP response
|
16
17
|
def index
|
17
18
|
"This application should be used with the websocket-shootout benchmark utility."
|
18
19
|
end
|
19
20
|
def on_open
|
20
|
-
subscribe
|
21
|
+
subscribe CHANNEL
|
21
22
|
end
|
22
23
|
# we won't be using AutoDispatch, but directly using the `on_message` callback.
|
23
24
|
def on_message data
|
24
25
|
if data[0] == 'b' # binary
|
25
|
-
publish(
|
26
|
+
publish(CHANNEL, data)
|
26
27
|
data[0] = 'r'
|
27
28
|
write data
|
28
29
|
return
|
@@ -31,9 +32,7 @@ class ShootoutApp
|
|
31
32
|
if cmd == 'echo'
|
32
33
|
write({type: 'echo', payload: payload}.to_json)
|
33
34
|
else
|
34
|
-
|
35
|
-
# broadcast :push2client, data
|
36
|
-
publish(channel: "shootout", message: ({type: 'broadcast', payload: payload}.to_json))
|
35
|
+
publish(CHANNEL, ({type: 'broadcast', payload: payload}.to_json))
|
37
36
|
write({type: "broadcastResult", payload: payload}.to_json)
|
38
37
|
end
|
39
38
|
rescue
|
data/lib/plezi/activation.rb
CHANGED
@@ -17,13 +17,14 @@ module Plezi
|
|
17
17
|
@plezi_autostart = true if @plezi_autostart.nil?
|
18
18
|
Iodine.patch_rack
|
19
19
|
if((ENV['PL_REDIS_URL'.freeze] ||= ENV['REDIS_URL'.freeze]))
|
20
|
-
|
21
|
-
|
22
|
-
Iodine.
|
20
|
+
ping = ENV['PL_REDIS_TIMEOUT'.freeze] || ENV['REDIS_TIMEOUT'.freeze]
|
21
|
+
ping = ping.to_i if ping
|
22
|
+
Iodine::PubSub.default = Iodine::PubSub::RedisEngine.new(ENV['PL_REDIS_URL'.freeze], ping: ping)
|
23
|
+
Iodine::PubSub.default = Iodine::PubSub::CLUSTER unless Iodine::PubSub.default
|
23
24
|
end
|
24
25
|
at_exit do
|
25
26
|
next if @plezi_autostart == false
|
26
|
-
::Iodine
|
27
|
+
::Iodine.listen2http app: ::Plezi.app
|
27
28
|
::Iodine.start
|
28
29
|
end
|
29
30
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Plezi
|
2
|
+
module Base
|
3
|
+
# This module bridges between the Plezi Controller and the Iodine::Connection .
|
4
|
+
module Bridge
|
5
|
+
CONTROLLER_NAME = "plezi.controller".to_sym
|
6
|
+
CLIENT_NAME = "@_pl__client".to_sym # don't rename without updating Controller
|
7
|
+
# returns a client's controller
|
8
|
+
def controller client
|
9
|
+
client.env[CONTROLLER_NAME]
|
10
|
+
end
|
11
|
+
|
12
|
+
# called when the callback object is linked with a new client
|
13
|
+
def on_open client
|
14
|
+
c = controller(client)
|
15
|
+
c.instance_variable_set(CLIENT_NAME, client)
|
16
|
+
if client.protocol == :sse
|
17
|
+
c.on_sse
|
18
|
+
else
|
19
|
+
c.on_open
|
20
|
+
end
|
21
|
+
end
|
22
|
+
# called when data is available
|
23
|
+
def on_message client, data
|
24
|
+
controller(client).on_message(data)
|
25
|
+
end
|
26
|
+
# called when the server is shutting down, before closing the client
|
27
|
+
# (it's still possible to send messages to the client)
|
28
|
+
def on_shutdown client
|
29
|
+
controller(client).on_shutdown
|
30
|
+
end
|
31
|
+
# called when the client is closed (no longer available)
|
32
|
+
def on_close client
|
33
|
+
controller(client).on_close
|
34
|
+
end
|
35
|
+
# called when all the previous calls to `client.write` have completed
|
36
|
+
# (the local buffer was drained and is now empty)
|
37
|
+
def on_drained client
|
38
|
+
controller(client).on_drained
|
39
|
+
end
|
40
|
+
extend self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -2,11 +2,15 @@ require 'plezi/render/render'
|
|
2
2
|
require 'plezi/controller/identification'
|
3
3
|
require 'plezi/controller/cookies'
|
4
4
|
require 'plezi/controller/controller_class'
|
5
|
+
require 'plezi/controller/bridge'
|
5
6
|
|
6
7
|
module Plezi
|
7
8
|
# This module contains the functionality provided to any Controller class.
|
8
9
|
#
|
9
10
|
# This module will be included within every Class that is asigned to a route, providing the functionality without forcing an inheritance model.
|
11
|
+
#
|
12
|
+
# Any Controller can suppoert WebSocket connections by either implementing an `on_message(data)` callback or setting the `@auto_dispatch` class instance variable to `true`.
|
13
|
+
#
|
10
14
|
module Controller
|
11
15
|
def self.included(base)
|
12
16
|
base.extend ::Plezi::Controller::ClassMethods
|
@@ -35,6 +39,10 @@ module Plezi
|
|
35
39
|
#
|
36
40
|
attr_reader :cookies
|
37
41
|
|
42
|
+
# @private
|
43
|
+
# Used internally to access the Iodine::Connection client data (if available).
|
44
|
+
attr_reader :_pl__client
|
45
|
+
|
38
46
|
# @private
|
39
47
|
# This function is used internally by Plezi, do not call.
|
40
48
|
def _pl_respond(request, response, params)
|
@@ -119,24 +127,48 @@ module Plezi
|
|
119
127
|
::Plezi::Base::Router.url_for self.class, func, params
|
120
128
|
end
|
121
129
|
|
122
|
-
#
|
123
|
-
def id
|
124
|
-
@_pl_id ||= (conn_id && "#{::Plezi::Base::Identification.pid}-#{conn_id.to_s(16)}")
|
125
|
-
end
|
126
|
-
|
127
|
-
# @private
|
128
|
-
# This is the process specific Websocket's ID. This function is here to protect you from yourself. Don't call it.
|
129
|
-
def conn_id
|
130
|
-
defined?(super) && super
|
131
|
-
end
|
132
|
-
|
133
|
-
# Override this method to read / write cookies, perform authentication or perform validation before establishing a Websocket connecion.
|
130
|
+
# Override this method to read / write cookies, perform authentication or perform validation before establishing a Websocket or SSE connecion.
|
134
131
|
#
|
135
132
|
# Return `false` or `nil` to refuse the websocket connection.
|
136
133
|
def pre_connect
|
137
134
|
true
|
138
135
|
end
|
139
136
|
|
137
|
+
# Writes to an SSE / WebSocket connection (raises an error unless the connection was already established).
|
138
|
+
def write data
|
139
|
+
_pl__client.write data
|
140
|
+
end
|
141
|
+
|
142
|
+
# Closes an SSE / WebSocket connection (raises an error unless the connection was already established).
|
143
|
+
def close
|
144
|
+
_pl__client.close
|
145
|
+
end
|
146
|
+
# Tests the known state for an SSE / WebSocket connection (the known state might not be the same as the actual state).
|
147
|
+
def open?
|
148
|
+
_pl__client && _pl__client.open?
|
149
|
+
end
|
150
|
+
# Returns the number of pending `write` operations that need to complete before the next `on_drained` callback is called.
|
151
|
+
def pending
|
152
|
+
return 0 unless _pl__client
|
153
|
+
_pl__client.pending
|
154
|
+
end
|
155
|
+
|
156
|
+
# Subscribes to a Pub/Sub stream / channel or replaces an existing subscription to the same stream / channel (raises an error unless an SSE / WebSocket connection was established).
|
157
|
+
def subscribe *args, &block
|
158
|
+
raise "WebSocket / SSE connection missing" unless _pl__client
|
159
|
+
if(block)
|
160
|
+
_pl__client.subscribe *args, &block
|
161
|
+
else
|
162
|
+
_pl__client.subscribe *args
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Publishes to a Pub/Sub stream / channel (routes to Iodine.publish).
|
167
|
+
def publish *args
|
168
|
+
::Iodine.publish *args
|
169
|
+
end
|
170
|
+
|
171
|
+
|
140
172
|
# Experimental: takes a module to be used for Websocket callbacks events.
|
141
173
|
#
|
142
174
|
# This function can only be called **after** a websocket connection was established (i.e., within the `on_open` callback).
|
@@ -168,6 +200,23 @@ module Plezi
|
|
168
200
|
@_pl_ad_map ||= self.class._pl_ad_map.dup
|
169
201
|
end
|
170
202
|
|
203
|
+
# @private
|
204
|
+
# Overload this method to handle event.
|
205
|
+
def on_open
|
206
|
+
end
|
207
|
+
# @private
|
208
|
+
# Overload this method to handle event.
|
209
|
+
def on_close
|
210
|
+
end
|
211
|
+
# @private
|
212
|
+
# Overload this method to handle event.
|
213
|
+
def on_drained
|
214
|
+
end
|
215
|
+
# @private
|
216
|
+
# Overload this method to handle event.
|
217
|
+
def on_shutdown
|
218
|
+
end
|
219
|
+
|
171
220
|
# @private
|
172
221
|
# This function is used internally by Plezi, for Auto-Dispatch support do not call.
|
173
222
|
def on_message(data)
|
@@ -186,7 +235,7 @@ module Plezi
|
|
186
235
|
puts "AutoDispatch Warnnig: JSON missing/invalid `event` name '#{json[:event]}' for class #{self.class.name}. Closing Connection."
|
187
236
|
close
|
188
237
|
end
|
189
|
-
write("{\"event\":\"_ack_\",\"_EID_\":#{json[:_EID_].to_json}}") if json[:_EID_]
|
238
|
+
_pl__client.write("{\"event\":\"_ack_\",\"_EID_\":#{json[:_EID_].to_json}}") if json[:_EID_]
|
190
239
|
_pl_ad_review __send__(envt, json)
|
191
240
|
end
|
192
241
|
|
@@ -196,9 +245,9 @@ module Plezi
|
|
196
245
|
return data unless self.class._pl_is_ad?
|
197
246
|
case data
|
198
247
|
when Hash
|
199
|
-
write data.to_json
|
248
|
+
_pl__client.write data.to_json
|
200
249
|
when String
|
201
|
-
write data
|
250
|
+
_pl__client.write data
|
202
251
|
# when Array
|
203
252
|
# write data.to_json
|
204
253
|
end
|
@@ -217,7 +266,8 @@ module Plezi
|
|
217
266
|
# This function is used internally by Plezi, do not call.
|
218
267
|
def preform_upgrade
|
219
268
|
return false unless pre_connect
|
220
|
-
request.env[
|
269
|
+
request.env[::Plezi::Base::Bridge::CONTROLLER_NAME] = self
|
270
|
+
request.env['rack.upgrade'.freeze] = ::Plezi::Base::Bridge
|
221
271
|
@params = @params.dup # disable memory saving (used a single object per thread)
|
222
272
|
@_pl_ws_map = self.class._pl_ws_map.dup
|
223
273
|
@_pl_ad_map = self.class._pl_ad_map.dup
|
@@ -19,7 +19,7 @@ module Plezi
|
|
19
19
|
|
20
20
|
# @private
|
21
21
|
# This is used internally by Plezi, do not use.
|
22
|
-
RESERVED_METHODS = [:delete, :create, :update, :new, :show, :pre_connect, :on_open, :on_close, :on_shutdown, :on_message].freeze
|
22
|
+
RESERVED_METHODS = [:delete, :create, :update, :new, :show, :pre_connect, :on_sse, :on_open, :on_close, :on_shutdown, :on_message].freeze
|
23
23
|
# @private
|
24
24
|
# This function is used internally by Plezi, do not call.
|
25
25
|
def _pl_get_map
|
@@ -71,6 +71,12 @@ module Plezi
|
|
71
71
|
@_pl_is_websocket
|
72
72
|
end
|
73
73
|
|
74
|
+
# @private
|
75
|
+
# This function is used internally by Plezi, do not call.
|
76
|
+
def _pl_is_sse?
|
77
|
+
@_pl_is_sse
|
78
|
+
end
|
79
|
+
|
74
80
|
# @private
|
75
81
|
# This function is used internally by Plezi, do not call.
|
76
82
|
def _pl_is_ad?
|
@@ -115,9 +121,11 @@ module Plezi
|
|
115
121
|
# puts "matching against #{params}"
|
116
122
|
case params['_method'.freeze]
|
117
123
|
when :get # since this is common, it's pushed upwards.
|
118
|
-
if env['
|
119
|
-
|
120
|
-
|
124
|
+
if env['rack.upgrade?'.freeze]
|
125
|
+
if (env['rack.upgrade?'.freeze] == :websocket && _pl_is_websocket?) || (env['rack.upgrade?'.freeze] == :sse && _pl_is_sse?)
|
126
|
+
@_pl_init_global_data ||= ::Plezi.plezi_initialize # why did we do this?
|
127
|
+
return :preform_upgrade
|
128
|
+
end
|
121
129
|
end
|
122
130
|
return :new if _pl_has_new && par_id == 'new'.freeze
|
123
131
|
return meth_id || (_pl_has_show && :show) || nil
|
@@ -143,6 +151,7 @@ module Plezi
|
|
143
151
|
@_pl_has_update = public_instance_methods(false).include?(:update)
|
144
152
|
@_pl_has_delete = public_instance_methods(false).include?(:delete)
|
145
153
|
@_pl_is_websocket = (instance_variable_defined?(:@auto_dispatch) && instance_variable_get(:@auto_dispatch)) || instance_methods(false).include?(:on_message)
|
154
|
+
@_pl_is_sse = instance_methods(false).include?(:on_sse)
|
146
155
|
_pl_get_map
|
147
156
|
_pl_ad_map
|
148
157
|
_pl_ws_map
|
data/lib/plezi/router/router.rb
CHANGED
data/lib/plezi/version.rb
CHANGED
data/plezi.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ['lib']
|
29
29
|
|
30
|
-
spec.add_dependency 'iodine', '>= 0.
|
30
|
+
spec.add_dependency 'iodine', '>= 0.6.0', '< 0.7.0'
|
31
31
|
spec.add_dependency 'rack', '>= 2.0.0'
|
32
32
|
spec.add_dependency 'bundler', '~> 1.14'
|
33
33
|
# spec.add_dependency 'redcarpet', '> 3.3.0'
|
data/resources/client.js
CHANGED
@@ -109,14 +109,17 @@ PleziClient.prototype.___dispatch =
|
|
109
109
|
}
|
110
110
|
delete this[msg._EID_];
|
111
111
|
}
|
112
|
-
if ((msg.event) && (this[msg.event])
|
112
|
+
if ((msg.event) && (this[msg.event]) &&
|
113
|
+
(typeof this[msg.event] === "function")) {
|
113
114
|
this[msg.event](msg);
|
114
|
-
} else if ((msg.event) && (this['on' + msg.event])
|
115
|
+
} else if ((msg.event) && (this['on' + msg.event]) &&
|
116
|
+
(typeof this[msg.event] === "function")) {
|
115
117
|
console.warn('PleziClient: use a callback called "' + msg.event +
|
116
118
|
'" instead of of "on' + msg.event + '"');
|
117
119
|
this['on' + msg.event](msg);
|
118
120
|
} else {
|
119
|
-
if (this['unknown'] && (msg.event != '_ack_')
|
121
|
+
if (this['unknown'] && (msg.event != '_ack_') &&
|
122
|
+
(typeof this['unknown'] === "function")) {
|
120
123
|
this['unknown'](msg);
|
121
124
|
};
|
122
125
|
}
|
data/resources/config.ru
CHANGED
data/resources/ctrlr.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Replace this sample with real code.
|
2
2
|
class ExampleCtrl
|
3
|
+
CHANNEL = "chat".freeze
|
3
4
|
# HTTP
|
4
5
|
def index
|
5
6
|
# any String returned will be appended to the response. We return a String.
|
@@ -8,18 +9,18 @@ class ExampleCtrl
|
|
8
9
|
|
9
10
|
# Websockets
|
10
11
|
def on_open
|
11
|
-
subscribe
|
12
|
+
subscribe CHANNEL
|
12
13
|
write 'Welcome to appname!'
|
13
14
|
@handle = params['id'.freeze] || 'Somebody'
|
14
|
-
publish
|
15
|
+
publish CHANNEL, "#{ERB::Util.html_escape @handle} joind us :-)"
|
15
16
|
end
|
16
17
|
def on_message(data)
|
17
18
|
data = ERB::Util.html_escape data
|
18
|
-
publish
|
19
|
+
publish CHANNEL, data
|
19
20
|
end
|
20
21
|
|
21
22
|
def on_close
|
22
|
-
publish
|
23
|
+
publish CHANNEL, "#{@handle} left us :-("
|
23
24
|
end
|
24
25
|
|
25
26
|
end
|
data/resources/mini_app.rb
CHANGED
@@ -17,7 +17,7 @@ Dir[File.join '{controllers}', '**', '*.rb'].each { |file| load File.expand_path
|
|
17
17
|
Dir[File.join '{lib}', '**', '*.rb'].each { |file| load File.expand_path(file) }
|
18
18
|
|
19
19
|
## Logging
|
20
|
-
Iodine::
|
20
|
+
Iodine::DEFAULT_HTTP_ARGS[:log] = 1 if Iodine::DEFAULT_HTTP_ARGS[:log].nil?
|
21
21
|
|
22
22
|
# # Optional Scaling (across processes or machines):
|
23
23
|
ENV['PL_REDIS_URL'] ||= ENV['REDIS_URL'] ||
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plezi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: iodine
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.6.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: 0.7.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: 0.6.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: 0.7.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: rack
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/plezi.rb
|
112
112
|
- lib/plezi/activation.rb
|
113
113
|
- lib/plezi/api.rb
|
114
|
+
- lib/plezi/controller/bridge.rb
|
114
115
|
- lib/plezi/controller/controller.rb
|
115
116
|
- lib/plezi/controller/controller_class.rb
|
116
117
|
- lib/plezi/controller/cookies.rb
|