plezi 0.12.22 → 0.14.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 +18 -0
- data/LICENSE.txt +17 -18
- data/README.md +54 -698
- data/Rakefile +7 -4
- data/bin/config.ru +22 -0
- data/{test → bin}/console +4 -6
- data/bin/hello_world +52 -0
- data/bin/setup +8 -0
- data/exe/plezi +145 -0
- data/lib/plezi.rb +24 -137
- data/lib/plezi/activation.rb +28 -0
- data/lib/plezi/api.rb +62 -0
- data/lib/plezi/controller/controller.rb +259 -0
- data/lib/plezi/controller/controller_class.rb +176 -0
- data/lib/plezi/controller/cookies.rb +40 -0
- data/lib/plezi/helpers.rb +60 -0
- data/lib/plezi/rake.rb +2 -24
- data/lib/plezi/render/erb.rb +34 -0
- data/lib/plezi/render/has_cache.rb +36 -0
- data/lib/plezi/render/markdown.rb +63 -0
- data/lib/plezi/render/render.rb +49 -0
- data/lib/plezi/render/sass.rb +55 -0
- data/lib/plezi/render/slim.rb +33 -0
- data/lib/plezi/router/adclient.rb +23 -0
- data/lib/plezi/router/assets.rb +67 -0
- data/lib/plezi/router/errors.rb +29 -0
- data/lib/plezi/router/route.rb +112 -0
- data/lib/plezi/router/router.rb +120 -0
- data/lib/plezi/version.rb +1 -1
- data/lib/plezi/websockets/message_dispatch.rb +91 -0
- data/lib/plezi/websockets/redis.rb +55 -0
- data/plezi.gemspec +25 -16
- data/resources/404.erb +5 -4
- data/resources/500.erb +5 -4
- data/resources/{500.html → 503.html} +8 -9
- data/resources/client.js +253 -0
- data/resources/config.ru +5 -36
- data/resources/ctrlr.rb +34 -0
- data/resources/gemfile +4 -0
- data/resources/mini_app.rb +28 -82
- data/resources/mini_exec +7 -0
- data/resources/mini_welcome_page.html +0 -0
- data/resources/procfile +3 -0
- data/resources/rakefile +4 -8
- data/resources/routes.rb +9 -26
- data/resources/{websockets.js → simple-client.js} +3 -3
- metadata +60 -85
- data/bin/plezi +0 -104
- data/docs/async_helpers.md +0 -245
- data/docs/controllers.md +0 -27
- data/docs/logging.md +0 -49
- data/docs/routes.md +0 -209
- data/docs/websockets.md +0 -213
- data/lib/plezi/builders/ac_model.rb +0 -59
- data/lib/plezi/builders/app_builder.rb +0 -137
- data/lib/plezi/builders/builder.rb +0 -43
- data/lib/plezi/builders/form_builder.rb +0 -27
- data/lib/plezi/common/api.rb +0 -92
- data/lib/plezi/common/cache.rb +0 -122
- data/lib/plezi/common/defer.rb +0 -21
- data/lib/plezi/common/dsl.rb +0 -94
- data/lib/plezi/common/redis.rb +0 -65
- data/lib/plezi/common/renderer.rb +0 -141
- data/lib/plezi/common/settings.rb +0 -52
- data/lib/plezi/handlers/controller_core.rb +0 -106
- data/lib/plezi/handlers/controller_magic.rb +0 -284
- data/lib/plezi/handlers/http_router.rb +0 -205
- data/lib/plezi/handlers/placebo.rb +0 -112
- data/lib/plezi/handlers/route.rb +0 -216
- data/lib/plezi/handlers/session.rb +0 -109
- data/lib/plezi/handlers/stubs.rb +0 -156
- data/lib/plezi/handlers/ws_identity.rb +0 -253
- data/lib/plezi/handlers/ws_object.rb +0 -308
- data/lib/plezi/helpers/http_sender.rb +0 -84
- data/lib/plezi/helpers/magic_helpers.rb +0 -104
- data/lib/plezi/helpers/mime_types.rb +0 -1995
- data/lib/plezi/oauth.rb +0 -5
- data/lib/plezi/oauth/auth_controller.rb +0 -229
- data/logo/dark.png +0 -0
- data/logo/light.png +0 -0
- data/logo/sign.png +0 -0
- data/resources/404.haml +0 -121
- data/resources/404.html +0 -124
- data/resources/404.slim +0 -120
- data/resources/500.haml +0 -120
- data/resources/500.slim +0 -120
- data/resources/Gemfile +0 -86
- data/resources/code.rb +0 -8
- data/resources/controller.rb +0 -142
- data/resources/database.yml +0 -33
- data/resources/db_ac_config.rb +0 -59
- data/resources/db_dm_config.rb +0 -51
- data/resources/db_sequel_config.rb +0 -33
- data/resources/en.yml +0 -204
- data/resources/haml_config.rb +0 -6
- data/resources/i18n_config.rb +0 -14
- data/resources/initialize.rb +0 -49
- data/resources/mini_exec.rb +0 -7
- data/resources/oauth_config.rb +0 -24
- data/resources/plezi_client.js +0 -198
- data/resources/plezi_websockets.html +0 -47
- data/resources/redis_config.rb +0 -42
- data/resources/slim_config.rb +0 -11
- data/resources/welcome_page.html +0 -272
- data/test/dispatch +0 -58
- data/test/hello_world +0 -13
- data/test/plezi_tests.rb +0 -581
@@ -1,284 +0,0 @@
|
|
1
|
-
module Plezi
|
2
|
-
|
3
|
-
# the methods defined in this module will be injected into the Controller class passed to
|
4
|
-
# Plezi (using the `route` or `shared_route` commands), and will be available
|
5
|
-
# for the controller to use within it's methods.
|
6
|
-
#
|
7
|
-
# for some reason, the documentation ignores the following additional attributes, which are listed here:
|
8
|
-
#
|
9
|
-
# request:: the HTTPRequest object containing all the data from the HTTP request. If a WebSocket connection was established, the `request` object will continue to contain the HTTP request establishing the connection (cookies, parameters sent and other information).
|
10
|
-
# params:: any parameters sent with the request (short-cut for `request.params`), will contain any GET or POST form data sent (including file upload and JSON format support).
|
11
|
-
# cookies:: a cookie-jar to get and set cookies (set: `cookie\[:name] = data` or get: `cookie\[:name]`). Cookies and some other data must be set BEFORE the response's headers are sent.
|
12
|
-
# flash:: a temporary cookie-jar, good for one request. this is a short-cut for the `response.flash` which handles this magical cookie style.
|
13
|
-
# response:: 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.
|
14
|
-
# host_params:: a copy of the parameters used to create the host and service which accepted the request and created this instance of the controller class.
|
15
|
-
#
|
16
|
-
# For Controller Class menthods, please read the documentation about {Plezi::ControllerMagic::ClassMethods}.
|
17
|
-
#
|
18
|
-
# For Controller Instance methods, please read the documentation about {Plezi::ControllerMagic::InstanceMethods}.
|
19
|
-
#
|
20
|
-
# {include: Plezi::ControllerMagic::InstanceMethods}
|
21
|
-
#
|
22
|
-
module ControllerMagic
|
23
|
-
# @!parse include Plezi::Base::WSObject
|
24
|
-
# @!parse include InstanceMethods
|
25
|
-
# @!parse extend ClassMethods
|
26
|
-
|
27
|
-
def self.included base
|
28
|
-
base.send :include, InstanceMethods
|
29
|
-
base.extend ClassMethods
|
30
|
-
end
|
31
|
-
|
32
|
-
module InstanceMethods
|
33
|
-
|
34
|
-
public
|
35
|
-
|
36
|
-
# the request object, type HTTPRequest.
|
37
|
-
attr_reader :request
|
38
|
-
|
39
|
-
# the :params variable contains all the parameters set by the request (/path?locale=he => params ["locale"] == "he").
|
40
|
-
attr_reader :params
|
41
|
-
|
42
|
-
# A cookie-jar to get and set cookies (set: `cookie [:name] = data` or get: `cookie [ :name ]`).
|
43
|
-
#
|
44
|
-
# Cookies and some other data must be set BEFORE the response's headers are sent.
|
45
|
-
attr_reader :cookies
|
46
|
-
|
47
|
-
# Session data can be stored here (session data will be stored on the Redis server, if Redis is available).
|
48
|
-
#
|
49
|
-
# 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.
|
50
|
-
#
|
51
|
-
# 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.
|
52
|
-
def session
|
53
|
-
@session ||= response.session
|
54
|
-
end
|
55
|
-
|
56
|
-
# 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.
|
57
|
-
attr_reader :response
|
58
|
-
|
59
|
-
# the :flash is a little bit of a magic hash that sets and reads temporary cookies.
|
60
|
-
# these cookies will live for one successful request to a Controller and will then be removed.
|
61
|
-
attr_reader :flash
|
62
|
-
|
63
|
-
# the parameters used to create the host (the parameters passed to the `Plezi.host`).
|
64
|
-
attr_reader :host_params
|
65
|
-
|
66
|
-
# this method does two things.
|
67
|
-
#
|
68
|
-
# 1. sets redirection headers for the response.
|
69
|
-
# 2. sets the `flash` object (short-time cookies) with all the values passed except the :permanent value.
|
70
|
-
#
|
71
|
-
# use:
|
72
|
-
# redirect_to 'http://google.com', notice: "foo", permanent: true
|
73
|
-
# # => redirects to 'http://google.com' with status 301 (permanent redirection) and adds notice: "foo" to the flash
|
74
|
-
# or, a simple temporary redirect:
|
75
|
-
# redirect_to 'http://google.com'
|
76
|
-
# # => redirects to 'http://google.com' with status 302 (default temporary redirection)
|
77
|
-
#
|
78
|
-
# if the url is a symbol or a hash, the method will try to format it into a url Srting, using the `url_for` method.
|
79
|
-
#
|
80
|
-
# if the url is a String, it will be passed along as is.
|
81
|
-
#
|
82
|
-
# An empty String or `nil` will be replaced with the root path for the request's specific host (i.e. `http://localhost:3000/`).
|
83
|
-
#
|
84
|
-
def redirect_to url, options = {}
|
85
|
-
return super() if defined? super
|
86
|
-
url = full_url_for(url, params) unless url.is_a?(String) || url.nil?
|
87
|
-
# redirect
|
88
|
-
response.redirect_to url, options
|
89
|
-
end
|
90
|
-
|
91
|
-
# Returns the RELATIVE url for methods in THIS controller (i.e.: "/path_to_controller/restful/params?non=restful¶ms=foo")
|
92
|
-
#
|
93
|
-
# accepts one parameter:
|
94
|
-
# dest:: a destination object, either a Hash, a Symbol, a Numerical or a String.
|
95
|
-
#
|
96
|
-
# If :dest is a Numerical, a Symbol or a String, it should signify the id of an object or the name of the method this controller should respond to.
|
97
|
-
#
|
98
|
-
# If :dest is a Hash, it should contain all the relevant parameters the url should set (i.e. `url_for id: :new, name: "Jhon Doe"`)
|
99
|
-
#
|
100
|
-
# If :dest is false (or nil), the String returned will be the url to the index.
|
101
|
-
#
|
102
|
-
# * If you use the same controller in different routes, the first route will dictate the returned url's structure (cause by route priority).
|
103
|
-
#
|
104
|
-
# * The route's host will be ignored. Even when using {#full_url_for}, the same host as the current request will be assumed. To change hosts, add the new host's address manualy, i.e.: `request.base_url.gsub('//www.', '//admin.') + UserController.url_for(user.id, params)
|
105
|
-
#
|
106
|
-
# * Not all controllers support this method. Regexp controller paths and multi-path options will throw an exception.
|
107
|
-
def url_for dest = nil
|
108
|
-
self.class.url_for dest, params
|
109
|
-
end
|
110
|
-
# same as #url_for, but returns the full URL (protocol:port:://host/path?params=foo)
|
111
|
-
def full_url_for dest
|
112
|
-
"#{request.base_url}#{self.class.url_for(dest, params)}"
|
113
|
-
end
|
114
|
-
|
115
|
-
# Send raw data to be saved as a file or viewed as an attachment. Browser should believe it had recieved a file.
|
116
|
-
#
|
117
|
-
# this is useful for sending 'attachments' (data to be downloaded) rather then
|
118
|
-
# a regular response.
|
119
|
-
#
|
120
|
-
# this is also useful for offering a file name for the browser to "save as".
|
121
|
-
#
|
122
|
-
# it accepts:
|
123
|
-
# data:: the data to be sent - this could be a String or an open File handle.
|
124
|
-
# options:: a hash of any of the options listed furtheron.
|
125
|
-
#
|
126
|
-
# the :symbol=>value options are:
|
127
|
-
# type:: the mime-type of the data to be sent. defaults to empty. if :filename is supplied, an attempt to guess will be made.
|
128
|
-
# inline:: sets the data to be sent an an inline object (to be viewed rather then downloaded). defaults to false.
|
129
|
-
# filename:: sets a filename for the browser to "save as". defaults to empty.
|
130
|
-
#
|
131
|
-
def send_data data, options = {}
|
132
|
-
raise 'Cannot use "send_data" after headers were sent' if response.headers_sent?
|
133
|
-
if response.body && response.body.any?
|
134
|
-
Plezi.warn 'existing response body was cleared by `#send_data`!'
|
135
|
-
response.body.close if response.body.respond_to? :close
|
136
|
-
end
|
137
|
-
response.body = data
|
138
|
-
|
139
|
-
# set headers
|
140
|
-
content_disposition = options[:inline] ? 'inline' : 'attachment'
|
141
|
-
content_disposition << "; filename=#{::File.basename(options[:filename])}" if options[:filename]
|
142
|
-
|
143
|
-
response['content-type'] = (options[:type] ||= options[:filename] && MimeTypeHelper::MIME_DICTIONARY[::File.extname(options[:filename])])
|
144
|
-
response['content-disposition'] = content_disposition
|
145
|
-
true
|
146
|
-
end
|
147
|
-
|
148
|
-
# Renders a template file (.slim/.erb/.haml) to a String and attempts to set the response's 'content-type' header (if it's still empty).
|
149
|
-
#
|
150
|
-
# For example, to render the file `body.html.slim` with the layout `main_layout.html.haml`:
|
151
|
-
# render :body, layout: :main_layout
|
152
|
-
#
|
153
|
-
# or, for example, to render the file `json.js.slim`
|
154
|
-
# render :json, format: 'js'
|
155
|
-
#
|
156
|
-
# or, for example, to render the file `template.haml`
|
157
|
-
# render :template, format: ''
|
158
|
-
#
|
159
|
-
# template:: a Symbol for the template to be used.
|
160
|
-
# options:: a Hash for any options such as `:layout` or `locale`.
|
161
|
-
# block:: an optional block, in case the template has `yield`, the block will be passed on to the template and it's value will be used inplace of the yield statement.
|
162
|
-
#
|
163
|
-
# options aceept the following keys:
|
164
|
-
# format:: the format for the `:layout' and 'template'. can be any format (the file's sub-extention), such as `"json"`. defaults to `"html"`.
|
165
|
-
# layout:: a layout template that has at least one `yield` statement where the template will be rendered.
|
166
|
-
# locale:: the I18n locale for the render. (defaults to params\[:locale]) - only if the I18n gem namespace is defined (`require 'i18n'`).
|
167
|
-
#
|
168
|
-
# if template is a string, it will assume the string is an
|
169
|
-
# absolute path to a template file. it will NOT search for the template but might raise exceptions.
|
170
|
-
#
|
171
|
-
# if the template is a symbol, the '_' characters will be used to destinguish sub-folders (NOT a partial template).
|
172
|
-
#
|
173
|
-
# returns false if the template or layout files cannot be found.
|
174
|
-
def render template, options = {}, &block
|
175
|
-
# make sure templates are enabled
|
176
|
-
return false if host_params[:templates].nil?
|
177
|
-
# set up defaults
|
178
|
-
@warned_type ||= (Iodine.warn("Deprecation warning! `#render` method called with optional `:type`. Use `:format` instead!") && true) if options[:type]
|
179
|
-
options[:format] ||= (options[:type] || params[:format] || 'html'.freeze).to_s
|
180
|
-
options[:locale] ||= params[:locale].to_sym if params[:locale]
|
181
|
-
# render layout using recursion, if exists
|
182
|
-
if options[:layout]
|
183
|
-
layout = options.delete(:layout)
|
184
|
-
inner = render(template, options, &block)
|
185
|
-
return false unless inner
|
186
|
-
return render(layout, options) { inner }
|
187
|
-
end
|
188
|
-
#update content-type header
|
189
|
-
case options[:format]
|
190
|
-
when 'html', 'js', 'txt'
|
191
|
-
response['content-type'] ||= "#{MimeTypeHelper::MIME_DICTIONARY[".#{options[:format]}".freeze]}; charset=utf-8".freeze
|
192
|
-
else
|
193
|
-
response['content-type'] ||= "#{MimeTypeHelper::MIME_DICTIONARY[".#{options[:format]}".freeze]}".freeze
|
194
|
-
end
|
195
|
-
# Circumvents I18n persistance issues (live updating and thread data storage).
|
196
|
-
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]
|
197
|
-
# find template and create template object
|
198
|
-
template = [template] if template.is_a?(String)
|
199
|
-
filename = ( template.is_a?(Array) ? File.join( host_params[:templates].to_s, *template) : File.join( host_params[:templates].to_s, *template.to_s.split('_'.freeze) ) ) + (options[:format].empty? ? ''.freeze : ".#{options[:format]}".freeze)
|
200
|
-
::Plezi::Renderer.render filename, binding, &block
|
201
|
-
end
|
202
|
-
|
203
|
-
# returns the initial method called (or about to be called) by the router for the HTTP request.
|
204
|
-
#
|
205
|
-
# this can be very useful within the before / after filters:
|
206
|
-
# def before
|
207
|
-
# return false unless "check credentials" && [:save, :update, :delete].include?(requested_method)
|
208
|
-
#
|
209
|
-
# if the controller responds to a WebSockets request (a controller that defines the `on_message` method),
|
210
|
-
# the value returned is invalid and will remain 'stuck' on :pre_connect
|
211
|
-
# (which is the last method called before the protocol is switched from HTTP to WebSockets).
|
212
|
-
def requested_method
|
213
|
-
# respond to websocket special case
|
214
|
-
return :pre_connect if request.upgrade?
|
215
|
-
# respond to save 'new' special case
|
216
|
-
return (self.class.has_method?(:save) ? :save : false) if (request.request_method =~ /POST|PUT|PATCH/i.freeze) && (params[:id].nil? || params[:id] == 'new'.freeze)
|
217
|
-
# set DELETE method if simulated
|
218
|
-
request.request_method = 'DELETE'.freeze if params[:_method] && params[:_method].to_s.downcase == 'delete'.freeze
|
219
|
-
# respond to special :id routing
|
220
|
-
params[:id].to_s.downcase.to_sym.tap { |met| return met if self.class.has_exposed_method?(met) } if params[:id]
|
221
|
-
#review general cases
|
222
|
-
case request.request_method
|
223
|
-
when 'GET'.freeze, 'HEAD'.freeze
|
224
|
-
return (self.class.has_method?(:index) ? :index : false) unless params[:id]
|
225
|
-
return (self.class.has_method?(:show) ? :show : false)
|
226
|
-
when 'POST'.freeze, 'PUT'.freeze, 'PATCH'.freeze
|
227
|
-
return (self.class.has_method?(:update) ? :update : false)
|
228
|
-
when 'DELETE'.freeze
|
229
|
-
return (self.class.has_method?(:delete) ? :delete : false)
|
230
|
-
end
|
231
|
-
false
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
module ClassMethods
|
236
|
-
public
|
237
|
-
|
238
|
-
# This class method behaves the same way as the instance method #url_for, but accepts an added `params` Hash
|
239
|
-
# that will be used to infer any persistent re-write parameters (i.e. `:locale` or `:format`).
|
240
|
-
# See the instance method's documentation for more details.
|
241
|
-
def url_for dest, params={}
|
242
|
-
case dest
|
243
|
-
when :index, nil, false
|
244
|
-
dest = {}
|
245
|
-
when String
|
246
|
-
dest = {id: dest}
|
247
|
-
when Numeric, Symbol
|
248
|
-
dest = {id: dest}
|
249
|
-
when Hash
|
250
|
-
true
|
251
|
-
else
|
252
|
-
# convert dest.id and dest[:id] to their actual :id value.
|
253
|
-
dest = {id: (dest.id rescue false) || (raise TypeError, "Expecting a Symbol, Hash, String, Numeric or an object that answers to obj[:id] or obj.id") }
|
254
|
-
end
|
255
|
-
::Plezi::Base::HTTPRouter.url_for self, dest, params
|
256
|
-
end
|
257
|
-
|
258
|
-
# resets the routing cache
|
259
|
-
def reset_routing_cache
|
260
|
-
@inheritance.each {|sub| sub.reset_routing_cache} if @inheritance
|
261
|
-
end
|
262
|
-
|
263
|
-
protected
|
264
|
-
|
265
|
-
# a callback that resets the class router whenever a method (a potential route) is added
|
266
|
-
def method_added(id)
|
267
|
-
reset_routing_cache
|
268
|
-
end
|
269
|
-
# a callback that resets the class router whenever a method (a potential route) is removed
|
270
|
-
def method_removed(id)
|
271
|
-
reset_routing_cache
|
272
|
-
end
|
273
|
-
# a callback that resets the class router whenever a method (a potential route) is undefined (using #undef_method).
|
274
|
-
def method_undefined(id)
|
275
|
-
reset_routing_cache
|
276
|
-
end
|
277
|
-
|
278
|
-
def inherited sub
|
279
|
-
(@inheritance ||= [].to_set) << sub
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
end
|
284
|
-
end
|
@@ -1,205 +0,0 @@
|
|
1
|
-
module Plezi
|
2
|
-
|
3
|
-
module Base
|
4
|
-
|
5
|
-
#####
|
6
|
-
# handles the HTTP Routing
|
7
|
-
module HTTPRouter
|
8
|
-
|
9
|
-
class Host
|
10
|
-
attr_reader :params
|
11
|
-
attr_reader :routes
|
12
|
-
def initialize params
|
13
|
-
@params = params
|
14
|
-
@routes = []
|
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
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# return the upgrade handler (the self.on_upgrade method)
|
22
|
-
def upgrade_proc
|
23
|
-
self.method :on_upgrade
|
24
|
-
end
|
25
|
-
#handles websocket connection requests.
|
26
|
-
def on_upgrade request, response
|
27
|
-
host = get_host(request[:host_name].to_s.downcase) || @hosts[:default]
|
28
|
-
return false unless host
|
29
|
-
request[:host_settings] = host.params
|
30
|
-
# return if a route answered the request
|
31
|
-
host.routes.each {|r| a = r.on_request(request, response); return a if a}
|
32
|
-
# websockets should cut out here
|
33
|
-
false
|
34
|
-
end
|
35
|
-
# initializes the HTTP router (the normal Handler for HTTP requests)
|
36
|
-
#
|
37
|
-
# the router holds the different hosts and sends them messages/requests.
|
38
|
-
@hosts = {}
|
39
|
-
@active_host = nil
|
40
|
-
|
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})
|
42
|
-
def add_host host_name, params = {}
|
43
|
-
(params = host_name) && (host_name = params.delete(:host)) if host_name.is_a?(Hash)
|
44
|
-
params[:index_file] ||= 'index.html'
|
45
|
-
params[:assets_public] ||= '/assets'
|
46
|
-
params[:assets_public].chomp! '/'
|
47
|
-
params[:public] ||= params[:root] # backwards compatability
|
48
|
-
host_name = (host_name.is_a?(String) ? host_name.to_s.downcase : (host_name.is_a?(Regexp) ? host_name : :default))
|
49
|
-
@active_host = get_host(host_name) || ( @hosts[host_name] = Host.new(params) )
|
50
|
-
add_alias host_name, *params[:alias] if params[:alias] # && host_name != :default
|
51
|
-
@active_host
|
52
|
-
end
|
53
|
-
# adds an alias to an existing host name (normally through the :alias parameter in the `add_host` method).
|
54
|
-
def add_alias host_name, *aliases
|
55
|
-
host = get_host host_name
|
56
|
-
raise "Couldn't find requested host to add alias." unless host
|
57
|
-
aliases.each {|a| @hosts[a.to_s.downcase] = host}
|
58
|
-
true
|
59
|
-
end
|
60
|
-
|
61
|
-
# adds a route to the active host. The active host is the last host referenced by the `add_host`.
|
62
|
-
def add_route path, controller, &block
|
63
|
-
@active_host ||= add_host :default
|
64
|
-
@active_host.routes << ::Plezi::Base::Route.new(path, controller, &block)
|
65
|
-
end
|
66
|
-
|
67
|
-
# adds a route to all existing hosts.
|
68
|
-
def add_shared_route path, controller, &block
|
69
|
-
add_host :default if @hosts.empty?
|
70
|
-
@hosts.each {|n, h| h.routes << ::Plezi::Base::Route.new(path, controller, &block) }
|
71
|
-
end
|
72
|
-
|
73
|
-
# handles requests send by the HTTP Protocol (HTTPRequest objects)
|
74
|
-
def call request, response
|
75
|
-
begin
|
76
|
-
host = get_host(request[:host_name].to_s.downcase) || @hosts[:default]
|
77
|
-
return false unless host
|
78
|
-
request[:host_settings] = host.params
|
79
|
-
# render any assets?
|
80
|
-
return true if render_assets request, response, host.params
|
81
|
-
# send static file, if exists and root is set.
|
82
|
-
return true if Base::HTTPSender.send_static_file request, response
|
83
|
-
# return if a route answered the request
|
84
|
-
host.routes.each {|r| a = r.on_request(request, response); return a if a}
|
85
|
-
#return error code or 404 not found
|
86
|
-
return Base::HTTPSender.send_by_code request, response, 404 unless ( @avoid_404 ||= ( Iodine::Http.on_http == ::Iodine::Http::Rack ? 1 : 0 ) ) == 1
|
87
|
-
rescue => e
|
88
|
-
# return 500 internal server error.
|
89
|
-
Iodine.error e
|
90
|
-
Base::HTTPSender.send_by_code request, response, 500
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# This method attempts to guess at the desired controller's URL, based on it's first path in order of route creation (ignoring host hierarchy).
|
95
|
-
#
|
96
|
-
# This will be usually used by the Controller's #url_for method to get the relative part of the url.
|
97
|
-
def url_for controller, dest, params = {}
|
98
|
-
raise TypeError, "Expecting destination parameter to be a Hash" unless dest.is_a?(Hash)
|
99
|
-
host = nil
|
100
|
-
@hosts.values.each do |h|
|
101
|
-
h.routes.each {|r| (host = h) && (controller = r.controller) && break if r.controller && r.controller.ancestors.include?(controller) }
|
102
|
-
break if host
|
103
|
-
end
|
104
|
-
raise "couldn't find Controller's route and host." unless host
|
105
|
-
url = []
|
106
|
-
dest = dest.dup
|
107
|
-
dest.default_proc = Plezi::Base::Helpers::HASH_SYM_PROC
|
108
|
-
host.routes.each do |r|
|
109
|
-
if r.controller == false
|
110
|
-
add = []
|
111
|
-
r.url_array.each do |sec|
|
112
|
-
next if sec == '*'
|
113
|
-
param_name = (::Plezi::Base::Route::REGEXP_OPTIONAL_PARAMS.match(sec) || ::Plezi::Base::Route::REGEXP_FORMATTED_OPTIONAL_PARAMS.match(sec) || ::Plezi::Base::Route::REGEXP_REQUIRED_PARAMS.match(sec) || ::Plezi::Base::Route::REGEXP_FORMATTED_REQUIRED_PARAMS.match(sec))
|
114
|
-
param_name = param_name[1].to_sym if param_name
|
115
|
-
|
116
|
-
if param_name && (dest[param_name] || params[param_name])
|
117
|
-
add << Plezi::Base::Helpers.encode_url(dest.delete(param_name) || params[param_name])
|
118
|
-
elsif !param_name
|
119
|
-
add << sec
|
120
|
-
else
|
121
|
-
add.clear
|
122
|
-
next
|
123
|
-
end
|
124
|
-
end if r.url_array
|
125
|
-
url.concat add
|
126
|
-
end
|
127
|
-
if r.controller == controller
|
128
|
-
raise NotImplementedError, "#url_for isn't implemented for this controller's route - could this be a Regexp based or special route?" unless r.url_array
|
129
|
-
r.url_array.each do |sec|
|
130
|
-
next if sec == '*'
|
131
|
-
param_name = (::Plezi::Base::Route::REGEXP_OPTIONAL_PARAMS.match(sec) || ::Plezi::Base::Route::REGEXP_FORMATTED_OPTIONAL_PARAMS.match(sec) || ::Plezi::Base::Route::REGEXP_REQUIRED_PARAMS.match(sec) || ::Plezi::Base::Route::REGEXP_FORMATTED_REQUIRED_PARAMS.match(sec))
|
132
|
-
param_name = param_name[1].to_sym if param_name
|
133
|
-
if param_name && dest[param_name]
|
134
|
-
url << Plezi::Base::Helpers.encode_url(dest.delete(param_name))
|
135
|
-
elsif !param_name
|
136
|
-
url << sec
|
137
|
-
elsif ::Plezi::Base::Route::REGEXP_REQUIRED_PARAMS === sec || ::Plezi::Base::Route::REGEXP_OPTIONAL_PARAMS === sec
|
138
|
-
url << ''.freeze
|
139
|
-
elsif ::Plezi::Base::Route::REGEXP_FORMATTED_REQUIRED_PARAMS === sec
|
140
|
-
raise ArgumentError, "URL can't be formatted becuse a required parameter (#{param_name.to_s}) isn't specified and it requires a special format (#{::Plezi::Base::Route::REGEXP_FORMATTED_REQUIRED_PARAMS.match(sec)[2]})."
|
141
|
-
end
|
142
|
-
end
|
143
|
-
return "/#{url.join '/'.freeze}#{"?#{dest.map {|k,v| "#{Plezi::Base::Helpers.encode_url k}=#{Plezi::Base::Helpers.encode_url v}" } .join('&'.freeze)}" if dest.any?}"
|
144
|
-
end
|
145
|
-
end
|
146
|
-
false
|
147
|
-
end
|
148
|
-
|
149
|
-
protected
|
150
|
-
|
151
|
-
def get_host host_name
|
152
|
-
@hosts.each {|k, v| return v if k === host_name}
|
153
|
-
nil
|
154
|
-
end
|
155
|
-
|
156
|
-
###############
|
157
|
-
## asset rendering and responses
|
158
|
-
|
159
|
-
# renders assets, if necessary, and places the rendered result in the cache and in the public folder.
|
160
|
-
def render_assets request, response, params
|
161
|
-
# contine only if assets are defined and called for
|
162
|
-
return false unless params[:assets] && (request.path =~ params[:assets_public_regex])
|
163
|
-
# review callback, if defined
|
164
|
-
return true if params[:assets_callback] && params[:assets_callback].call(request, response)
|
165
|
-
|
166
|
-
# get file requested
|
167
|
-
source_file = File.join(params[:assets], *(request.path[params[:assets_public_length]..-1].split('/')))
|
168
|
-
|
169
|
-
|
170
|
-
# stop if file name is reserved / has security issues
|
171
|
-
return false if File.directory?(source_file) || source_file =~ params[:assets_refuse_templates]
|
172
|
-
|
173
|
-
# set where to store the rendered asset
|
174
|
-
target_file = File.join( params[:public].to_s, *request.path.split('/') )
|
175
|
-
|
176
|
-
# send the file if it exists (no render needed)
|
177
|
-
if File.exists?(source_file)
|
178
|
-
data = if ::Plezi::Cache::CACHABLE.include?(::File.extname(source_file)[1..-1])
|
179
|
-
Plezi.cache_needs_update?(source_file) ? Plezi.save_file(target_file, Plezi.reload_file(source_file), (params[:public] && params[:save_assets])) : Plezi.load_file(source_file)
|
180
|
-
else
|
181
|
-
::File.new source_file, 'rb'
|
182
|
-
end
|
183
|
-
return (data ? Base::HTTPSender.send_raw_data(request, response, data, MimeTypeHelper::MIME_DICTIONARY[::File.extname(source_file)]) : false)
|
184
|
-
end
|
185
|
-
|
186
|
-
# render the file if it's a registered asset
|
187
|
-
data = ::Plezi::AssetManager.render source_file, binding
|
188
|
-
if data
|
189
|
-
return ::Plezi::Base::HTTPSender.send_raw_data request, response, Plezi.save_file(target_file, data, (params[:public] && params[:save_assets])), MimeTypeHelper::MIME_DICTIONARY[::File.extname(source_file)]
|
190
|
-
end
|
191
|
-
|
192
|
-
# send the data if it's a cached asset (map files and similar assets that were cached while rendering)
|
193
|
-
if Plezi.cached?(source_file)
|
194
|
-
return Base::HTTPSender.send_raw_data(request, response, Plezi.get_cached(source_file), MimeTypeHelper::MIME_DICTIONARY[::File.extname(source_file)])
|
195
|
-
end
|
196
|
-
|
197
|
-
# return false if an asset couldn't be rendered and wasn't found.
|
198
|
-
return false
|
199
|
-
end
|
200
|
-
extend self
|
201
|
-
end
|
202
|
-
Iodine::Http.on_http ::Plezi::Base::HTTPRouter
|
203
|
-
Iodine::Http.on_websocket ::Plezi::Base::HTTPRouter.upgrade_proc
|
204
|
-
end
|
205
|
-
end
|