plezi 0.8.7 → 0.9.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 +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
|