lib/plezi/handlers/ws_object.rb in plezi-0.12.2 vs lib/plezi/handlers/ws_object.rb in plezi-0.12.3

- old
+ new

@@ -1,33 +1,76 @@ module Plezi - # the methods defined in this module will be injected into the Controller class passed to - # Plezi (using the `route` or `shared_route` commands), and will be available - # for the controller to use within it's methods. - # - # for some reason, the documentation ignores the following additional attributes, which are listed here: - # - # 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). - # 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). - # 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. - # flash:: a temporary cookie-jar, good for one request. this is a short-cut for the `response.flash` which handles this magical cookie style. - # 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. - # 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. - # module Base # This module includes all the methods that will be injected into Websocket objects, # specifically into Plezi Controllers and Placebo objects. + # + # the methods defined in this module will be injected into the Controller class passed to + # Plezi (using the `route` or `shared_route` commands), and will be available + # for the controller to use within it's methods. + # + # for some reason, the documentation ignores the following additional attributes, which are listed here: + # + # 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). + # 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). + # 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. + # flash:: a temporary cookie-jar, good for one request. this is a short-cut for the `response.flash` which handles this magical cookie style. + # 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. + # 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. + # module WSObject def self.included base base.send :include, InstanceMethods base.extend ClassMethods base.superclass.instance_eval {extend SuperClassMethods} + base.superclass.instance_eval {include SuperInstanceMethods} end + def self.translate_message msg + begin + @safe_types ||= [Symbol, Date, Time, Encoding, Struct, Regexp, Range, Set] + data = YAML.safe_load(msg, @safe_types) + rescue => e + Iodine.error "The following could be a security breach attempt:" + Iodine.error e + nil + end + end + def self.forward_message data + begin + return false if data[:server] == Plezi::Settings.uuid + data[:type] = Object.const_get(data[:type]) unless data[:type].nil? || data[:type] == :all + if data[:target] + data[:type].___faild_unicast( data ) unless Iodine::Http::Websockets.unicast data[:target], data + else + Iodine::Http::Websockets.broadcast data + end + rescue => e + Iodine.error "The following could be a security breach attempt:" + Iodine.error e + nil + end + end + module InstanceMethods public + + # handles websocket opening. + def on_open + @ws_io = @request[:io] + super() if defined?(super) + end + # handles websocket messages. + def on_message data + super if defined?(super) + end + # handles websocket being closed. + def on_close + super if defined? super + end + # handles broadcasts / unicasts def on_broadcast data unless data.is_a?(Hash) && (data[:type] || data[:target]) && data[:method] && data[:data] Iodine.warn "Broadcast message unknown... falling back on base broadcasting" return super(data) if defined? super @@ -37,10 +80,30 @@ # return ( self.class.placebo? ? true : we.write(ws.data)) if :method == :to_client return ((data[:type] == :all) ? false : (raise "Broadcasting recieved but no method can handle it - dump:\r\n #{data.to_s}") ) unless self.class.has_super_method?(data[:method]) self.method(data[:method]).call *data[:data] end + # Get's the websocket's unique identifier for unicast transmissions. + # + # This UUID is also used to make sure Radis broadcasts don't triger the + # boadcasting object's event. + def uuid + return @uuid if @uuid + if __get_io + return (@uuid ||= Plezi::Settings.uuid + @io.id) + end + nil + end + alias :unicast_id :uuid + + protected + + # allows writing of data to the websocket (if opened). Otherwise appends the message to the Http response. + def write data + (@ws_io || @response) << data + end + # Performs a websocket unicast to the specified target. def unicast target_uuid, method_name, *args self.class.unicast target_uuid, method_name, *args end @@ -66,24 +129,10 @@ # def multicast method_name, *args self.class._inner_broadcast({ method: method_name, data: args, type: :all}, __get_io ) end - # Get's the websocket's unique identifier for unicast transmissions. - # - # This UUID is also used to make sure Radis broadcasts don't triger the - # boadcasting object's event. - def uuid - return @uuid if @uuid - if __get_io - return (@uuid ||= Plezi::Settings.uuid + @io.id) - end - nil - end - alias :unicast_id :uuid - - protected def __get_io @io ||= (@request ? @request[:io] : nil) end end module ClassMethods @@ -103,11 +152,17 @@ def has_super_method? method_name @super_methods_list ||= self.superclass.instance_methods.to_set @super_methods_list.include? method_name end def has_exposed_method? method_name - @exposed_methods_list ||= ( (self.public_instance_methods - Class.new.instance_methods - Plezi::ControllerMagic::InstanceMethods.instance_methods - [:before, :after, :save, :show, :update, :delete, :initialize, :on_message, :on_broadcast, :pre_connect, :on_open, :on_close]).delete_if {|m| m.to_s[0] == '_'} ).to_set + @reserved_methods_list ||= Class.new.public_instance_methods + + Plezi::Base::WSObject::InstanceMethods.public_instance_methods + + Plezi::Base::WSObject::SuperInstanceMethods.public_instance_methods + + Plezi::ControllerMagic::InstanceMethods.public_instance_methods + + Plezi::Base::ControllerCore::InstanceMethods.public_instance_methods + + [:before, :after, :save, :show, :update, :delete, :initialize] + @exposed_methods_list ||= ( (self.public_instance_methods - @reserved_methods_list ).delete_if {|m| m.to_s[0] == '_'} ).to_set @exposed_methods_list.include? method_name end protected @@ -122,9 +177,11 @@ # a callback that resets the class router whenever a method (a potential route) is undefined (using #undef_method). def method_undefined(id) reset_routing_cache end + end + module SuperInstanceMethods end module SuperClassMethods public