plezi 0.8.7 → 0.9.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 +23 -0
- data/bin/plezi +11 -9
- data/lib/plezi/common/dsl.rb +1 -1
- data/lib/plezi/eventmachine/connection.rb +7 -3
- data/lib/plezi/eventmachine/io.rb +1 -1
- data/lib/plezi/handlers/http_host.rb +11 -12
- data/lib/plezi/server/http_protocol.rb +5 -5
- data/lib/plezi/server/websocket.rb +43 -0
- data/lib/plezi/server/websocket_client.rb +7 -2
- data/lib/plezi/server/ws_response.rb +41 -6
- data/lib/plezi/version.rb +1 -1
- data/plezi.gemspec +4 -4
- data/resources/db_sequel_config.rb +6 -15
- data/resources/websockets.js +18 -17
- data/resources/welcome_page.html +84 -27
- data/test/plezi_tests.rb +33 -1
- metadata +8 -15
- data/resources/plezi_gray.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1b45fb775eeba5ab996d2581da537e38640f7d4
|
4
|
+
data.tar.gz: 1060b31518ce6e3ee36cfa315ce916f72e7ab1d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 030e93b8a30cc04c3ad35c3aae1303e335b5bd1558469e9673cc14e07417c17b43e0a271a4441bee64b53c6785804b2a9460cd391d3402c2cc12e0093fe0a626
|
7
|
+
data.tar.gz: d663be79b8da32121b279848fc2cad6b5b66562ccbeedac9de25a41965bfa40380085a1b43af806f4f5e763a5e86eee7314e1f88fda8d5c43a2ba23d01c7fbc3
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,29 @@
|
|
2
2
|
|
3
3
|
***
|
4
4
|
|
5
|
+
Change log v.0.9.0
|
6
|
+
|
7
|
+
**changes** (might break code):
|
8
|
+
|
9
|
+
- The error code file handling logic has been changed.
|
10
|
+
|
11
|
+
Plezi will no longer look the 404 and 505 files in the _public_ `:root` location. Instead the files should be placed at the **templates** folder if defined or at the app's root folder (_if templates folder isn't set_).
|
12
|
+
|
13
|
+
Also, error code files should now correctly specify that they are html templates - for example, the older '404.erb' should be renamed as '404.html.erb'
|
14
|
+
|
15
|
+
To update your application **please rename the error code files and move them to the app template's folder** (`appname/app/views`).
|
16
|
+
|
17
|
+
- Updated the template's welcome page and database configuration support. Existing applications shouldn't be effected.
|
18
|
+
|
19
|
+
|
20
|
+
**feature**: auto-pinging can now be customized for different hosting-server timeouts and it can also be disabled using the `Plezi.ping_interval` setter and getter.
|
21
|
+
|
22
|
+
**feature**: The Plezi framework can now impose limits on Websocket message sizes (even messages split across a number of frames) by using the `Plezi.ws_message_size_limit=` method.
|
23
|
+
|
24
|
+
**fix**: Outgoing Websocket messages would break for messages over 32KB (and sometimes over 16KB). This was caused by an issue in the frame splitting algorithm which is now resolved.
|
25
|
+
|
26
|
+
***
|
27
|
+
|
5
28
|
Change log v.0.8.7
|
6
29
|
|
7
30
|
**minor performance**: streamlined the ping/pong Websocket process.
|
data/bin/plezi
CHANGED
@@ -46,10 +46,21 @@ class AppTemplate
|
|
46
46
|
app_tree["app"]["models"] ||= {}
|
47
47
|
app_tree["app"]["views"] ||= {}
|
48
48
|
|
49
|
+
# set up templates for status error codes
|
50
|
+
app_tree["app"]["views"]["404.html"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.html"), __FILE__))
|
51
|
+
app_tree["app"]["views"]["500.html"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.html"), __FILE__))
|
52
|
+
app_tree["app"]["views"]["404.html.erb"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.erb"), __FILE__))
|
53
|
+
app_tree["app"]["views"]["500.html.erb"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.erb"), __FILE__))
|
54
|
+
app_tree["app"]["views"]["404.html.slim"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.slim"), __FILE__))
|
55
|
+
app_tree["app"]["views"]["500.html.slim"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.slim"), __FILE__))
|
56
|
+
app_tree["app"]["views"]["404.html.haml"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.haml"), __FILE__))
|
57
|
+
app_tree["app"]["views"]["500.html.haml"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.haml"), __FILE__))
|
58
|
+
|
49
59
|
# set up the assets folder
|
50
60
|
app_tree["assets"] ||= {}
|
51
61
|
app_tree["assets"]["stylesheets"] ||= {}
|
52
62
|
app_tree["assets"]["javascripts"] ||= {}
|
63
|
+
app_tree["assets"]["javascripts"]["websocket.js"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"websockets.js"), __FILE__)).gsub('appname', ARGV[1])
|
53
64
|
app_tree["assets"]["welcome.html"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"welcome_page.html"), __FILE__)).gsub('appname', ARGV[1])
|
54
65
|
|
55
66
|
# app core files.
|
@@ -92,19 +103,10 @@ class AppTemplate
|
|
92
103
|
|
93
104
|
# set up a public folder for static file service
|
94
105
|
app_tree["public"] ||= {}
|
95
|
-
app_tree["public"]["404.slim"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.slim"), __FILE__))
|
96
|
-
app_tree["public"]["500.slim"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.slim"), __FILE__))
|
97
|
-
app_tree["public"]["404.html"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.html"), __FILE__))
|
98
|
-
app_tree["public"]["500.html"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.html"), __FILE__))
|
99
|
-
app_tree["public"]["404.erb"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.erb"), __FILE__))
|
100
|
-
app_tree["public"]["500.erb"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.erb"), __FILE__))
|
101
|
-
app_tree["public"]["404.haml"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.haml"), __FILE__))
|
102
|
-
app_tree["public"]["500.haml"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.haml"), __FILE__))
|
103
106
|
app_tree["public"]["assets"] ||= {}
|
104
107
|
app_tree["public"]["assets"]["stylesheets"] ||= {}
|
105
108
|
app_tree["public"]["assets"]["javascripts"] ||= {}
|
106
109
|
app_tree["public"]["images"] ||= {}
|
107
|
-
app_tree["public"]["images"]['plezi_gray.png'] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"plezi_gray.png"), __FILE__))
|
108
110
|
|
109
111
|
end
|
110
112
|
|
data/lib/plezi/common/dsl.rb
CHANGED
@@ -113,7 +113,7 @@ Encoding.default_external = 'utf-8'
|
|
113
113
|
# PL is a shortcut for the Plezi module, so that `PL == Plezi`.
|
114
114
|
PL = Plezi
|
115
115
|
|
116
|
-
# shortcut for Plezi.listen.
|
116
|
+
# shortcut for Plezi::DSL.listen.
|
117
117
|
#
|
118
118
|
def listen(params = {})
|
119
119
|
Plezi::DSL.listen params
|
@@ -74,6 +74,7 @@ module Plezi
|
|
74
74
|
rescue => e
|
75
75
|
EventMachine.queue( [@socket], REMOVE_CONNECTION_PROC)
|
76
76
|
end
|
77
|
+
true
|
77
78
|
end
|
78
79
|
|
79
80
|
# the non-blocking proc used for send_nonblock
|
@@ -106,10 +107,13 @@ module Plezi
|
|
106
107
|
@protocol = false
|
107
108
|
end
|
108
109
|
end
|
109
|
-
|
110
|
+
|
111
|
+
# the non-blocking proc used for send_nonblock
|
112
|
+
FLUSH_AND_CLOSE_PROC = Proc.new {|c| c.flush; EventMachine.remove_io c.socket}
|
113
|
+
|
114
|
+
# Closes the connection. This is always asynchronous and will return immidiately.
|
110
115
|
def close
|
111
|
-
|
112
|
-
EventMachine.queue [@socket], REMOVE_CONNECTION_PROC
|
116
|
+
EventMachine.queue [self], FLUSH_AND_CLOSE_PROC
|
113
117
|
end
|
114
118
|
alias :disconnect :close
|
115
119
|
|
@@ -213,7 +213,7 @@ module Plezi
|
|
213
213
|
Plezi.run_every(3_600) {GC.start; Plezi.info "Refreshing worker threads."; EventMachine.stop; EventMachine.start Plezi.max_threads}
|
214
214
|
# run_every( 1 , Proc.new() { Plezi.info "#{IO_CONNECTION_DIC.length} active connections ( #{ IO_CONNECTION_DIC.select{|k,v| v.protocol.is_a?(WSProtocol)} .length } websockets)." })
|
215
215
|
# run_every 10 , -> {Plezi.info "Cache report: #{CACHE_STORE.length} objects cached." }
|
216
|
-
puts "** Deprecation Warning:\n- The current code for default error pages will be changed in version 0.9.0.\n- Default error pages will follow a different naming and location conventions.\n- The updated design will be part of the updated `plezi` helper script.\nPlease review your code before upgrading to the 0.9.0 version.\n"
|
216
|
+
# puts "** Deprecation Warning:\n- The current code for default error pages will be changed in version 0.9.0.\n- Default error pages will follow a different naming and location conventions.\n- The updated design will be part of the updated `plezi` helper script.\nPlease review your code before upgrading to the 0.9.0 version.\n"
|
217
217
|
puts "Services running Plezi version #{Plezi::VERSION}. Press ^C to stop"
|
218
218
|
EventMachine.start Plezi.max_threads
|
219
219
|
|
@@ -95,18 +95,17 @@ module Plezi
|
|
95
95
|
# sends a response for an error code, rendering the relevent file (if exists).
|
96
96
|
def send_by_code request, code, headers = {}
|
97
97
|
begin
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
98
|
+
@base_code_path ||= params[:templates] || File.expand_path('.')
|
99
|
+
if defined?(::Slim) && Plezi.file_exists?(fn = File.join(@base_code_path, "#{code}.html.slim"))
|
100
|
+
Plezi.cache_data fn, Slim::Template.new( fn ) unless Plezi.cached? fn
|
101
|
+
return send_raw_data request, Plezi.get_cached( fn ).render( self, request: request ), 'text/html', code, headers
|
102
|
+
elsif defined?(::Haml) && Plezi.file_exists?(fn = File.join(@base_code_path, "#{code}.html.haml"))
|
103
|
+
Plezi.cache_data fn, Haml::Engine.new( IO.read( fn ) ) unless Plezi.cached? fn
|
104
|
+
return send_raw_data request, Plezi.get_cached( File.join(@base_code_path, "#{code}.html.haml") ).render( self ), 'text/html', code, headers
|
105
|
+
elsif defined?(::ERB) && Plezi.file_exists?(fn = File.join(@base_code_path, "#{code}.html.erb"))
|
106
|
+
return send_raw_data request, ERB.new( Plezi.load_file( fn ) ).result(binding), 'text/html', code, headers
|
107
|
+
elsif Plezi.file_exists?(fn = File.join(@base_code_path, "#{code}.html"))
|
108
|
+
return send_file(request, fn, code, headers)
|
110
109
|
end
|
111
110
|
return true if send_raw_data(request, HTTPResponse::STATUS_CODES[code], 'text/plain', code, headers)
|
112
111
|
rescue Exception => e
|
@@ -31,11 +31,11 @@ module Plezi
|
|
31
31
|
def on_message
|
32
32
|
# parse the request
|
33
33
|
parse_message
|
34
|
-
if (@parser_stage == 1) && @parser_data[:version] >= 1.1
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
34
|
+
# if (@parser_stage == 1) && @parser_data[:version] >= 1.1
|
35
|
+
# # send 100 continue message????? doesn't work! both Crome and Safari go crazy if this is sent after the request was sent (but before all the packets were recieved... msgs over 1 Mb).
|
36
|
+
# # Plezi.push_event Proc.new { Plezi.info "sending continue signal."; connection.send_nonblock "100 Continue\r\n\r\n" }
|
37
|
+
# # connection.send_unsafe_interrupt "100 Continue\r\n\r\n" # causes double lock on connection
|
38
|
+
# end
|
39
39
|
true
|
40
40
|
end
|
41
41
|
|
@@ -124,6 +124,7 @@ module Plezi
|
|
124
124
|
end
|
125
125
|
@parser_data[:step] = 0
|
126
126
|
@parser_stage += 1
|
127
|
+
review_message_size
|
127
128
|
end
|
128
129
|
if @parser_stage == 2 && @parser_data[:mask] == 1
|
129
130
|
@parser_data[:mask_key] = data.slice!(0,4)
|
@@ -187,6 +188,48 @@ module Plezi
|
|
187
188
|
@parser_data[:body].clear
|
188
189
|
@parser_data[:step] = 0
|
189
190
|
end
|
191
|
+
#reviews the message size and closes the connection if expected message size is over the allowed limit.
|
192
|
+
def review_message_size
|
193
|
+
if ( self.class.message_size_limit.to_i > 0 ) && ( ( @parser_data[:len] + @message.bytesize ) > self.class.message_size_limit.to_i )
|
194
|
+
Plezi.callback @connection, :disconnect
|
195
|
+
@message.clear
|
196
|
+
@parser_data[:step] = 0
|
197
|
+
@parser_data[:body].clear
|
198
|
+
@parser_stage = -1
|
199
|
+
return false
|
200
|
+
end
|
201
|
+
true
|
202
|
+
end
|
203
|
+
|
204
|
+
# Sets the message byte size limit for a Websocket message. Defaults to 0 (no limit)
|
205
|
+
#
|
206
|
+
# Although memory will be allocated for the latest TCP/IP frame,
|
207
|
+
# this allows the websocket to disconnect if the incoming expected message size exceeds the allowed maximum size.
|
208
|
+
#
|
209
|
+
# 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.
|
210
|
+
def self.message_size_limit=val
|
211
|
+
@message_size_limit = val
|
212
|
+
end
|
213
|
+
# Gets the message byte size limit for a Websocket message. Defaults to 0 (no limit)
|
214
|
+
def self.message_size_limit
|
215
|
+
@message_size_limit
|
216
|
+
end
|
217
|
+
message_size_limit = 0
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
# Sets the message byte size limit for a Websocket message. Defaults to 0 (no limit)
|
222
|
+
#
|
223
|
+
# Although memory will be allocated for the latest TCP/IP frame,
|
224
|
+
# this allows the websocket to disconnect if the incoming expected message size exceeds the allowed maximum size.
|
225
|
+
#
|
226
|
+
# 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.
|
227
|
+
def self.ws_message_size_limit=val
|
228
|
+
WSProtocol.message_size_limit = val
|
229
|
+
end
|
230
|
+
# Gets the message byte size limit for a Websocket message. Defaults to 0 (no limit)
|
231
|
+
def self.ws_message_size_limit
|
232
|
+
WSProtocol.message_size_limit
|
190
233
|
end
|
191
234
|
end
|
192
235
|
|
@@ -52,9 +52,14 @@ module Plezi
|
|
52
52
|
end
|
53
53
|
alias :close :disconnect
|
54
54
|
|
55
|
-
# sends data through the socket. a shortcut for ws_client.response <<
|
55
|
+
# Asynchronously sends data through the socket. a shortcut for ws_client.response <<
|
56
56
|
def << data
|
57
|
-
@response << data
|
57
|
+
@response << data
|
58
|
+
end
|
59
|
+
|
60
|
+
# Synchronously sends data through the socket. a shortcut for ws_client.response <<
|
61
|
+
def send data
|
62
|
+
@response.send data
|
58
63
|
end
|
59
64
|
|
60
65
|
# Create a simple Websocket Client(!)
|
@@ -17,7 +17,22 @@ module Plezi
|
|
17
17
|
#the request.
|
18
18
|
attr_accessor :request
|
19
19
|
|
20
|
-
|
20
|
+
# Sets the defalt Websockt auto-ping interval.
|
21
|
+
#
|
22
|
+
# The default ping interval is 45 seconds.
|
23
|
+
#
|
24
|
+
# It's possible to set the ping interval to false, thereby disabling auto-pinging.
|
25
|
+
def self.ping_interval=(val)
|
26
|
+
@ping_interval = val
|
27
|
+
end
|
28
|
+
# Returns the defalt Websockt auto-ping interval.
|
29
|
+
#
|
30
|
+
# Plezi will automatically send a ping frame to keep websocket connections open.
|
31
|
+
# This auto-pinging can be disabled by setting the `ping_interval` to false.
|
32
|
+
def self.ping_interval
|
33
|
+
@ping_interval ||= 45
|
34
|
+
end
|
35
|
+
PING_PROC = Proc.new {|res| EventMachine.timed_job ping_interval, 1, [res.ping], PING_PROC unless res.service.disconnected? || !ping_interval }
|
21
36
|
|
22
37
|
def initialize request
|
23
38
|
@request, @service = request,request.service
|
@@ -81,20 +96,20 @@ module Plezi
|
|
81
96
|
service.locker.locked? ? (EventMachine.queue [service], CLOSE_PROC) : (CLOSE_PROC.call(service))
|
82
97
|
end
|
83
98
|
|
84
|
-
FRAME_SIZE_LIMIT = 131_072
|
99
|
+
FRAME_SIZE_LIMIT = 131_072 # javascript to test: str = '0123456789'; bigstr = ""; for(i = 0; i<=1033200; i+=1) {bigstr += str}; ws = new WebSocket('ws://localhost:3000/ws/size') ; ws.onmessage = function(e) {console.log(e.data.length)};ws. onopen = function(e) {ws.send(bigstr)}
|
85
100
|
|
86
|
-
# Dangerzone!
|
101
|
+
# Dangerzone! use `send` instead: formats the data as one or more WebSocket frames.
|
87
102
|
def self.frame_data data, op_code = nil, fin = true
|
88
103
|
# set up variables
|
89
104
|
frame = ''.force_encoding('binary')
|
90
105
|
op_code ||= (data.encoding.name == 'UTF-8' ? 1 : 2)
|
91
106
|
|
92
107
|
|
93
|
-
if data[FRAME_SIZE_LIMIT]
|
108
|
+
if data[FRAME_SIZE_LIMIT] && fin
|
94
109
|
# fragment big data chuncks into smaller frames - op-code reset for 0 for all future frames.
|
95
110
|
data = data.dup
|
96
111
|
data.force_encoding('binary')
|
97
|
-
[frame << frame_data(data.slice!(0
|
112
|
+
[frame << frame_data(data.slice!(0...FRAME_SIZE_LIMIT), op_code, false), op_code = 0] while data.length > FRAME_SIZE_LIMIT # 1048576
|
98
113
|
# frame << frame_data(data.slice!(0..1048576), op_code, false)
|
99
114
|
# data =
|
100
115
|
# op_code = 0
|
@@ -110,7 +125,7 @@ module Plezi
|
|
110
125
|
|
111
126
|
if data.length < 125
|
112
127
|
frame << data.length.chr
|
113
|
-
elsif data.length.bit_length
|
128
|
+
elsif data.length.bit_length <= 16
|
114
129
|
frame << 126.chr
|
115
130
|
frame << [data.length].pack('S>')
|
116
131
|
else
|
@@ -123,4 +138,24 @@ module Plezi
|
|
123
138
|
frame
|
124
139
|
end
|
125
140
|
end
|
141
|
+
|
142
|
+
module_function
|
143
|
+
# Sets the defalt Websockt auto-ping interval.
|
144
|
+
#
|
145
|
+
# This method accepts one value, which should be either a number in seconds or `false`.
|
146
|
+
#
|
147
|
+
# The default ping interval is 45 seconds.
|
148
|
+
#
|
149
|
+
# It's possible to set the ping interval to false, thereby disabling auto-pinging.
|
150
|
+
def ping_interval=(val)
|
151
|
+
WSResponse.ping_interval = val
|
152
|
+
end
|
153
|
+
# Returns the defalt Websockt auto-ping interval.
|
154
|
+
#
|
155
|
+
# Plezi will automatically send a ping frame to keep websocket connections open.
|
156
|
+
# This auto-pinging can be disabled by setting the `ping_interval` to false.
|
157
|
+
def ping_interval
|
158
|
+
WSResponse.ping_interval
|
159
|
+
end
|
160
|
+
|
126
161
|
end
|
data/lib/plezi/version.rb
CHANGED
data/plezi.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Plezi::VERSION
|
9
9
|
spec.authors = ["Boaz Segev"]
|
10
10
|
spec.email = ['boaz@2be.co.il']
|
11
|
-
spec.summary = %q{Plezi is the native Ruby Framework for real time web-apps
|
12
|
-
spec.description = %q{Plezi is the native Ruby Framework for real time web-apps
|
11
|
+
spec.summary = %q{Plezi is the native Ruby Framework for real time web-apps. An easy way to write Websockets, RESTful routing and HTTP streaming apps.}
|
12
|
+
spec.description = %q{Plezi is the native Ruby Framework for real time web-apps. An easy way to write Websockets, RESTful routing and HTTP streaming apps.}
|
13
13
|
spec.homepage = "http://boazsegev.github.io/plezi/"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.7"
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
23
|
|
24
|
-
spec.post_install_message = "
|
25
|
-
spec.post_install_message
|
24
|
+
spec.post_install_message = "Thank you for installing Plezi, the native Ruby Framework for real time web-apps."
|
25
|
+
# spec.post_install_message = "** Deprecation Warning:\n- The current code for default error pages will be changed in version 0.9.0.\n- Default error pages will follow a different naming and location conventions.\n- The updated design will be part of the updated `plezi` helper script.\nPlease review your code before upgrading to the 0.9.0 version.\n\nThank you for installing Plezi, the native Ruby Framework for real time web-apps."
|
26
26
|
|
27
27
|
end
|
@@ -11,21 +11,12 @@
|
|
11
11
|
# http://sequel.jeremyevans.net
|
12
12
|
if defined? Sequel
|
13
13
|
|
14
|
-
if defined?
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
DB = Sequel.
|
20
|
-
|
21
|
-
elsif defined? PG
|
22
|
-
if ENV['DYNO']
|
23
|
-
# A Postgres connection for Heroku:
|
24
|
-
DB = Sequel.connect(ENV['HEROKU_POSTGRESQL_RED_URL'])
|
25
|
-
else
|
26
|
-
# app name is the same as the root app folder: Root.to_s.split(/\/\\/).last
|
27
|
-
DB = Sequel.connect("postgres://localhost/#{Root.to_s.split(/[\/\\]/).last}")
|
28
|
-
end
|
14
|
+
if defined? PG && ENV['DYNO']
|
15
|
+
# A default Postgres connection for Heroku:
|
16
|
+
DB = Sequel.connect(ENV['HEROKU_POSTGRESQL_RED_URL'])
|
17
|
+
else
|
18
|
+
# use db/config.yaml to connect to database
|
19
|
+
DB = Sequel.connect( YAML::load( File.open( Root.join('db', 'config.yml').to_s ) )[ ENV["ENV"].to_s ] )
|
29
20
|
end
|
30
21
|
if defined? Rake
|
31
22
|
##########
|
data/resources/websockets.js
CHANGED
@@ -1,28 +1,29 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
// Your websocket URI should be an absolute path. The following sets the base URI.
|
2
|
+
var ws_uri = 'ws://' + window.location.hostname + (window.location.port == '' ? '' : (':' + window.location.port) );
|
3
|
+
// remember to add the specific controller's path to your websocket URI.
|
4
|
+
ws_uri += "/";
|
5
|
+
// websocket variable.
|
4
6
|
var websocket = NaN
|
5
7
|
|
6
8
|
function init_websocket()
|
7
9
|
{
|
8
10
|
websocket = new WebSocket(ws_uri);
|
9
|
-
websocket.onopen = function(e) {
|
10
|
-
websocket.onclose = function(e) { on_close(e) };
|
11
|
-
websocket.onmessage = function(e) { on_message(e) };
|
12
|
-
websocket.onerror = function(e) { on_error(e) }; }
|
13
|
-
|
14
|
-
function on_open(e) {
|
11
|
+
websocket.onopen = function(e) {
|
15
12
|
// what do you want to do now?
|
16
|
-
}
|
17
|
-
|
13
|
+
};
|
14
|
+
|
15
|
+
websocket.onclose = function(e) {
|
18
16
|
// you probably want to reopen the websocket if it closes.
|
19
17
|
init_websocket()
|
20
|
-
}
|
21
|
-
function
|
18
|
+
};
|
19
|
+
websocket.onerror = function(e) {
|
22
20
|
// what do you want to do now?
|
23
|
-
}
|
24
|
-
function
|
21
|
+
};
|
22
|
+
websocket.onmessage = function(e) {
|
25
23
|
// what do you want to do now?
|
26
|
-
|
24
|
+
console.log(e.data);
|
25
|
+
// to use JSON, use:
|
26
|
+
// msg = JSON.parse(e.data); // remember to use JSON also in your Plezi controller.
|
27
|
+
};
|
27
28
|
}
|
28
|
-
window.addEventListener("load",
|
29
|
+
window.addEventListener("load", init_websocket, false);
|
data/resources/welcome_page.html
CHANGED
@@ -1,30 +1,64 @@
|
|
1
|
-
<!DOCTYPE html><head><title>appname - Feed Me!</title
|
1
|
+
<!DOCTYPE html><head><title>appname - Feed Me!</title>
|
2
|
+
<link href='http://fonts.googleapis.com/css?family=Shadows+Into+Light|Architects+Daughter' rel='stylesheet' type='text/css'>
|
3
|
+
|
4
|
+
<link href="https://fonts.googleapis.com/css?family=Architects+Daughter" rel="stylesheet" type="text/css">
|
5
|
+
<style type="text/css">
|
6
|
+
/*
|
7
|
+
med-blue: #44518E
|
8
|
+
dark-gray: #424A70
|
9
|
+
blue: #1B2864
|
10
|
+
light-blue: #818ECE
|
11
|
+
light-gray: #99A3CE
|
12
|
+
*/
|
13
|
+
body, html
|
2
14
|
{
|
3
|
-
background-color: #
|
15
|
+
background-color: #99A3CE;
|
4
16
|
padding: 0; margin: 0;
|
5
17
|
width: 100%;
|
6
18
|
font-size: 1em;
|
7
19
|
}
|
8
|
-
body, html, h1, #wrapper, #wrapper h2
|
9
|
-
{
|
10
|
-
background-image: url(/images/plezi_gray.png);
|
11
|
-
background-position: center top;
|
12
|
-
background-origin: inherit;
|
13
|
-
background-repeat: no-repeat;
|
14
|
-
background-size: 88% auto;
|
15
|
-
background-attachment: fixed;
|
16
|
-
|
17
|
-
}
|
18
20
|
|
19
21
|
h1
|
20
22
|
{
|
21
|
-
|
22
|
-
color: #
|
23
|
+
font-family: 'Indie Flower', cursive;
|
24
|
+
background-color: #1B2864;
|
25
|
+
color: #99A3CE;
|
23
26
|
text-align: center;
|
24
|
-
border-bottom: 1px solid #
|
27
|
+
border-bottom: 1px solid #424A70;
|
25
28
|
margin: 0 0 1em 0;
|
26
29
|
padding: 0.5em 0;
|
27
30
|
width: 100%;
|
31
|
+
|
32
|
+
}
|
33
|
+
h2, h3
|
34
|
+
{
|
35
|
+
background-color: #44518E;
|
36
|
+
color: #99A3CE;
|
37
|
+
text-align: left;
|
38
|
+
margin: 0 0 1em 0;
|
39
|
+
padding: 0.5em 5%;
|
40
|
+
border-radius: 20px;
|
41
|
+
font-family: 'Shadows Into Light', cursive;
|
42
|
+
}
|
43
|
+
h2:before {
|
44
|
+
content: "|||";
|
45
|
+
color: #424A70;
|
46
|
+
padding-right: 0.3em;
|
47
|
+
margin-left: -1.5em;
|
48
|
+
}
|
49
|
+
h3:before {
|
50
|
+
content: "|||||";
|
51
|
+
color: #424A70;
|
52
|
+
padding-right: 0.3em;
|
53
|
+
margin-left: -2em;
|
54
|
+
}
|
55
|
+
h1 a, h2 a, h3 a
|
56
|
+
{
|
57
|
+
color: #EBCD86;
|
58
|
+
}
|
59
|
+
h1 a:hover, h2 a:hover, h3 a:hover
|
60
|
+
{
|
61
|
+
color: #EBD7A6;
|
28
62
|
}
|
29
63
|
p
|
30
64
|
{
|
@@ -34,12 +68,12 @@ p
|
|
34
68
|
}
|
35
69
|
a
|
36
70
|
{
|
37
|
-
color: #
|
71
|
+
color: #D0AC54;
|
38
72
|
text-decoration: none;
|
39
73
|
}
|
40
74
|
a:hover
|
41
75
|
{
|
42
|
-
color: #
|
76
|
+
color: #927121;
|
43
77
|
text-decoration: underline;
|
44
78
|
}
|
45
79
|
#wrapper
|
@@ -51,15 +85,7 @@ a:hover
|
|
51
85
|
min-height: 50%;
|
52
86
|
color: #007;
|
53
87
|
}
|
54
|
-
|
55
|
-
{
|
56
|
-
background-color: #ddd;
|
57
|
-
color: #008;
|
58
|
-
text-align: left;
|
59
|
-
margin: 0 0 1em 0;
|
60
|
-
padding: 0.5em 5%;
|
61
|
-
border-radius: 20px;
|
62
|
-
}
|
88
|
+
|
63
89
|
#wrapper p{ padding: 0 2%;}
|
64
90
|
.bold { font-weight: bold; }
|
65
91
|
#wrapper ol li{ padding: 0 2%;}
|
@@ -69,4 +95,35 @@ pre
|
|
69
95
|
padding: 0.5em 0;
|
70
96
|
background-color: #444;
|
71
97
|
color: #ddd;
|
72
|
-
}
|
98
|
+
}
|
99
|
+
|
100
|
+
</style>
|
101
|
+
</head>
|
102
|
+
<body>
|
103
|
+
<h1>Welcome to <a href="https://github.com/boazsegev/plezi">Plezi</a></h1>
|
104
|
+
<div id="wrapper">
|
105
|
+
<h2>Congratulations, <a href='/'>appname</a> is running - What's next?</h2>
|
106
|
+
<p><span class="bold">Congratulations</span>, you're now running appname and it has so much potential!</p>
|
107
|
+
<p>appname started out <a href="https://github.com/boazsegev/plezi">Plezi</a> and it's your quest to feed it your code and make sure appname grows strong and happy.</p>
|
108
|
+
<p>You're the master of this quest, and your next steps might include:</p>
|
109
|
+
<ol><li><p class="bold">Deciding which gems to use:</p>
|
110
|
+
<ul>
|
111
|
+
<li>edit Gemfile in the appname folder.</li>
|
112
|
+
</ul>
|
113
|
+
</li>
|
114
|
+
<li>
|
115
|
+
<p class="bold">Reviewing the sample code and feeding <a href="https://github.com/boazsegev/plezi">Plezi</a> your code:</p>
|
116
|
+
<ul>
|
117
|
+
<li>Review the 'sample_controller.rb' file in the appname/app/controllers folder.</li>
|
118
|
+
<li>Delete the 'sample_controller.rb' file and this file (appname/assets/welcome.html).</li>
|
119
|
+
<li>Write your own controller and code.</li>
|
120
|
+
<li>Edit the 'routes.rb' file to set up your routes.</li>
|
121
|
+
</ul>
|
122
|
+
</li>
|
123
|
+
<li>
|
124
|
+
<p><span class="bold">Having fun</span> and submitting any issues you discover to the <a href="https://github.com/boazsegev/plezi">Plezi Github Project.</a></p>
|
125
|
+
</li>
|
126
|
+
</ol>
|
127
|
+
<p class="bold">Good Luck!</p>
|
128
|
+
</div>
|
129
|
+
</body>
|
data/test/plezi_tests.rb
CHANGED
@@ -135,6 +135,15 @@ class TestCtrl
|
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
138
|
+
class WSsizeTestCtrl
|
139
|
+
# called when new Websocket data is recieved
|
140
|
+
#
|
141
|
+
# data is a string that contains binary or UTF8 (message dependent) data.
|
142
|
+
def on_message data
|
143
|
+
response << data
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
138
147
|
module PleziTestTasks
|
139
148
|
module_function
|
140
149
|
|
@@ -251,7 +260,7 @@ module PleziTestTasks
|
|
251
260
|
go_test = false
|
252
261
|
end
|
253
262
|
end
|
254
|
-
ws3 = Plezi::WebsocketClient.connect_to("
|
263
|
+
ws3 = Plezi::WebsocketClient.connect_to("ws://localhost:3000") do |msg|
|
255
264
|
if msg.match /uuid: ([^s]*)/
|
256
265
|
ws2 << "to: #{msg.match(/^uuid: ([^s]*)/)[1]}"
|
257
266
|
puts " * Websocket UUID for unicast testing: #{msg.match(/^uuid: ([^s]*)/)[1]}"
|
@@ -290,6 +299,27 @@ module PleziTestTasks
|
|
290
299
|
PL.on_shutdown {puts " * Websocket broadcast message test: #{RESULTS[broadcast_test]}" unless broadcast_test}
|
291
300
|
PL.on_shutdown {puts " * Websocket unicast message test: #{RESULTS[unicast_test]}"}
|
292
301
|
end
|
302
|
+
def test_websocket_sizes
|
303
|
+
should_disconnect = false
|
304
|
+
ws = Plezi::WebsocketClient.connect_to("ws://localhost:3000/ws/size") do |msg|
|
305
|
+
if should_disconnect
|
306
|
+
puts " * Websocket size disconnection test: #{RESULTS[false]}"
|
307
|
+
else
|
308
|
+
puts " * Websocket message size test: got #{msg.bytesize} bytes"
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
ws.on_disconnect do
|
313
|
+
puts " * Websocket size disconnection test: #{RESULTS[should_disconnect]}"
|
314
|
+
end
|
315
|
+
str = 'a'
|
316
|
+
time_now = Time.now
|
317
|
+
6.times {|i| str = str * 2**i;puts " * Websocket message size test: sending #{str.bytesize} bytes"; ws.send str; sleep 0.2 }
|
318
|
+
sleep (Time.now - time_now + 1)
|
319
|
+
should_disconnect = true
|
320
|
+
Plezi.ws_message_size_limit = 1024
|
321
|
+
ws << str
|
322
|
+
end
|
293
323
|
def test_404
|
294
324
|
puts " * 404 not found and router continuity tests: #{RESULTS[ Net::HTTP.get_response(URI.parse "http://localhost:3000/get404" ).code == '404' ]}"
|
295
325
|
|
@@ -323,6 +353,8 @@ route("/ssl") {|req, res| res << "false" }
|
|
323
353
|
listen port: 3030, ssl: true
|
324
354
|
route("/ssl") {|req, res| res << "true" }
|
325
355
|
|
356
|
+
shared_route 'ws/size', WSsizeTestCtrl
|
357
|
+
|
326
358
|
shared_route '/some/:multi{path|another_path}/(:option){route|test}/(:id)/(:optional)', TestCtrl
|
327
359
|
shared_route '/', TestCtrl
|
328
360
|
|
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.9.0
|
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-06
|
11
|
+
date: 2015-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,8 +38,8 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
-
description: Plezi is the native Ruby Framework for real time web-apps
|
42
|
-
RESTful routing and HTTP streaming
|
41
|
+
description: Plezi is the native Ruby Framework for real time web-apps. An easy way
|
42
|
+
to write Websockets, RESTful routing and HTTP streaming apps.
|
43
43
|
email:
|
44
44
|
- boaz@2be.co.il
|
45
45
|
executables:
|
@@ -106,7 +106,6 @@ files:
|
|
106
106
|
- resources/haml_config.rb
|
107
107
|
- resources/i18n_config.rb
|
108
108
|
- resources/oauth_config.rb
|
109
|
-
- resources/plezi_gray.png
|
110
109
|
- resources/plezi_websockets.html
|
111
110
|
- resources/rakefile
|
112
111
|
- resources/redis_config.rb
|
@@ -119,14 +118,8 @@ homepage: http://boazsegev.github.io/plezi/
|
|
119
118
|
licenses:
|
120
119
|
- MIT
|
121
120
|
metadata: {}
|
122
|
-
post_install_message:
|
123
|
-
|
124
|
-
- The current code for default error pages will be changed in version 0.9.0.
|
125
|
-
- Default error pages will follow a different naming and location conventions.
|
126
|
-
- The updated design will be part of the updated `plezi` helper script.
|
127
|
-
Please review your code before upgrading to the 0.9.0 version.
|
128
|
-
|
129
|
-
Thank you for installing Plezi, the native Ruby Framework for real time web-apps.
|
121
|
+
post_install_message: Thank you for installing Plezi, the native Ruby Framework for
|
122
|
+
real time web-apps.
|
130
123
|
rdoc_options: []
|
131
124
|
require_paths:
|
132
125
|
- lib
|
@@ -145,7 +138,7 @@ rubyforge_project:
|
|
145
138
|
rubygems_version: 2.4.7
|
146
139
|
signing_key:
|
147
140
|
specification_version: 4
|
148
|
-
summary: Plezi is the native Ruby Framework for real time web-apps
|
149
|
-
RESTful routing and HTTP streaming
|
141
|
+
summary: Plezi is the native Ruby Framework for real time web-apps. An easy way to
|
142
|
+
write Websockets, RESTful routing and HTTP streaming apps.
|
150
143
|
test_files:
|
151
144
|
- test/plezi_tests.rb
|
data/resources/plezi_gray.png
DELETED
Binary file
|