plezi 0.12.22 → 0.14.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 +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
|