Module: Plezi::Controller
- Included in:
- Base::Err404Ctrl, Base::Err500Ctrl
- Defined in:
- lib/plezi/controller/controller.rb,
lib/plezi/controller/cookies.rb,
lib/plezi/controller/controller_class.rb
Overview
This module contains the functionality provided to any Controller class.
This module will be included within every Class that is asigned to a route, providing the functionality without forcing an inheritance model.
Any Controller can suppoert WebSocket connections by either implementing an ‘on_message(data)` callback or setting the `@auto_dispatch` class instance variable to `true`.
Defined Under Namespace
Modules: ClassMethods Classes: Cookies
Instance Attribute Summary collapse
-
#_pl__client ⇒ Object
readonly
Used internally to access the Iodine::Connection client data (if available).
-
#cookies ⇒ Object
readonly
A cookie jar for both accessing and setting cookies.
-
#params ⇒ Object
readonly
A union between the ‘request.params` and the route’s inline parameters.
-
#request ⇒ Object
readonly
A Rack::Request object for the current request.
-
#response ⇒ Object
readonly
A Rack::Response object used for the current request.
Class Method Summary collapse
Instance Method Summary collapse
-
#_pl_ad_httpreview(data) ⇒ Object
This function is used internally by Plezi, do not call.
-
#_pl_ad_map ⇒ Object
This function is used internally by Plezi, do not call.
-
#_pl_ad_review(data) ⇒ Object
This function is used internally by Plezi, do not call.
-
#_pl_respond(request, response, params) ⇒ Object
This function is used internally by Plezi, do not call.
-
#_pl_ws_map ⇒ Object
This function is used internally by Plezi, do not call.
-
#close ⇒ Object
Closes an SSE / WebSocket connection (raises an error unless the connection was already established).
-
#extend(mod) ⇒ Object
Experimental: takes a module to be used for Websocket callbacks events.
-
#keys ⇒ Object
Returns an array with all the keys of any available cookies (both existing and new cookies).
-
#on_close ⇒ Object
Overload this method to handle event.
-
#on_drained ⇒ Object
Overload this method to handle event.
-
#on_message(data) ⇒ Object
This function is used internally by Plezi, for Auto-Dispatch support do not call.
-
#on_open ⇒ Object
Overload this method to handle event.
-
#on_shutdown ⇒ Object
Overload this method to handle event.
-
#open? ⇒ Boolean
Tests the known state for an SSE / WebSocket connection (the known state might not be the same as the actual state).
-
#pending ⇒ Object
Returns the number of pending ‘write` operations that need to complete before the next `on_drained` callback is called.
-
#pre_connect ⇒ Object
Override this method to read / write cookies, perform authentication or perform validation before establishing a Websocket or SSE connecion.
-
#publish(*args) ⇒ Object
Publishes to a Pub/Sub stream / channel (routes to Iodine.publish).
-
#redirect_to(target, status = 302) ⇒ Object
A shortcut for Rack’s ‘response.redirect`.
-
#render(template, &block) ⇒ Object
Renders the requested template (should be a string, subfolders are fine).
-
#requested_method ⇒ Object
Returns the method that was called by the HTTP request.
-
#send_data(data, options = {}) ⇒ Object
Sends a block of data, setting a file name, mime type and content disposition headers when possible.
-
#send_file(filename, options = {}) ⇒ Object
Same as #send_data, but accepts a file name (to be opened and sent) rather then a String.
-
#subscribe(*args, &block) ⇒ Object
Subscribes to a Pub/Sub stream / channel or replaces an existing subscription to the same stream / channel (raises an error unless an SSE / WebSocket connection was established).
-
#to_s ⇒ Object
Writes a line dlimited string of all the existing and the new cookies.
-
#url_for(func, params = {}) ⇒ Object
Returns a relative URL for the controller, placing the requested parameters in the URL (inline, where possible and as query data when not possible).
-
#values ⇒ Object
Returns an array with all the values of any available cookies (both existing and new cookies).
-
#write(data) ⇒ Object
Writes to an SSE / WebSocket connection (raises an error unless the connection was already established).
Instance Attribute Details
#_pl__client ⇒ Object (readonly)
Used internally to access the Iodine::Connection client data (if available).
44 45 46 |
# File 'lib/plezi/controller/controller.rb', line 44 def _pl__client @_pl__client end |
#cookies ⇒ Object (readonly)
A cookie jar for both accessing and setting cookies. Unifies ‘request.set_cookie`, `request.delete_cookie` and `request.cookies` with a single Hash like inteface.
Read a cookie:
["name"]
Set a cookie:
["name"] = "value"
["name"] = {value: "value", secure: true}
Delete a cookie:
["name"] = nil
40 41 42 |
# File 'lib/plezi/controller/controller.rb', line 40 def @cookies end |
#params ⇒ Object (readonly)
A union between the ‘request.params` and the route’s inline parameters. This is different then ‘request.params`
24 25 26 |
# File 'lib/plezi/controller/controller.rb', line 24 def params @params end |
#request ⇒ Object (readonly)
A Rack::Request object for the current request.
20 21 22 |
# File 'lib/plezi/controller/controller.rb', line 20 def request @request end |
#response ⇒ Object (readonly)
A Rack::Response object used for the current request.
22 23 24 |
# File 'lib/plezi/controller/controller.rb', line 22 def response @response end |
Class Method Details
.included(base) ⇒ Object
15 16 17 |
# File 'lib/plezi/controller/controller.rb', line 15 def self.included(base) base.extend ::Plezi::Controller::ClassMethods end |
Instance Method Details
#_pl_ad_httpreview(data) ⇒ Object
This function is used internally by Plezi, do not call.
258 259 260 261 |
# File 'lib/plezi/controller/controller.rb', line 258 def _pl_ad_httpreview(data) return data.to_json if self.class._pl_is_ad? && data.is_a?(Hash) data end |
#_pl_ad_map ⇒ Object
This function is used internally by Plezi, do not call.
199 200 201 |
# File 'lib/plezi/controller/controller.rb', line 199 def _pl_ad_map @_pl_ad_map ||= self.class._pl_ad_map.dup end |
#_pl_ad_review(data) ⇒ Object
This function is used internally by Plezi, do not call.
244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/plezi/controller/controller.rb', line 244 def _pl_ad_review(data) return data unless self.class._pl_is_ad? case data when Hash _pl__client.write data.to_json when String _pl__client.write data # when Array # write data.to_json end end |
#_pl_respond(request, response, params) ⇒ Object
This function is used internally by Plezi, do not call.
48 49 50 51 52 53 54 55 56 57 |
# File 'lib/plezi/controller/controller.rb', line 48 def _pl_respond(request, response, params) @request = request @response = response @params = params @cookies = Cookies.new(request, response) mthd = requested_method # puts "m == #{m.nil? ? 'nil' : m.to_s}" return _pl_ad_httpreview(__send__(mthd)) if mthd false end |
#_pl_ws_map ⇒ Object
This function is used internally by Plezi, do not call.
193 194 195 |
# File 'lib/plezi/controller/controller.rb', line 193 def _pl_ws_map @_pl_ws_map ||= self.class._pl_ws_map.dup end |
#close ⇒ Object
Closes an SSE / WebSocket connection (raises an error unless the connection was already established).
143 144 145 |
# File 'lib/plezi/controller/controller.rb', line 143 def close _pl__client.close end |
#extend(mod) ⇒ Object
Experimental: takes a module to be used for Websocket callbacks events.
This function can only be called after a websocket connection was established (i.e., within the ‘on_open` callback).
This allows a module “library” to be used similar to the way “rooms” are used in node.js, so that a number of different Controllers can listen to shared events.
By dynamically extending a Controller instance using a module, Auto Dispatch events can be routed to the newly available methods.
Notice: It is impossible to ‘unextend` an extended module at this time.
181 182 183 184 185 186 187 188 189 |
# File 'lib/plezi/controller/controller.rb', line 181 def extend(mod) raise TypeError, '`mod` should be a module' unless mod.class == Module unless is_a?(mod) mod.extend ::Plezi::Controller::ClassMethods super(mod) end _pl_ws_map.update mod._pl_ws_map _pl_ad_map.update mod._pl_ad_map end |
#keys ⇒ Object
Returns an array with all the keys of any available cookies (both existing and new cookies).
47 48 49 |
# File 'lib/plezi/controller/cookies.rb', line 47 def keys (@request ? (super + request..keys) : super) end |
#on_close ⇒ Object
Overload this method to handle event.
209 210 |
# File 'lib/plezi/controller/controller.rb', line 209 def on_close end |
#on_drained ⇒ Object
Overload this method to handle event.
213 214 |
# File 'lib/plezi/controller/controller.rb', line 213 def on_drained end |
#on_message(data) ⇒ Object
This function is used internally by Plezi, for Auto-Dispatch support do not call.
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/plezi/controller/controller.rb', line 222 def (data) json = nil begin json = JSON.parse(data, symbolize_names: true) # json.default_proc = Plezi.hash_proc_4symstr rescue puts 'AutoDispatch Warnnig: Received non-JSON message. Closing Connection.' close return end envt = _pl_ad_map[json[:event]] || _pl_ad_map[:unknown] if json[:event].nil? || envt.nil? puts _pl_ad_map puts "AutoDispatch Warnnig: JSON missing/invalid `event` name '#{json[:event]}' for class #{self.class.name}. Closing Connection." close end _pl__client.write("{\"event\":\"_ack_\",\"_EID_\":#{json[:_EID_].to_json}}") if json[:_EID_] _pl_ad_review __send__(envt, json) end |
#on_open ⇒ Object
Overload this method to handle event.
205 206 |
# File 'lib/plezi/controller/controller.rb', line 205 def on_open end |
#on_shutdown ⇒ Object
Overload this method to handle event.
217 218 |
# File 'lib/plezi/controller/controller.rb', line 217 def on_shutdown end |
#open? ⇒ Boolean
Tests the known state for an SSE / WebSocket connection (the known state might not be the same as the actual state).
147 148 149 |
# File 'lib/plezi/controller/controller.rb', line 147 def open? _pl__client && _pl__client.open? end |
#pending ⇒ Object
Returns the number of pending ‘write` operations that need to complete before the next `on_drained` callback is called.
151 152 153 154 |
# File 'lib/plezi/controller/controller.rb', line 151 def pending return 0 unless _pl__client _pl__client.pending end |
#pre_connect ⇒ Object
Override this method to read / write cookies, perform authentication or perform validation before establishing a Websocket or SSE connecion.
Return ‘false` or `nil` to refuse the websocket connection.
133 134 135 |
# File 'lib/plezi/controller/controller.rb', line 133 def pre_connect true end |
#publish(*args) ⇒ Object
Publishes to a Pub/Sub stream / channel (routes to Iodine.publish).
167 168 169 |
# File 'lib/plezi/controller/controller.rb', line 167 def publish *args ::Iodine.publish *args end |
#redirect_to(target, status = 302) ⇒ Object
A shortcut for Rack’s ‘response.redirect`.
120 121 122 123 |
# File 'lib/plezi/controller/controller.rb', line 120 def redirect_to(target, status = 302) response.redirect target, status true end |
#render(template, &block) ⇒ Object
Renders the requested template (should be a string, subfolders are fine).
Template name shouldn’t include the template’s extension or format - this allows for dynamic format template resolution, so that ‘json` and `html` requests can share the same code. i.e.
Plezi.templates = "views/"
render "users/index"
Using layouts (nested templates) is easy by using a block (a little different then other frameworks):
render("users/layout") { render "users/index" }
80 81 82 83 84 85 86 |
# File 'lib/plezi/controller/controller.rb', line 80 def render(template, &block) frmt = params['format'.freeze] || 'html'.freeze mime = nil ret = ::Plezi::Renderer.render "#{File.join(::Plezi.templates, template.to_s)}.#{frmt}", binding, &block response[Rack::CONTENT_TYPE] = mime if ret && !response.content_type && (mime = Rack::Mime.mime_type(".#{frmt}".freeze, nil)) ret end |
#requested_method ⇒ Object
Returns the method that was called by the HTTP request.
It’s possible to override this method to change the default Controller behavior.
For Websocket connections this method is most likely to return :preform_upgrade
64 65 66 67 |
# File 'lib/plezi/controller/controller.rb', line 64 def requested_method params['_method'.freeze] = (params['_method'.freeze] || request.request_method.downcase).to_sym self.class._pl_params2method(params, request.env) end |
#send_data(data, options = {}) ⇒ Object
Sends a block of data, setting a file name, mime type and content disposition headers when possible. This should also be a good choice when sending large amounts of data.
By default, ‘send_data` sends the data as an attachment, unless `inline: true` was set.
If a mime type is provided, it will be used to set the Content-Type header. i.e. ‘mime: “text/plain”`
If a file name was provided, Rack will be used to find the correct mime type (unless provided). i.e. ‘filename: “sample.pdf”` will set the mime type to `application/pdf`
Available options: ‘:inline` (`true` / `false`), `:filename`, `:mime`.
97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/plezi/controller/controller.rb', line 97 def send_data(data, = {}) response.write data if data filename = [:filename] # set headers content_disposition = [:inline] ? 'inline'.dup : 'attachment'.dup content_disposition << "; filename=#{::File.basename([:filename])}" if filename cont_type = ([:mime] ||= filename && Rack::Mime.mime_type(::File.extname(filename))) response['content-type'.freeze] = cont_type if cont_type response['content-disposition'.freeze] = content_disposition true end |
#send_file(filename, options = {}) ⇒ Object
Same as #send_data, but accepts a file name (to be opened and sent) rather then a String.
See #send_data for available options.
112 113 114 115 116 117 |
# File 'lib/plezi/controller/controller.rb', line 112 def send_file(filename, = {}) response['X-Sendfile'.freeze] = filename [:filename] ||= File.basename(filename) filename = File.open(filename, 'rb'.freeze) # unless Iodine::Rack.public send_data filename, end |
#subscribe(*args, &block) ⇒ Object
Subscribes to a Pub/Sub stream / channel or replaces an existing subscription to the same stream / channel (raises an error unless an SSE / WebSocket connection was established).
157 158 159 160 161 162 163 164 |
# File 'lib/plezi/controller/controller.rb', line 157 def subscribe *args, &block raise "WebSocket / SSE connection missing" unless _pl__client if(block) _pl__client.subscribe *args, &block else _pl__client.subscribe *args end end |
#to_s ⇒ Object
Writes a line dlimited string of all the existing and the new cookies. i.e.:
name1=value1
name2=value2
42 43 44 |
# File 'lib/plezi/controller/cookies.rb', line 42 def to_s (@request ? (to_a + request..to_a) : to_a).map! { |pair| pair.join('=') } .join "\n" end |
#url_for(func, params = {}) ⇒ Object
Returns a relative URL for the controller, placing the requested parameters in the URL (inline, where possible and as query data when not possible).
126 127 128 |
# File 'lib/plezi/controller/controller.rb', line 126 def url_for(func, params = {}) ::Plezi::Base::Router.url_for self.class, func, params end |
#values ⇒ Object
Returns an array with all the values of any available cookies (both existing and new cookies).
52 53 54 |
# File 'lib/plezi/controller/cookies.rb', line 52 def values (@request ? (super + request..values) : super) end |
#write(data) ⇒ Object
Writes to an SSE / WebSocket connection (raises an error unless the connection was already established).
138 139 140 |
# File 'lib/plezi/controller/controller.rb', line 138 def write data _pl__client.write data end |