plezi 0.10.16 → 0.10.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/plezi/common/dsl.rb +1 -1
- data/lib/plezi/common/redis.rb +55 -33
- data/lib/plezi/handlers/controller_core.rb +2 -1
- data/lib/plezi/handlers/controller_magic.rb +8 -2
- data/lib/plezi/handlers/route.rb +2 -2
- data/lib/plezi/handlers/session.rb +2 -1
- data/lib/plezi/handlers/ws_object.rb +2 -0
- data/lib/plezi/oauth/auth_controller.rb +1 -1
- data/lib/plezi/version.rb +1 -1
- data/plezi.gemspec +1 -1
- data/resources/mini_app.rb +1 -1
- data/resources/mini_welcome_page.html +3 -1
- data/resources/websockets.js +1 -0
- data/resources/welcome_page.html +3 -1
- data/test/console +2 -3
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c509d0a1c5c9aa5fec5827c0f7b6a27dbf143840
|
4
|
+
data.tar.gz: c1cef78d006408e83140295a0a392553ee8b1521
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edfc62fc655f782518bc355b0fd83b6784e141b445867f4307c948b8d92dd79d5d20dbb7b843143cc4e45f4cf0a9a1867b7a9df433e952c57b117644a6c2453c
|
7
|
+
data.tar.gz: 46af810bb76558461e3933645e9e6064109228257e57aea3f09063425a3676fcf61a06d5cb96b6849aed99376f56dc29f14f794ae628b981a98d2d0e7eb774e6
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
***
|
4
4
|
|
5
|
+
Change log v.0.10.17
|
6
|
+
|
7
|
+
**Update**: Requires a newer version of the GRHttp server and GReactor, building on it's WSClient and HTTP decoding improvements.
|
8
|
+
|
9
|
+
**Security**: Redis connection broadcasting now enforces `safe_load`, so that even id the Redis server and it's data are compromized, it should not lead to foreign code execution. Please note that this will enforce limits on session data as well as on websocket broadcasting.
|
10
|
+
|
11
|
+
**Sessions**: Sessions are now avoided unless explicitly created or unless a websocket connection is established. The reason being that unless Redis is defined, sessions are stored in-memory and end up requiring a lot of space. File storage might be considered for future releases.
|
12
|
+
|
13
|
+
***
|
14
|
+
|
5
15
|
Change log v.0.10.16
|
6
16
|
|
7
17
|
**Fix**: Requires a newer version of the GRHttp server, which fixs an issue with Firefox's websocket implementation.
|
data/lib/plezi/common/dsl.rb
CHANGED
@@ -95,7 +95,7 @@ unless defined? PLEZI_NON_DSL
|
|
95
95
|
$PL_ARGV = $*.dup
|
96
96
|
|
97
97
|
# sets up a generic session-token name based on the script name
|
98
|
-
GRHttp.session_token = "#{($0).split(/[\\\/]/).last.split(/[\s]+/).first}_uuid"
|
98
|
+
GRHttp.session_token = "#{($0).split(/[\\\/]/).last.split(/[\s\.]+/).first}_uuid"
|
99
99
|
# restarts the Plezi app with the same arguments as when it was started.
|
100
100
|
#
|
101
101
|
# EXPERIMENTAL
|
data/lib/plezi/common/redis.rb
CHANGED
@@ -1,6 +1,53 @@
|
|
1
1
|
|
2
2
|
module Plezi
|
3
3
|
|
4
|
+
module Base
|
5
|
+
module AutoRedis
|
6
|
+
@redis_locker ||= Mutex.new
|
7
|
+
@redis = @redis_sub_thread = nil
|
8
|
+
module_function
|
9
|
+
def inner_init_redis
|
10
|
+
return false unless ENV['PL_REDIS_URL'] && defined?(::Redis)
|
11
|
+
@redis_locker.synchronize do
|
12
|
+
return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis # repeat the test once syncing is done.
|
13
|
+
@redis_uri ||= URI.parse(ENV['PL_REDIS_URL'])
|
14
|
+
@redis.quit if @redis
|
15
|
+
@redis = ::Redis.new(host: @redis_uri.host, port: @redis_uri.port, password: @redis_uri.password)
|
16
|
+
raise "Redis connction failed for: #{ENV['PL_REDIS_URL']}" unless @redis
|
17
|
+
@redis_sub_thread = Thread.new do
|
18
|
+
begin
|
19
|
+
safe_types = [Symbol, Date, Time, Encoding, Struct, Regexp, Range, Set]
|
20
|
+
::Redis.new(host: @redis_uri.host, port: @redis_uri.port, password: @redis_uri.password).subscribe(Plezi::Settings.redis_channel_name, Plezi::Settings.uuid) do |on|
|
21
|
+
on.message do |channel, msg|
|
22
|
+
begin
|
23
|
+
data = YAML.safe_load(msg, safe_types)
|
24
|
+
next if data[:server] == Plezi::Settings.uuid
|
25
|
+
data[:type] = Object.const_get(data[:type]) unless data[:type].nil? || data[:type] == :all
|
26
|
+
if data[:target]
|
27
|
+
GRHttp::Base::WSHandler.unicast data[:target], data
|
28
|
+
else
|
29
|
+
GRHttp::Base::WSHandler.broadcast data
|
30
|
+
end
|
31
|
+
rescue => e
|
32
|
+
GReactor.error e
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
rescue => e
|
37
|
+
GReactor.error e
|
38
|
+
retry
|
39
|
+
end
|
40
|
+
end
|
41
|
+
@redis
|
42
|
+
end
|
43
|
+
end
|
44
|
+
def get_redis
|
45
|
+
return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis
|
46
|
+
inner_init_redis
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
4
51
|
module_function
|
5
52
|
|
6
53
|
# Reviews the Redis connection, sets it up if it's missing and returns the Redis connection.
|
@@ -10,41 +57,16 @@ module Plezi
|
|
10
57
|
# ENV['PL_REDIS_URL'] = ENV['REDISCLOUD_URL']`
|
11
58
|
# or
|
12
59
|
# ENV['PL_REDIS_URL'] = "redis://username:password@my.host:6379"
|
60
|
+
#
|
61
|
+
# Accepts an optional block that will receive the Redis connection object. i.e.
|
62
|
+
#
|
63
|
+
# Plezi.redis {|r| r.connected? }
|
64
|
+
#
|
65
|
+
# Returns the Redis object or the block's returned value (if a block is provided).
|
13
66
|
def redis
|
14
|
-
|
15
|
-
|
16
|
-
@redis_locker ||= Mutex.new
|
17
|
-
@redis_locker.synchronize do
|
18
|
-
return @redis if (@redis_sub_thread && @redis_sub_thread.alive?) && @redis # repeat the test once syncing is done.
|
19
|
-
@redis_uri ||= URI.parse(ENV['PL_REDIS_URL'])
|
20
|
-
@redis ||= Redis.new(host: @redis_uri.host, port: @redis_uri.port, password: @redis_uri.password)
|
21
|
-
raise "Redis connction failed for: #{ENV['PL_REDIS_URL']}" unless @redis
|
22
|
-
@redis_sub_thread = Thread.new do
|
23
|
-
begin
|
24
|
-
Redis.new(host: @redis_uri.host, port: @redis_uri.port, password: @redis_uri.password).subscribe(Plezi::Settings.redis_channel_name, Plezi::Settings.uuid) do |on|
|
25
|
-
on.message do |channel, msg|
|
26
|
-
begin
|
27
|
-
data = YAML.load(msg)
|
28
|
-
next if data[:server] == Plezi::Settings.uuid
|
29
|
-
if data[:target]
|
30
|
-
GRHttp::Base::WSHandler.unicast data[:target], data
|
31
|
-
else
|
32
|
-
GRHttp::Base::WSHandler.broadcast data
|
33
|
-
end
|
34
|
-
rescue => e
|
35
|
-
Reactor.error e
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
rescue => e
|
40
|
-
Reactor.error e
|
41
|
-
retry
|
42
|
-
end
|
43
|
-
end
|
67
|
+
if r = Plezi::Base::AutoRedis.get_redis
|
68
|
+
return (block_given? ? yield(r) : r)
|
44
69
|
end
|
45
|
-
@redis
|
46
|
-
rescue => e
|
47
|
-
Reactor.error e
|
48
70
|
false
|
49
71
|
end
|
50
72
|
alias :redis_connection :redis
|
@@ -19,7 +19,6 @@ module Plezi
|
|
19
19
|
@host_params = request.io[:params]
|
20
20
|
@response = response
|
21
21
|
@cookies = request.cookies
|
22
|
-
@session = response.session
|
23
22
|
# # \@response["content-type"] ||= ::Plezi.default_content_type
|
24
23
|
super()
|
25
24
|
end
|
@@ -38,6 +37,8 @@ module Plezi
|
|
38
37
|
return false if (defined?(super) && !super)
|
39
38
|
# finish if the response was sent
|
40
39
|
return false if response.headers_sent?
|
40
|
+
# make sure that the session object is available for websocket connections
|
41
|
+
response.session
|
41
42
|
# complete handshake
|
42
43
|
return self
|
43
44
|
end
|
@@ -34,8 +34,14 @@ module Plezi
|
|
34
34
|
# Cookies and some other data must be set BEFORE the response's headers are sent.
|
35
35
|
attr_reader :cookies
|
36
36
|
|
37
|
-
# Session data can be stored here (
|
38
|
-
|
37
|
+
# Session data can be stored here (session data will be stored on the Redis server, if Redis is available).
|
38
|
+
#
|
39
|
+
# The first time this method is called, the session object will be created. The session object must be created BEFORE the headers are set , if it is to be used.
|
40
|
+
#
|
41
|
+
# Sessions are not automatically created, because they are memory hogs. The one exception is the Websocket connection that will force a session object into existence.
|
42
|
+
def session
|
43
|
+
response.session
|
44
|
+
end
|
39
45
|
|
40
46
|
# the HTTPResponse **OR** the WSResponse object that formats the response and sends it. use `response << data`. This object can be used to send partial data (such as headers, or partial html content) in blocking mode as well as sending data in the default non-blocking mode.
|
41
47
|
attr_reader :response
|
data/lib/plezi/handlers/route.rb
CHANGED
@@ -112,7 +112,7 @@ module Plezi
|
|
112
112
|
param_name = param_name[1].to_sym if param_name
|
113
113
|
|
114
114
|
if param_name && dest[param_name]
|
115
|
-
url << GRHttp::HTTP.
|
115
|
+
url << GRHttp::HTTP.encode_url(dest.delete(param_name))
|
116
116
|
url << '/'
|
117
117
|
elsif !param_name
|
118
118
|
url << sec
|
@@ -125,7 +125,7 @@ module Plezi
|
|
125
125
|
end
|
126
126
|
unless dest.empty?
|
127
127
|
add = '?'
|
128
|
-
dest.each {|k, v| url << "#{add}#{GRHttp::HTTP.
|
128
|
+
dest.each {|k, v| url << "#{add}#{GRHttp::HTTP.encode_url k}=#{GRHttp::HTTP.encode_url v}"; add = '&'}
|
129
129
|
end
|
130
130
|
url
|
131
131
|
|
@@ -4,6 +4,7 @@ module Plezi
|
|
4
4
|
module_function
|
5
5
|
# returns a session object
|
6
6
|
def fetch id
|
7
|
+
return Plezi::Session.new(id) if Plezi.redis # avoid a local cache if Redis is used.
|
7
8
|
@session_cache[id] || (@session_cache[id] = Plezi::Session.new(id))
|
8
9
|
end
|
9
10
|
@session_cache = {}
|
@@ -20,7 +21,7 @@ module Plezi
|
|
20
21
|
# called by the Plezi framework to initiate a session with the id requested
|
21
22
|
def initialize id
|
22
23
|
@id = id
|
23
|
-
if (conn=Plezi.redis)
|
24
|
+
if id && (conn=Plezi.redis)
|
24
25
|
@data=conn.hgetall(id)
|
25
26
|
end
|
26
27
|
@data ||= {}
|
@@ -193,6 +193,8 @@ module Plezi
|
|
193
193
|
|
194
194
|
def __inner_redis_broadcast data
|
195
195
|
return unless conn = Plezi.redis
|
196
|
+
data = data.dup
|
197
|
+
data[:type] = data[:type].name if data[:type]
|
196
198
|
data[:server] = Plezi::Settings.uuid
|
197
199
|
return conn.publish( ( data[:to_server] ? data[:to_server] : Plezi::Settings.redis_channel_name ), data.to_yaml ) if conn
|
198
200
|
false
|
@@ -74,7 +74,7 @@ module Plezi
|
|
74
74
|
#
|
75
75
|
# defaults to the example above, which isn't a very sercure behavior, but allows for easy testing.
|
76
76
|
def self.auth_callback &block
|
77
|
-
block_given? ? (@@auth_callback = block) : ( @@auth_callback ||= (Proc.new {|service, service_token, id, email, res| Plezi.info "deafult callback called for #{service}, with response: #{res.to_s}";
|
77
|
+
block_given? ? (@@auth_callback = block) : ( @@auth_callback ||= (Proc.new {|service, service_token, id, email, res| Plezi.info "deafult callback called for #{service}, with response: #{res.to_s}"; session["#{service}_pl_auth_token"], session["#{service}_user_id"], session["#{service}_user_email"] = service_token, id, email}) )
|
78
78
|
end
|
79
79
|
|
80
80
|
|
data/lib/plezi/version.rb
CHANGED
data/plezi.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "grhttp", "~> 0.0.
|
21
|
+
spec.add_dependency "grhttp", "~> 0.0.23"
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.7"
|
23
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
24
|
|
data/resources/mini_app.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
require 'pathname'
|
6
6
|
## Set up root object, it might be used by the environment and\or the plezi extension gems.
|
7
7
|
Root ||= Pathname.new(File.dirname(__FILE__)).expand_path
|
8
|
-
## Set a
|
8
|
+
## Set a persistent session token id name
|
9
9
|
GRHttp.session_token = 'appname_uui'
|
10
10
|
## make sure all file access and file loading is relative to the application's root folder
|
11
11
|
# Dir.chdir Root.to_s
|
@@ -2,7 +2,8 @@
|
|
2
2
|
<head>
|
3
3
|
<title>appname - Feed Me!</title>
|
4
4
|
<meta content="width=device-width, initial-scale=1, maximum-scale=2.0, user-scalable=yes, minimal-ui=yes" name="viewport">
|
5
|
-
<link href='
|
5
|
+
<link href='https://fonts.googleapis.com/css?family=Shadows+Into+Light|Architects+Daughter' rel='stylesheet' type='text/css'>
|
6
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
6
7
|
<style type="text/css">
|
7
8
|
/*
|
8
9
|
med-blue: #44518E
|
@@ -185,6 +186,7 @@ var websocket_fail_count = 0
|
|
185
186
|
|
186
187
|
function init_websocket()
|
187
188
|
{
|
189
|
+
if(websocket && websocket.readyState == 1) return true; // console.log('no need to renew socket connection');
|
188
190
|
websocket = new WebSocket(ws_uri);
|
189
191
|
websocket.onopen = function(e) {
|
190
192
|
//restart fail count
|
data/resources/websockets.js
CHANGED
@@ -14,6 +14,7 @@ var websocket_fail_limit = NaN
|
|
14
14
|
|
15
15
|
function init_websocket()
|
16
16
|
{
|
17
|
+
if(websocket && websocket.readyState == 1) return true; // console.log('no need to renew socket connection');
|
17
18
|
websocket = new WebSocket(ws_uri);
|
18
19
|
websocket.onopen = function(e) {
|
19
20
|
// reset the count.
|
data/resources/welcome_page.html
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
<head>
|
3
3
|
<title>appname - Feed Me!</title>
|
4
4
|
<meta content="width=device-width, initial-scale=1, maximum-scale=2.0, user-scalable=yes, minimal-ui=yes" name="viewport">
|
5
|
-
<link href='
|
5
|
+
<link href='https://fonts.googleapis.com/css?family=Shadows+Into+Light|Architects+Daughter' rel='stylesheet' type='text/css'>
|
6
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
6
7
|
<style type="text/css">
|
7
8
|
/*
|
8
9
|
med-blue: #44518E
|
@@ -185,6 +186,7 @@ var websocket_fail_count = 0
|
|
185
186
|
|
186
187
|
function init_websocket()
|
187
188
|
{
|
189
|
+
if(websocket && websocket.readyState == 1) return true; // console.log('no need to renew socket connection');
|
188
190
|
websocket = new WebSocket(ws_uri);
|
189
191
|
websocket.onopen = function(e) {
|
190
192
|
//restart fail count
|
data/test/console
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# encoding: UTF-8
|
3
3
|
|
4
|
-
Dir.chdir '/Users/2Be/Ruby/plezi/plezi/'
|
5
|
-
|
6
4
|
require 'benchmark'
|
7
|
-
|
5
|
+
$LOAD_PATH.unshift File.expand_path(File.join('..', '..', 'lib'), __FILE__ )
|
8
6
|
require "plezi"
|
7
|
+
require "bundler/setup"
|
9
8
|
|
10
9
|
# You can add fixtures and/or initialization code here to make experimenting
|
11
10
|
# with your gem easier. You can also use a different console, if you like.
|
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.10.
|
4
|
+
version: 0.10.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: grhttp
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0.
|
19
|
+
version: 0.0.23
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.0.
|
26
|
+
version: 0.0.23
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|