plezi 0.15.1 → 0.16.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/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
|