plezi 0.14.4 → 0.14.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,176 +1,191 @@
1
- require 'json'
2
1
  module Plezi
3
- module Controller
4
- module ClassMethods
5
- # A Ruby callback used to initialize class data for new Controllers.
6
- def self.extended(base)
7
- base._pl_init_class_data
8
- end
9
-
10
- # Returns a relative URL for the controller, placing the requested parameters in the URL (inline, where possible and as query data when not possible).
11
- def url_for(func, params = {})
12
- ::Plezi::Base::Router.url_for self, func, params
13
- end
14
-
15
- # Invokes a method on the `target` websocket connection. When using Iodine, the method is invoked asynchronously.
16
- #
17
- # self.unicast target, :my_method, "argument 1"
18
- #
19
- # Methods invoked using {unicast}, {broadcast} or {multicast} will quitely fail if the connection was lost, the requested method is undefined or the 'target' was invalid.
20
- def unicast(target, event_method, *args)
21
- ::Plezi::Base::MessageDispatch.unicast(self, target, event_method, args)
22
- end
23
-
24
- # Invokes a method on every websocket connection that belongs to this Controller / Type. When using Iodine, the method is invoked asynchronously.
25
- #
26
- # self.broadcast :my_method, "argument 1", "argument 2", 3
27
- #
28
- # Methods invoked using {unicast}, {broadcast} or {multicast} will quitely fail if the connection was lost, the requested method is undefined or the 'target' was invalid.
29
- def broadcast(event_method, *args)
30
- ::Plezi::Base::MessageDispatch.broadcast(self, event_method, args)
31
- end
32
-
33
- # Invokes a method on every websocket connection in the application.
34
- #
35
- # self.multicast :my_method, "argument 1", "argument 2", 3
36
- #
37
- # Methods invoked using {unicast}, {broadcast} or {multicast} will quitely fail if the connection was lost, the requested method is undefined or the 'target' was invalid.
38
- def multicast(event_method, *args)
39
- ::Plezi::Base::MessageDispatch.multicast(self, event_method, args)
40
- end
41
-
42
- # @private
43
- # This is used internally by Plezi, do not use.
44
- RESERVED_METHODS = [:delete, :create, :update, :new, :show, :pre_connect, :on_open, :on_close, :on_shutdown, :on_message].freeze
45
- # @private
46
- # This function is used internally by Plezi, do not call.
47
- def _pl_get_map
48
- return @_pl_get_map if @_pl_get_map
49
-
50
- @_pl_get_map = {}
51
- mths = public_instance_methods false
52
- mths.delete_if { |m| m.to_s[0] == '_' || !(-1..0).cover?(instance_method(m).arity) }
53
- @_pl_get_map[nil] = :index if mths.include?(:index)
54
- RESERVED_METHODS.each { |m| mths.delete m }
55
- mths.each { |m| @_pl_get_map[m.to_s.freeze] = m }
56
-
57
- @_pl_get_map
58
- end
59
-
60
- # @private
61
- # This function is used internally by Plezi, do not call.
62
- def _pl_has_delete
63
- @_pl_has_delete
64
- end
65
-
66
- # @private
67
- # This function is used internally by Plezi, do not call.
68
- def _pl_has_update
69
- @_pl_has_update
70
- end
71
-
72
- # @private
73
- # This function is used internally by Plezi, do not call.
74
- def _pl_has_create
75
- @_pl_has_create
76
- end
77
-
78
- # @private
79
- # This function is used internally by Plezi, do not call.
80
- def _pl_has_new
81
- @_pl_has_new
82
- end
83
-
84
- # @private
85
- # This function is used internally by Plezi, do not call.
86
- def _pl_has_show
87
- @_pl_has_show
88
- end
89
-
90
- # @private
91
- # This function is used internally by Plezi, do not call.
92
- def _pl_is_websocket?
93
- @_pl_is_websocket
94
- end
95
-
96
- # @private
97
- # This function is used internally by Plezi, do not call.
98
- def _pl_is_ad?
99
- @auto_dispatch
100
- end
101
-
102
- # @private
103
- # This function is used internally by Plezi, do not call.
104
- def _pl_ws_map
105
- return @_pl_ws_map if @_pl_ws_map
106
-
107
- @_pl_ws_map = {}
108
- mths = instance_methods false
109
- mths.delete :index
110
- RESERVED_METHODS.each { |m| mths.delete m }
111
- mths.each { |m| @_pl_ws_map[m.to_s.freeze] = m; @_pl_ws_map[m] = m }
112
-
113
- @_pl_ws_map
114
- end
115
-
116
- # @private
117
- # This function is used internally by Plezi, do not call.
118
- def _pl_ad_map
119
- return @_pl_ad_map if @_pl_ad_map
120
-
121
- @_pl_ad_map = {}
122
- mths = public_instance_methods false
123
- mths.delete_if { |m| m.to_s[0] == '_' || ![-2, -1, 1].freeze.include?(instance_method(m).arity) }
124
- mths.delete :index
125
- RESERVED_METHODS.each { |m| mths.delete m }
126
- mths.each { |m| @_pl_ad_map[m.to_s.freeze] = m; @_pl_ad_map[m] = m }
127
-
128
- @_pl_ad_map
129
- end
130
-
131
- # @private
132
- # This function is used internally by Plezi, do not call.
133
- def _pl_params2method(params, env)
134
- par_id = params['id'.freeze]
135
- meth_id = _pl_get_map[par_id]
136
- return meth_id if par_id && meth_id
137
- # puts "matching against #{params}"
138
- case params['_method'.freeze]
139
- when :get # since this is common, it's pushed upwards.
140
- if env['HTTP_UPGRADE'.freeze] && _pl_is_websocket? && env['HTTP_UPGRADE'.freeze].downcase.start_with?('websocket'.freeze)
141
- @_pl_init_global_data ||= ::Plezi.plezi_initialize # wake up pub/sub drivers in case of `fork`
142
- return :preform_upgrade
143
- end
144
- return :new if _pl_has_new && par_id == 'new'.freeze
145
- return meth_id || (_pl_has_show && :show) || nil
146
- when :put, :patch
147
- return :create if _pl_has_create && (par_id.nil? || par_id == 'new'.freeze)
148
- return :update if _pl_has_update
149
- when :post
150
- return :create if _pl_has_create
151
- when :delete
152
- return :delete if _pl_has_delete
153
- end
154
- meth_id || (_pl_has_show && :show) || nil
155
- end
156
-
157
- # @private
158
- # This function is used internally by Plezi, do not call.
159
- def _pl_init_class_data
160
- @auto_dispatch ||= nil
161
- @_pl_get_map = nil
162
- @_pl_ad_map = nil
163
- @_pl_ws_map = nil
164
- @_pl_has_show = public_instance_methods(false).include?(:show)
165
- @_pl_has_new = public_instance_methods(false).include?(:new)
166
- @_pl_has_create = public_instance_methods(false).include?(:create)
167
- @_pl_has_update = public_instance_methods(false).include?(:update)
168
- @_pl_has_delete = public_instance_methods(false).include?(:delete)
169
- @_pl_is_websocket = (instance_variable_defined?(:@auto_dispatch) && instance_variable_get(:@auto_dispatch)) || instance_methods(false).include?(:on_message)
170
- _pl_get_map
171
- _pl_ad_map
172
- _pl_ws_map
173
- end
174
- end
175
- end
2
+ module Controller
3
+ # this module extends the controller class with Plezi functions
4
+ module ClassMethods
5
+ # A Ruby callback used to initialize class data for new Controllers.
6
+ def self.extended(base)
7
+ base._pl_init_class_data
8
+ end
9
+
10
+ # Returns a relative URL for the controller, placing the requested parameters in the URL (inline, where possible and as query data when not possible).
11
+ def url_for(func, params = {})
12
+ ::Plezi::Base::Router.url_for self, func, params
13
+ end
14
+
15
+ # Invokes a method on the `target` websocket connection. When using Iodine, the method is invoked asynchronously.
16
+ #
17
+ # self.unicast target, :my_method, "argument 1"
18
+ #
19
+ # Methods invoked using {unicast}, {broadcast} or {multicast} will quitely fail if the connection was lost, the requested method is undefined or the 'target' was invalid.
20
+ def unicast(target, event_method, *args)
21
+ ::Plezi::Base::MessageDispatch.unicast(self, target, event_method, args)
22
+ end
23
+
24
+ # Invokes a method on every websocket connection that belongs to this Controller / Type. When using Iodine, the method is invoked asynchronously.
25
+ #
26
+ # self.broadcast :my_method, "argument 1", "argument 2", 3
27
+ #
28
+ # Methods invoked using {unicast}, {broadcast} or {multicast} will quitely fail if the connection was lost, the requested method is undefined or the 'target' was invalid.
29
+ def broadcast(event_method, *args)
30
+ ::Plezi::Base::MessageDispatch.broadcast(self, event_method, args)
31
+ end
32
+
33
+ # Invokes a method on every websocket connection in the application.
34
+ #
35
+ # self.multicast :my_method, "argument 1", "argument 2", 3
36
+ #
37
+ # Methods invoked using {unicast}, {broadcast} or {multicast} will quitely fail if the connection was lost, the requested method is undefined or the 'target' was invalid.
38
+ def multicast(event_method, *args)
39
+ ::Plezi::Base::MessageDispatch.multicast(self, event_method, args)
40
+ end
41
+ # Writes a message to every client websocket connection in all controllers(!). Accepts an optional filter method using a location reference for a *static* (Class/Module/global) method. The filter method will be passerd the websocket object and it should return `true` / `false`.
42
+ #
43
+ # self.write2everyone {event: "global", message: "This will be sent to everyone"}.to_json
44
+ # # or, we can define a filter method somewhere in our code
45
+ # module Filter
46
+ # def self.should_send? ws
47
+ # true
48
+ # end
49
+ # end
50
+ # # and we can use this filter method.
51
+ # data = {event: "global", message: "This will be sent to everyone"}.to_json
52
+ # self.write2everyone data, ::Filter, :should_send?
53
+ #
54
+ # It's important that the filter method is defined statically in our code and isn't dynamically allocated. Otherwise, scaling the application would be impossible.
55
+ def write2everyone(data, filter_owner = nil, filter_name = nil)
56
+ ::Plezi::Base::MessageDispatch.write2everyone(self, data, filter_owner, filter_name)
57
+ end
58
+
59
+ # @private
60
+ # This is used internally by Plezi, do not use.
61
+ RESERVED_METHODS = [:delete, :create, :update, :new, :show, :pre_connect, :on_open, :on_close, :on_shutdown, :on_message].freeze
62
+ # @private
63
+ # This function is used internally by Plezi, do not call.
64
+ def _pl_get_map
65
+ return @_pl_get_map if @_pl_get_map
66
+
67
+ @_pl_get_map = {}
68
+ mths = public_instance_methods false
69
+ mths.delete_if { |mthd| mthd.to_s[0] == '_' || !(-1..0).cover?(instance_method(mthd).arity) }
70
+ @_pl_get_map[nil] = :index if mths.include?(:index)
71
+ RESERVED_METHODS.each { |mthd| mths.delete mthd }
72
+ mths.each { |mthd| @_pl_get_map[mthd.to_s.freeze] = mthd }
73
+
74
+ @_pl_get_map
75
+ end
76
+
77
+ # @private
78
+ # This function is used internally by Plezi, do not call.
79
+ def _pl_has_delete
80
+ @_pl_has_delete
81
+ end
82
+
83
+ # @private
84
+ # This function is used internally by Plezi, do not call.
85
+ def _pl_has_update
86
+ @_pl_has_update
87
+ end
88
+
89
+ # @private
90
+ # This function is used internally by Plezi, do not call.
91
+ def _pl_has_create
92
+ @_pl_has_create
93
+ end
94
+
95
+ # @private
96
+ # This function is used internally by Plezi, do not call.
97
+ def _pl_has_new
98
+ @_pl_has_new
99
+ end
100
+
101
+ # @private
102
+ # This function is used internally by Plezi, do not call.
103
+ def _pl_has_show
104
+ @_pl_has_show
105
+ end
106
+
107
+ # @private
108
+ # This function is used internally by Plezi, do not call.
109
+ def _pl_is_websocket?
110
+ @_pl_is_websocket
111
+ end
112
+
113
+ # @private
114
+ # This function is used internally by Plezi, do not call.
115
+ def _pl_is_ad?
116
+ @auto_dispatch
117
+ end
118
+
119
+ # @private
120
+ # This function is used internally by Plezi, do not call.
121
+ def _pl_ws_map
122
+ return @_pl_ws_map if @_pl_ws_map
123
+
124
+ @_pl_ws_map = {}
125
+ mths = instance_methods false
126
+ mths.delete :index
127
+ RESERVED_METHODS.each { |mthd| mths.delete mthd }
128
+ mths.each { |mthd| @_pl_ws_map[mthd.to_s.freeze] = mthd; @_pl_ws_map[mthd] = mthd }
129
+
130
+ @_pl_ws_map
131
+ end
132
+
133
+ # @private
134
+ # This function is used internally by Plezi, do not call.
135
+ def _pl_ad_map
136
+ return @_pl_ad_map if @_pl_ad_map
137
+
138
+ @_pl_ad_map = {}
139
+ mths = public_instance_methods false
140
+ mths.delete_if { |m| m.to_s[0] == '_' || ![-2, -1, 1].freeze.include?(instance_method(m).arity) }
141
+ mths.delete :index
142
+ RESERVED_METHODS.each { |m| mths.delete m }
143
+ mths.each { |m| @_pl_ad_map[m.to_s.freeze] = m; @_pl_ad_map[m] = m }
144
+
145
+ @_pl_ad_map
146
+ end
147
+
148
+ # @private
149
+ # This function is used internally by Plezi, do not call.
150
+ def _pl_params2method(params, env)
151
+ par_id = params['id'.freeze]
152
+ meth_id = _pl_get_map[par_id]
153
+ return meth_id if par_id && meth_id
154
+ # puts "matching against #{params}"
155
+ case params['_method'.freeze]
156
+ when :get # since this is common, it's pushed upwards.
157
+ if env['HTTP_UPGRADE'.freeze] && _pl_is_websocket? && env['HTTP_UPGRADE'.freeze].downcase.start_with?('websocket'.freeze)
158
+ @_pl_init_global_data ||= ::Plezi.plezi_initialize # wake up pub/sub drivers in case of `fork`
159
+ return :preform_upgrade
160
+ end
161
+ return :new if _pl_has_new && par_id == 'new'.freeze
162
+ return meth_id || (_pl_has_show && :show) || nil
163
+ when :put, :patch
164
+ return :create if _pl_has_create && (par_id.nil? || par_id == 'new'.freeze)
165
+ return :update if _pl_has_update
166
+ when :post
167
+ return :create if _pl_has_create
168
+ when :delete
169
+ return :delete if _pl_has_delete
170
+ end
171
+ meth_id || (_pl_has_show && :show) || nil
172
+ end
173
+
174
+ # @private
175
+ # This function is used internally by Plezi, do not call.
176
+ def _pl_init_class_data
177
+ @auto_dispatch ||= nil
178
+ @_pl_get_map = @_pl_ad_map = @_pl_ws_map = nil
179
+ @_pl_has_show = public_instance_methods(false).include?(:show)
180
+ @_pl_has_new = public_instance_methods(false).include?(:new)
181
+ @_pl_has_create = public_instance_methods(false).include?(:create)
182
+ @_pl_has_update = public_instance_methods(false).include?(:update)
183
+ @_pl_has_delete = public_instance_methods(false).include?(:delete)
184
+ @_pl_is_websocket = (instance_variable_defined?(:@auto_dispatch) && instance_variable_get(:@auto_dispatch)) || instance_methods(false).include?(:on_message)
185
+ _pl_get_map
186
+ _pl_ad_map
187
+ _pl_ws_map
188
+ end
189
+ end
190
+ end
176
191
  end
@@ -1,54 +1,56 @@
1
1
  module Plezi
2
- module Controller
3
- # The cookie jar class. Controllers have an instance of this class named `cookies`.
4
- class Cookies < Hash
5
- attr_reader :request, :response
6
- def initialize(request, response)
7
- @request = request
8
- @response = response
2
+ module Controller
3
+ # The cookie jar class. Controllers have an instance of this class named `cookies`.
4
+ class Cookies < Hash
5
+ attr_reader :request, :response
6
+ def initialize(request, response)
7
+ @request = request
8
+ @response = response
9
+ end
10
+
11
+ # Reads a cookie from either the request cookie Hash or the new cookies Hash.
12
+ def[](key)
13
+ if key.is_a? Symbol
14
+ super(key) || super(key.to_s) || @request.cookies[key] || @request.cookies[key.to_s]
15
+ elsif key.is_a? String
16
+ super(key) || super(key.to_sym) || @request.cookies[key] || @request.cookies[key.to_sym]
17
+ else
18
+ super(key) || @request.cookies[key]
19
+ end
20
+ end
21
+
22
+ # Sets (or deletes) a cookie. New cookies are placed in the new cookie Hash and are accessible only to the controller that created them.
23
+ def[]=(key, value)
24
+ if value.nil?
25
+ @response.delete_cookie key
26
+ delete key
27
+ if key.is_a? Symbol
28
+ delete key.to_s
29
+ elsif key.is_a? String
30
+ delete key.to_sym
31
+ end
32
+ return nil
33
+ end
34
+ @response.set_cookie key, value
35
+ value = value[:value] if value.is_a? Hash
36
+ super
37
+ end
38
+ end
39
+ # Writes a line dlimited string of all the existing and the new cookies. i.e.:
40
+ # name1=value1
41
+ # name2=value2
42
+ def to_s
43
+ (@request ? (to_a + request.cookies.to_a) : to_a).map! { |pair| pair.join('=') } .join "\n"
9
44
  end
10
45
 
11
- # Reads a cookie from either the request cookie Hash or the new cookies Hash.
12
- def[](key)
13
- if key.is_a? Symbol
14
- super(key) || super(key.to_s) || @request.cookies[key] || @request.cookies[key.to_s]
15
- elsif key.is_a? String
16
- super(key) || super(key.to_sym) || @request.cookies[key] || @request.cookies[key.to_sym]
17
- else
18
- super(key) || @request.cookies[key]
19
- end
46
+ # Returns an array with all the keys of any available cookies (both existing and new cookies).
47
+ def keys
48
+ (@request ? (super + request.cookies.keys) : super)
20
49
  end
21
50
 
22
- # Sets (or deletes) a cookie. New cookies are placed in the new cookie Hash and are accessible only to the controller that created them.
23
- def[]=(key, value)
24
- if value.nil?
25
- @response.delete_cookie key
26
- delete key
27
- if key.is_a? Symbol
28
- delete key.to_s
29
- elsif key.is_a? String
30
- delete key.to_sym
31
- end
32
- return nil
33
- end
34
- @response.set_cookie key, value
35
- value = value[:value] if value.is_a? Hash
36
- super
51
+ # Returns an array with all the values of any available cookies (both existing and new cookies).
52
+ def values
53
+ (@request ? (super + request.cookies.values) : super)
37
54
  end
38
- end
39
- # Writes a line dlimited string of all the existing and the new cookies. i.e.:
40
- # name1=value1
41
- # name2=value2
42
- def to_s
43
- (@request ? (self.to_a + request.cookies.to_a) : self.to_a).map! {|pair| pair.join('=') } .join ("\n")
44
- end
45
- # Returns an array with all the keys of any available cookies (both existing and new cookies).
46
- def keys
47
- (@request ? (super + request.cookies.keys) : super)
48
- end
49
- # Returns an array with all the values of any available cookies (both existing and new cookies).
50
- def values
51
- (@request ? (super + request.cookies.values) : super)
52
- end
53
- end
55
+ end
54
56
  end