plezi 0.11.2 → 0.12.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 +20 -0
- data/README.md +32 -33
- data/docs/async_helpers.md +90 -40
- data/docs/logging.md +38 -3
- data/docs/routes.md +177 -5
- data/docs/websockets.md +5 -0
- data/lib/plezi.rb +2 -10
- data/lib/plezi/common/api.rb +48 -101
- data/lib/plezi/common/defer.rb +4 -4
- data/lib/plezi/common/dsl.rb +13 -24
- data/lib/plezi/common/redis.rb +9 -5
- data/lib/plezi/common/settings.rb +4 -24
- data/lib/plezi/handlers/controller_core.rb +7 -14
- data/lib/plezi/handlers/controller_magic.rb +12 -10
- data/lib/plezi/handlers/http_router.rb +27 -22
- data/lib/plezi/handlers/placebo.rb +40 -33
- data/lib/plezi/handlers/route.rb +233 -234
- data/lib/plezi/handlers/session.rb +2 -2
- data/lib/plezi/handlers/stubs.rb +7 -0
- data/lib/plezi/handlers/ws_object.rb +25 -15
- data/lib/plezi/helpers/http_sender.rb +3 -3
- data/lib/plezi/helpers/magic_helpers.rb +3 -3
- data/lib/plezi/version.rb +1 -1
- data/plezi.gemspec +1 -1
- data/resources/config.ru +12 -18
- data/resources/environment.rb +6 -7
- data/resources/mini_app.rb +22 -22
- data/resources/redis_config.rb +4 -2
- data/test/plezi_tests.rb +76 -87
- data/websocket chatroom.md +3 -5
- metadata +6 -6
- data/docs/http_helpers.md +0 -9
data/lib/plezi/common/defer.rb
CHANGED
@@ -3,19 +3,19 @@ module Plezi
|
|
3
3
|
|
4
4
|
module_function
|
5
5
|
|
6
|
-
# Defers any missing methods to the
|
6
|
+
# Defers any missing methods to the Iodine Library.
|
7
7
|
def method_missing name, *args, &block
|
8
8
|
return super unless REACTOR_METHODS.include? name
|
9
|
-
::
|
9
|
+
::Iodine.__send__ name, *args, &block
|
10
10
|
end
|
11
|
-
# Defers any missing methods to the
|
11
|
+
# Defers any missing methods to the Iodine Library.
|
12
12
|
def respond_to_missing?(name, include_private = false)
|
13
13
|
REACTOR_METHODS.include?(name) || super
|
14
14
|
end
|
15
15
|
|
16
16
|
protected
|
17
17
|
|
18
|
-
REACTOR_METHODS = ::
|
18
|
+
REACTOR_METHODS = ::Iodine.public_methods(false)
|
19
19
|
|
20
20
|
end
|
21
21
|
|
data/lib/plezi/common/dsl.rb
CHANGED
@@ -3,22 +3,24 @@ PL = Plezi
|
|
3
3
|
|
4
4
|
unless defined? PLEZI_NON_DSL
|
5
5
|
|
6
|
-
# shortcut for Plezi.listen.
|
6
|
+
# shortcut for Plezi.listen. Deprecated.
|
7
7
|
#
|
8
8
|
def listen(params = {})
|
9
9
|
Plezi.listen params
|
10
10
|
end
|
11
11
|
|
12
|
-
# adds a virtul host
|
12
|
+
# adds a virtul host or switches to an existing host, for routes setup or parameters update.
|
13
13
|
#
|
14
14
|
# accepts:
|
15
15
|
# host_name: a String with the full host name (i.e. "www.google.com" / "mail.google.com")
|
16
|
-
# params:: any of the parameters accepted by the
|
16
|
+
# params:: any of the parameters accepted by the {Plezi.host} command.
|
17
|
+
#
|
18
|
+
# If no host is specified or host name is `false`, the default host would be set as the active host and returned.
|
17
19
|
def host(host_name = false, params = {})
|
18
20
|
Plezi.host host_name, params
|
19
21
|
end
|
20
22
|
|
21
|
-
# adds a route to the last
|
23
|
+
# adds a route to the last (or default) host
|
22
24
|
#
|
23
25
|
# path:: the path for the route
|
24
26
|
# controller:: The controller class which will accept the route.
|
@@ -49,7 +51,7 @@ unless defined? PLEZI_NON_DSL
|
|
49
51
|
#
|
50
52
|
# magic routes make for difficult debugging - the smarter the routes, the more difficult the debugging.
|
51
53
|
# use with care and avoid complex routes when possible. RESTful routes are recommended when possible.
|
52
|
-
#
|
54
|
+
# JSON serving apps are advised to use required parameters and empty sections indicating missing required parameters (i.e. /path///foo/bar///).
|
53
55
|
#
|
54
56
|
def route(path, controller = nil, &block)
|
55
57
|
Plezi.route(path, controller, &block)
|
@@ -74,28 +76,10 @@ unless defined? PLEZI_NON_DSL
|
|
74
76
|
end
|
75
77
|
|
76
78
|
|
77
|
-
|
78
|
-
# finishes setup of the servers and starts them up. This will hange the proceess.
|
79
|
-
#
|
80
|
-
# this method is called automatically by the Plezi framework.
|
81
|
-
#
|
82
|
-
# it is recommended that you DO NOT CALL this method.
|
83
|
-
# if any post shut-down actions need to be performed, use Plezi.on_shutdown instead.
|
84
|
-
def start_services
|
85
|
-
return 0 if defined?(NO_PLEZI_AUTO_START)
|
86
|
-
undef listen
|
87
|
-
undef host
|
88
|
-
undef route
|
89
|
-
undef shared_route
|
90
|
-
Plezi.start
|
91
|
-
end
|
92
|
-
|
93
79
|
# sets information to be used when restarting
|
94
80
|
$PL_SCRIPT = $0
|
95
81
|
$PL_ARGV = $*.dup
|
96
82
|
|
97
|
-
# sets up a generic session-token name based on the script name
|
98
|
-
GRHttp.session_token = "#{($0).split(/[\\\/]/).last.split(/[\s\.]+/).first}_uuid"
|
99
83
|
# restarts the Plezi app with the same arguments as when it was started.
|
100
84
|
#
|
101
85
|
# EXPERIMENTAL
|
@@ -104,5 +88,10 @@ unless defined? PLEZI_NON_DSL
|
|
104
88
|
end
|
105
89
|
|
106
90
|
# sets to start the services once dsl script is finished loading.
|
107
|
-
at_exit
|
91
|
+
at_exit do
|
92
|
+
undef listen
|
93
|
+
undef host
|
94
|
+
undef route
|
95
|
+
undef shared_route
|
96
|
+
end
|
108
97
|
end
|
data/lib/plezi/common/redis.rb
CHANGED
@@ -24,18 +24,18 @@ module Plezi
|
|
24
24
|
next if data[:server] == Plezi::Settings.uuid
|
25
25
|
data[:type] = Object.const_get(data[:type]) unless data[:type].nil? || data[:type] == :all
|
26
26
|
if data[:target]
|
27
|
-
|
27
|
+
data[:type].___faild_unicast( data ) unless Iodine::Http::Websockets.unicast data[:target], data
|
28
28
|
else
|
29
|
-
|
29
|
+
Iodine::Http::Websockets.broadcast data
|
30
30
|
end
|
31
31
|
rescue => e
|
32
|
-
|
33
|
-
|
32
|
+
Iodine.error "The following could be a security breach attempt:"
|
33
|
+
Iodine.error e
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
rescue => e
|
38
|
-
|
38
|
+
Iodine.error e
|
39
39
|
retry
|
40
40
|
end
|
41
41
|
end
|
@@ -46,6 +46,10 @@ module Plezi
|
|
46
46
|
return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis
|
47
47
|
inner_init_redis
|
48
48
|
end
|
49
|
+
def away? server
|
50
|
+
return true unless get_redis
|
51
|
+
@redis.pubsub('CHANNELS', server).empty?
|
52
|
+
end
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
@@ -6,26 +6,6 @@ module Plezi
|
|
6
6
|
|
7
7
|
module_function
|
8
8
|
|
9
|
-
# The maximum number of threads that are used for concurrency.
|
10
|
-
def max_threads
|
11
|
-
@max_threads ||= 30
|
12
|
-
end
|
13
|
-
# Sets the maximum number of threads that are used for concurrency.
|
14
|
-
def max_threads=val
|
15
|
-
@max_threads = val
|
16
|
-
end
|
17
|
-
|
18
|
-
# The number of second between pings automatically sent by an open websocket.
|
19
|
-
def autoping
|
20
|
-
@autoping ||= 45
|
21
|
-
end
|
22
|
-
# Sets the number of second between pings automatically sent by an open websocket.
|
23
|
-
#
|
24
|
-
# Set to nil or false to disable auto-pinging.
|
25
|
-
def autoping=val
|
26
|
-
@autoping = 45
|
27
|
-
end
|
28
|
-
|
29
9
|
# Sets the Redis Channel Name.
|
30
10
|
def redis_channel_name=val
|
31
11
|
return false unless defined? Redis
|
@@ -35,7 +15,7 @@ module Plezi
|
|
35
15
|
# Returns the Redis Channel Name used by this app.
|
36
16
|
# @return [String]
|
37
17
|
def redis_channel_name
|
38
|
-
@redis_channel_name ||= '
|
18
|
+
@redis_channel_name ||= "#{File.basename($0, '.*')}_Redis_Channel"
|
39
19
|
end
|
40
20
|
|
41
21
|
# Sets the message byte size limit for a Websocket message. Defaults to 0 (no limit)
|
@@ -45,11 +25,11 @@ module Plezi
|
|
45
25
|
#
|
46
26
|
# If the sessage size limit is exceeded, the disconnection will be immidiate as an attack will be assumed. The protocol's normal disconnect sequesnce will be discarded.
|
47
27
|
def ws_message_size_limit=val
|
48
|
-
|
28
|
+
Iodine::Http::Websockets.message_size_limit = val
|
49
29
|
end
|
50
30
|
# Gets the message byte size limit for a Websocket message. Defaults to 0 (no limit)
|
51
31
|
def ws_message_size_limit
|
52
|
-
|
32
|
+
Iodine::Http::Websockets.message_size_limit
|
53
33
|
end
|
54
34
|
|
55
35
|
# This Server's UUID, for Redis and unicasting identification.
|
@@ -58,4 +38,4 @@ module Plezi
|
|
58
38
|
end
|
59
39
|
end
|
60
40
|
end
|
61
|
-
|
41
|
+
Iodine.threads = 30
|
@@ -16,7 +16,7 @@ module Plezi
|
|
16
16
|
@request = request
|
17
17
|
@params = request.params
|
18
18
|
@flash = response.flash
|
19
|
-
@host_params = request
|
19
|
+
@host_params = request[:host_settings]
|
20
20
|
@response = response
|
21
21
|
@cookies = request.cookies
|
22
22
|
# # \@response["content-type"] ||= ::Plezi.default_content_type
|
@@ -38,31 +38,24 @@ module Plezi
|
|
38
38
|
# finish if the response was sent
|
39
39
|
return false if response.headers_sent?
|
40
40
|
# make sure that the session object is available for websocket connections
|
41
|
-
|
41
|
+
session
|
42
42
|
# complete handshake
|
43
43
|
return self
|
44
44
|
end
|
45
45
|
# handles websocket opening.
|
46
|
-
def on_open
|
47
|
-
# set broadcasts and return true
|
48
|
-
@response = ws
|
49
|
-
ws.autoping Plezi::Settings.autoping if Plezi::Settings.autoping
|
50
|
-
# create the redis connection (in case this in the first instance of this class)
|
51
|
-
Plezi.redis
|
46
|
+
def on_open
|
52
47
|
super() if defined?(super)
|
53
48
|
end
|
54
49
|
# handles websocket messages.
|
55
|
-
def on_message
|
56
|
-
super
|
50
|
+
def on_message data
|
51
|
+
super if defined?(super)
|
57
52
|
end
|
58
53
|
# handles websocket being closed.
|
59
|
-
def on_close
|
60
|
-
super
|
54
|
+
def on_close
|
55
|
+
super if defined? super
|
61
56
|
end
|
62
57
|
|
63
58
|
# Inner Routing
|
64
|
-
#
|
65
|
-
#
|
66
59
|
def _route_path_to_methods_and_set_the_response_
|
67
60
|
#run :before filter
|
68
61
|
return false if self.class.has_method?(:before) && self.before == false
|
@@ -42,7 +42,7 @@ module Plezi
|
|
42
42
|
|
43
43
|
# Session data can be stored here (session data will be stored on the Redis server, if Redis is available).
|
44
44
|
#
|
45
|
-
# The first time this method is called, the
|
45
|
+
# The first time this method is called, the `n object will be created. The session object must be created BEFORE the headers are set , if it is to be used.
|
46
46
|
#
|
47
47
|
# Sessions are not automatically created, because they require more resources. The one exception is the Websocket connection that will force a session object into existence, as it's very common to use session data in Websocket connections and the extra connection time is less relevant for a long term connection.
|
48
48
|
def session
|
@@ -56,7 +56,7 @@ module Plezi
|
|
56
56
|
# these cookies will live for one successful request to a Controller and will then be removed.
|
57
57
|
attr_reader :flash
|
58
58
|
|
59
|
-
# the parameters used to create the host (the parameters passed to the `
|
59
|
+
# the parameters used to create the host (the parameters passed to the `Plezi.host`).
|
60
60
|
attr_reader :host_params
|
61
61
|
|
62
62
|
# this method does two things.
|
@@ -79,7 +79,6 @@ module Plezi
|
|
79
79
|
#
|
80
80
|
def redirect_to url, options = {}
|
81
81
|
return super *[] if defined? super
|
82
|
-
raise 'Cannot redirect once a Websocket connection was established.' if response.is_a?(::GRHttp::WSEvent)
|
83
82
|
raise 'Cannot redirect after headers were sent.' if response.headers_sent?
|
84
83
|
url = "#{request.base_url}/#{url.to_s.gsub('_', '/')}" if url.is_a?(Symbol) || ( url.is_a?(String) && url.empty? ) || url.nil?
|
85
84
|
# redirect
|
@@ -129,8 +128,6 @@ module Plezi
|
|
129
128
|
# filename:: sets a filename for the browser to "save as". defaults to empty.
|
130
129
|
#
|
131
130
|
def send_data data, options = {}
|
132
|
-
raise 'Cannot use "send_data" once a Websocket connection was established.' if response.is_a?(::GRHttp::WSEvent)
|
133
|
-
# return response.write(data) if response.is_a?(::GRHttp::WSEvent)
|
134
131
|
raise 'Cannot use "send_data" after headers were sent' if response.headers_sent?
|
135
132
|
Plezi.warn 'HTTP response buffer is cleared by `#send_data`' if response.body && response.body.any? && response.body.clear
|
136
133
|
response << data
|
@@ -180,7 +177,12 @@ module Plezi
|
|
180
177
|
options[:type] ||= 'html'.freeze
|
181
178
|
options[:locale] ||= params[:locale].to_sym if params[:locale]
|
182
179
|
#update content-type header
|
183
|
-
|
180
|
+
case options[:type]
|
181
|
+
when 'html', 'js', 'txt'
|
182
|
+
response['content-type'] ||= "#{MimeTypeHelper::MIME_DICTIONARY[".#{options[:type]}".freeze]}; charset=utf-8".freeze
|
183
|
+
else
|
184
|
+
response['content-type'] ||= "#{MimeTypeHelper::MIME_DICTIONARY[".#{options[:type]}".freeze]}".freeze
|
185
|
+
end
|
184
186
|
# Circumvents I18n persistance issues (live updating and thread data storage).
|
185
187
|
I18n.locale = options[:locale] || I18n.default_locale if defined?(I18n) # sets the locale to nil for default behavior even if the locale was set by a previous action - removed: # && options[:locale]
|
186
188
|
# find template and create template object
|
@@ -201,19 +203,19 @@ module Plezi
|
|
201
203
|
# respond to websocket special case
|
202
204
|
return :pre_connect if request.upgrade?
|
203
205
|
# respond to save 'new' special case
|
204
|
-
return (self.class.has_method?(:save) ? :save : false) if request.request_method
|
206
|
+
return (self.class.has_method?(:save) ? :save : false) if (request.request_method =~ /POST|PUT|PATCH/i.freeze) && (params[:id].nil? || params[:id] == 'new')
|
205
207
|
# set DELETE method if simulated
|
206
208
|
request.request_method = 'DELETE' if params[:_method].to_s.downcase == 'delete'
|
207
209
|
# respond to special :id routing
|
208
210
|
return params[:id].to_s.to_sym if params[:id] && self.class.has_exposed_method?(params[:id].to_s.to_sym)
|
209
211
|
#review general cases
|
210
212
|
case request.request_method
|
211
|
-
when 'GET', 'HEAD'
|
213
|
+
when 'GET'.freeze, 'HEAD'.freeze
|
212
214
|
return (self.class.has_method?(:index) ? :index : false) unless params[:id]
|
213
215
|
return (self.class.has_method?(:show) ? :show : false)
|
214
|
-
when 'POST', 'PUT', 'PATCH'
|
216
|
+
when 'POST'.freeze, 'PUT'.freeze, 'PATCH'.freeze
|
215
217
|
return (self.class.has_method?(:update) ? :update : false)
|
216
|
-
when 'DELETE'
|
218
|
+
when 'DELETE'.freeze
|
217
219
|
return (self.class.has_method?(:delete) ? :delete : false)
|
218
220
|
end
|
219
221
|
false
|
@@ -4,7 +4,7 @@ module Plezi
|
|
4
4
|
|
5
5
|
#####
|
6
6
|
# handles the HTTP Routing
|
7
|
-
|
7
|
+
module HTTPRouter
|
8
8
|
|
9
9
|
class Host
|
10
10
|
attr_reader :params
|
@@ -12,8 +12,9 @@ module Plezi
|
|
12
12
|
def initialize params
|
13
13
|
@params = params
|
14
14
|
@routes = []
|
15
|
-
params[:assets_public_regex] = /^#{params[:assets_public].to_s.chomp('/')}
|
16
|
-
params[:
|
15
|
+
@params[:assets_public_regex] = /^#{params[:assets_public].to_s.chomp('/')}\//i.freeze
|
16
|
+
@params[:assets_public_length] = @params[:assets_public].to_s.chomp('/').length + 1
|
17
|
+
@params[:assets_refuse_templates] = /(#{AssetManager.all_extentions.join('|')}|\.\.\/)$/i.freeze
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -25,23 +26,25 @@ module Plezi
|
|
25
26
|
def on_upgrade request, response
|
26
27
|
host = get_host(request[:host_name].to_s.downcase) || @hosts[:default]
|
27
28
|
return false unless host
|
28
|
-
request
|
29
|
+
request[:host_settings] = host.params
|
29
30
|
# return if a route answered the request
|
30
31
|
host.routes.each {|r| a = r.on_request(request, response); return a if a}
|
31
32
|
# websockets should cut out here
|
32
33
|
false
|
33
34
|
end
|
34
|
-
# initializes
|
35
|
+
# initializes the HTTP router (the normal Handler for HTTP requests)
|
35
36
|
#
|
36
37
|
# the router holds the different hosts and sends them messages/requests.
|
37
|
-
|
38
|
-
|
39
|
-
@active_host = nil
|
40
|
-
end
|
38
|
+
@hosts = {}
|
39
|
+
@active_host = nil
|
41
40
|
|
42
|
-
# adds a host to the router (or activates an existing host to add new routes). accepts a host name and any parameters not related to the actual connection (ssl etc') (see {Plezi.
|
41
|
+
# adds a host to the router (or activates an existing host to add new routes). accepts a host name and any parameters not related to the actual connection (ssl etc') (see {Plezi.host})
|
43
42
|
def add_host host_name, params = {}
|
44
|
-
|
43
|
+
params[:index_file] ||= 'index.html'
|
44
|
+
params[:assets_public] ||= '/assets'
|
45
|
+
params[:assets_public].chomp! '/'
|
46
|
+
params[:public] ||= params[:root] # backwards compatability
|
47
|
+
host_name = (host_name.is_a?(String) ? host_name.to_s.downcase : (host_name.is_a?(Regexp) ? host_name : :default))
|
45
48
|
@active_host = get_host(host_name) || ( @hosts[host_name] = Host.new(params) )
|
46
49
|
add_alias host_name, *params[:alias] if params[:alias]
|
47
50
|
@active_host
|
@@ -49,21 +52,21 @@ module Plezi
|
|
49
52
|
# adds an alias to an existing host name (normally through the :alias parameter in the `add_host` method).
|
50
53
|
def add_alias host_name, *aliases
|
51
54
|
host = get_host host_name
|
52
|
-
|
55
|
+
host ||= add_host :default
|
53
56
|
aliases.each {|a| @hosts[a.to_s.downcase] = host}
|
54
57
|
true
|
55
58
|
end
|
56
59
|
|
57
60
|
# adds a route to the active host. The active host is the last host referenced by the `add_host`.
|
58
61
|
def add_route path, controller, &block
|
59
|
-
|
60
|
-
@active_host.routes << Route.new(path, controller, &block)
|
62
|
+
@active_host ||= add_host :default
|
63
|
+
@active_host.routes << ::Plezi::Base::Route.new(path, controller, &block)
|
61
64
|
end
|
62
65
|
|
63
66
|
# adds a route to all existing hosts.
|
64
67
|
def add_shared_route path, controller, &block
|
65
|
-
|
66
|
-
@hosts.each {|n, h| h.routes << Route.new(path, controller, &block) }
|
68
|
+
add_host :default if @hosts.empty?
|
69
|
+
@hosts.each {|n, h| h.routes << ::Plezi::Base::Route.new(path, controller, &block) }
|
67
70
|
end
|
68
71
|
|
69
72
|
# handles requests send by the HTTP Protocol (HTTPRequest objects)
|
@@ -71,7 +74,7 @@ module Plezi
|
|
71
74
|
begin
|
72
75
|
host = get_host(request[:host_name].to_s.downcase) || @hosts[:default]
|
73
76
|
return false unless host
|
74
|
-
request
|
77
|
+
request[:host_settings] = host.params
|
75
78
|
# render any assets?
|
76
79
|
return true if render_assets request, response, host.params
|
77
80
|
# send static file, if exists and root is set.
|
@@ -79,10 +82,10 @@ module Plezi
|
|
79
82
|
# return if a route answered the request
|
80
83
|
host.routes.each {|r| a = r.on_request(request, response); return a if a}
|
81
84
|
#return error code or 404 not found
|
82
|
-
return Base::HTTPSender.send_by_code request, response, 404 unless
|
85
|
+
return Base::HTTPSender.send_by_code request, response, 404 unless ( @avoid_404 ||= ( Iodine::Http.on_http == ::Iodine::Http::Rack ? 1 : 0 ) ) == 1
|
83
86
|
rescue => e
|
84
87
|
# return 500 internal server error.
|
85
|
-
|
88
|
+
Iodine.error e
|
86
89
|
Base::HTTPSender.send_by_code request, response, 500
|
87
90
|
end
|
88
91
|
end
|
@@ -105,14 +108,14 @@ module Plezi
|
|
105
108
|
return true if params[:assets_callback] && params[:assets_callback].call(request, response)
|
106
109
|
|
107
110
|
# get file requested
|
108
|
-
source_file = File.join(params[:assets], *(request.path
|
111
|
+
source_file = File.join(params[:assets], *(request.path[params[:assets_public_length]..-1].split('/')))
|
109
112
|
|
110
113
|
|
111
114
|
# stop if file name is reserved / has security issues
|
112
115
|
return false if File.directory?(source_file) || source_file =~ params[:assets_refuse_templates]
|
113
116
|
|
114
117
|
# set where to store the rendered asset
|
115
|
-
target_file = File.join( params[:public].to_s,
|
118
|
+
target_file = File.join( params[:public].to_s, *request.path.split('/') )
|
116
119
|
|
117
120
|
# send the file if it exists (no render needed)
|
118
121
|
if File.exists?(source_file)
|
@@ -134,7 +137,9 @@ module Plezi
|
|
134
137
|
# return false if an asset couldn't be rendered and wasn't found.
|
135
138
|
return false
|
136
139
|
end
|
137
|
-
|
140
|
+
extend self
|
138
141
|
end
|
142
|
+
Iodine::Http.on_http ::Plezi::Base::HTTPRouter
|
143
|
+
Iodine::Http.on_websocket ::Plezi::Base::HTTPRouter.upgrade_proc
|
139
144
|
end
|
140
145
|
end
|
@@ -3,15 +3,27 @@ module Plezi
|
|
3
3
|
# This API wil allows you to listen to Websocket Broadcasts sent to any object and to accept unicasts
|
4
4
|
# even when NOT connected to a websocket.
|
5
5
|
#
|
6
|
-
# Simpley create a class to handle any events and call `Plezi::Placebo.new ClassName` :
|
6
|
+
# Simpley create a class to handle any events and call `Plezi::Placebo.new ClassName` or use the {Plezi.start_placebo} shortcut:
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# end
|
8
|
+
# # Important: set up a unique - but shared - main redis channel for BOTH Apps (The Plezi and the Placebo).
|
9
|
+
# Plezi::Settings.redis_channel_name = 'unique_channel_name_for_app_b24270e2'
|
10
|
+
# # Important: set Plezi's auo-Redis pub/sub server.
|
11
|
+
# ENV['PL_REDIS_URL'] ||= "redis://redis:password@redis.server.com:9999"
|
13
12
|
#
|
14
|
-
#
|
13
|
+
# # create the Placebo bridge handler
|
14
|
+
# class PleziBridge
|
15
|
+
# def on_open
|
16
|
+
# multicast :print, "Hello from Placebo!"
|
17
|
+
# end
|
18
|
+
# def print data
|
19
|
+
# Iodine.info "Placebo message: #{data}"
|
20
|
+
# puts "Placebo message: #{data}"
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # initiate Placebo mode using the bridge class. it's possible to create multiple
|
25
|
+
# # it's possible to create multiple bridge classes this way.
|
26
|
+
# Plezi.start_placebo(PleziBridge)
|
15
27
|
#
|
16
28
|
# A new instance will be created and that instance will answer any broadcasts, for ALL possible
|
17
29
|
# Plezi controllers, as long as it had a method defined that is capable to handle the broadcast.
|
@@ -37,15 +49,17 @@ module Plezi
|
|
37
49
|
module InstanceMethods
|
38
50
|
public
|
39
51
|
attr_accessor :io
|
40
|
-
def initialize
|
41
|
-
@
|
42
|
-
@
|
52
|
+
def initialize io_in, io_out, request
|
53
|
+
@io_in = io_in
|
54
|
+
@io_out = io_out
|
55
|
+
@request = request
|
43
56
|
super()
|
44
57
|
end
|
45
|
-
#
|
58
|
+
# Cleanup on disconnection
|
46
59
|
def on_close
|
60
|
+
io_out.close unless io_out.closed?
|
47
61
|
return super() if defined? super
|
48
|
-
|
62
|
+
Iodine.warn "Placebo #{self.class.superclass.name} disconnected. Ignore if this message appears during shutdown."
|
49
63
|
end
|
50
64
|
def placebo?
|
51
65
|
true
|
@@ -60,17 +74,19 @@ module Plezi
|
|
60
74
|
end
|
61
75
|
end
|
62
76
|
end
|
63
|
-
class PlaceboIO <
|
64
|
-
|
65
|
-
|
77
|
+
class PlaceboIO < ::Iodine::Http::Websockets
|
78
|
+
# emulate Iodine::Protocol#timeout?
|
79
|
+
def timeout? time
|
80
|
+
false
|
66
81
|
end
|
82
|
+
# emulate Iodine::Protocol#call
|
67
83
|
def call
|
68
|
-
|
69
|
-
|
84
|
+
read
|
85
|
+
Iodine.warn "Placebo IO recieved IO signal - this is unexpected..."
|
70
86
|
end
|
71
|
-
|
72
|
-
|
73
|
-
|
87
|
+
# override "go_away"
|
88
|
+
def go_away
|
89
|
+
close
|
74
90
|
end
|
75
91
|
end
|
76
92
|
end
|
@@ -86,19 +102,10 @@ module Plezi
|
|
86
102
|
Object.const_set(new_class_name, new_class)
|
87
103
|
end
|
88
104
|
i, o = IO.pipe
|
89
|
-
|
90
|
-
new_class.new(
|
105
|
+
req = {}
|
106
|
+
handler = new_class.new(i, o, req)
|
107
|
+
io = Placebo::Base::PlaceboIO.new i, handler, req
|
108
|
+
handler
|
91
109
|
end
|
92
110
|
end
|
93
111
|
end
|
94
|
-
|
95
|
-
|
96
|
-
# class A
|
97
|
-
# def _hi
|
98
|
-
# 'hi'
|
99
|
-
# end
|
100
|
-
# end
|
101
|
-
# Plezi::Placebo.new A
|
102
|
-
# a = nil
|
103
|
-
# GReactor.each {|h| a= h}
|
104
|
-
# a[:websocket_handler].on_broadcast GRHttp::WSEvent.new(nil, type: true, data: [], method: :_hi)
|