plezi 0.10.13 → 0.10.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +33 -36
- data/bin/plezi +2 -0
- data/lib/plezi/common/api.rb +1 -1
- data/lib/plezi/common/settings.rb +2 -1
- data/lib/plezi/handlers/controller_core.rb +1 -14
- data/lib/plezi/handlers/controller_magic.rb +3 -3
- data/lib/plezi/handlers/placebo.rb +1 -1
- data/lib/plezi/handlers/ws_object.rb +4 -0
- data/lib/plezi/version.rb +1 -1
- data/plezi.gemspec +1 -1
- data/resources/environment.rb +1 -1
- data/resources/mini_app.rb +3 -1
- data/resources/mini_exec.rb +2 -0
- data/resources/websockets.js +1 -1
- data/resources/welcome_page.html +1 -1
- data/test/plezi_tests.rb +28 -24
- metadata +4 -5
- data/lib/plezi/handlers/placebo old.rb +0 -161
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2487750b4f8cbcb1de42a7bc91e065da2f94c212
|
4
|
+
data.tar.gz: 7f39f9de1020bc8f3d80113b2dc01d7c59c9d706
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c97f85a27d0cce6a6d1df74e31ed9c8fef44377cfb9f0646d097f8917d80137dcddbe951631b2ab2126827595ad9028b53c01ffa3e1d3e1662440c710754ceb3
|
7
|
+
data.tar.gz: 79c93625fcc681835f0db3c87919fa4e4a906a4f4747c42ef3093155ac02489e3d834b2307c1b621a9a5cff43ea0481ecdab6f26b18488ef3dd8068d86ee94a4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
#Change Log
|
2
2
|
|
3
|
+
Change log v.0.10.14
|
4
|
+
|
5
|
+
**Deprecation notice**: Setting the public root folder is now done using the option `public` instead of the option `root`.
|
6
|
+
|
7
|
+
**Fix**: Yard documentation failed due to duplicate entries. The issue was fixed.
|
8
|
+
|
9
|
+
**Update**: removed duplicate code and updated the server for better Rack support.
|
10
|
+
|
11
|
+
***
|
12
|
+
|
3
13
|
Change log v.0.10.13
|
4
14
|
|
5
15
|
**Fix**: The Placebo API was tested and an issue with the new Placebo class broadcast method was fixed.
|
data/README.md
CHANGED
@@ -12,7 +12,7 @@ With Plezi, you can easily:
|
|
12
12
|
|
13
13
|
3. Create a full fledged Ruby web application, taking full advantage of RESTful routing, HTTP streaming and scalable Websocket features.
|
14
14
|
|
15
|
-
Plezi leverages [GRHttp server](https://github.com/boazsegev/GRHttp)
|
15
|
+
Plezi leverages [GRHttp server's](https://github.com/boazsegev/GRHttp) new architecture. GRHttp is a pure Ruby HTTP and Websocket Generic Server built using [GReactor](https://github.com/boazsegev/GReactor) - a multi-threaded pure ruby alternative to EventMachine with basic process forking support (enjoy forking, if your code is scaling ready).
|
16
16
|
|
17
17
|
## Installation
|
18
18
|
|
@@ -117,20 +117,27 @@ Remember to connect to the service from at least two browser windows - to truly
|
|
117
117
|
|
118
118
|
method names starting with an underscore ('_') will NOT be made public by the router: so while both '/hello' and '/humans.txt' are public ( [try it](http://localhost:3000/humans.txt) ), '/_send_message' will return a 404 not found error ( [try it](http://localhost:3000/_send_message) ).
|
119
119
|
|
120
|
-
##
|
120
|
+
## Adding Websockets to your existing Rails/Sinatra/Rack application
|
121
121
|
|
122
|
-
You already have an amazing WebApp, but now you want to add websocket broadcasting and unicasting support - Plezi makes
|
122
|
+
You already have an amazing WebApp, but now you want to add websocket broadcasting and unicasting support - Plezi makes connecting your existing WebApp with your Plezi Websocket backend as easy as it gets.
|
123
123
|
|
124
124
|
|
125
|
-
There are two easy ways to
|
125
|
+
There are two easy ways to add Plezi websockets to your existing WebApp, depending on your needs and preferences:
|
126
126
|
|
127
|
-
1.
|
127
|
+
1. **The super easy way - a Hybrid app**:
|
128
128
|
|
129
|
-
|
129
|
+
Plezi plays well with others, so you can add Plezi to your existing framework and let it catch any incoming websocket connections. Your application will still handle anything you didn't ask Plezi to handle (Plezi Websockets and routes will recieve priority, so your app can keep handling the 404 response).
|
130
130
|
|
131
|
-
### The super easy augmentation - run together
|
132
131
|
|
133
|
-
The
|
132
|
+
2. **The Placebo API**:
|
133
|
+
|
134
|
+
Plezi has a Placebo API, allowing you to add Plezi features without running a Plezi app.
|
135
|
+
|
136
|
+
By adding the Plezi Placebo to your app, you can easily communicate between your existing app and a remote Plezi process/server. So, although websocket connections are made to a different server, your app can still send and recieve data through the websocket connection (using Redis).
|
137
|
+
|
138
|
+
### The super easy way - a Hybrid app
|
139
|
+
|
140
|
+
The easiest way to add Plezi websockets to your existing application is to use [GRHttp's](https://github.com/boazsegev/GRHttp) Rack adapter to run your Rack app, while Plezi will use GRHttp's native features (such as Websockets and HTTP streaming).
|
134
141
|
|
135
142
|
You can eaither use your existing Plezi application or create a new mini plezi application inside your existing app folder using:
|
136
143
|
|
@@ -145,22 +152,21 @@ Plezi.start_rack
|
|
145
152
|
|
146
153
|
That's it! Now you can use the Plezi API and your existing application's API at the same time and they are both running on the same server.
|
147
154
|
|
148
|
-
Plezi's
|
155
|
+
Plezi's routes will be attempted first, so that your app can keep handling the 404 (not found) error page.
|
149
156
|
|
150
|
-
|
157
|
+
### The Plezi Placebo API - talking from afar
|
151
158
|
|
152
|
-
|
159
|
+
To use Plezi and your App on different processes, without mixing them together, simply include the Plezi App in your existing app and call `Plezi.start_placebo` - now you can access all the websocket API that you want from your existing WebApp, but Plezi will not interfere with your WebApp in any way.
|
153
160
|
|
154
|
-
|
155
|
-
|
156
|
-
For instance, add the following code to your environment on a Rails or Sinatra app:
|
161
|
+
For instance, add the following code to your environment setup on a Rails or Sinatra app:
|
157
162
|
|
158
163
|
```ruby
|
159
164
|
|
160
165
|
require './my_plezi_app/environment.rb'
|
161
166
|
require './my_plezi_app/routes.rb'
|
162
167
|
|
163
|
-
|
168
|
+
# # Make sure the following is already in your 'my_plezi_app/environment.rb' file:
|
169
|
+
# ENV['PL_REDIS_URL'] = "redis://username:password@my.host:6379"
|
164
170
|
|
165
171
|
Plezi.start_placebo
|
166
172
|
```
|
@@ -172,7 +178,7 @@ Plezi will automatically set up the Redis connections and pub/sub to connect you
|
|
172
178
|
Now you can use Plezi from withing your existing App's code. For example, if your Plezi app has a controller named `ClientPleziCtrl`, you might use:
|
173
179
|
|
174
180
|
```ruby
|
175
|
-
|
181
|
+
# Demo a Rails Controller:
|
176
182
|
class ClientsController < ApplicationController
|
177
183
|
def update
|
178
184
|
#... your original logic here
|
@@ -199,23 +205,20 @@ Oh, that's easy too.
|
|
199
205
|
|
200
206
|
With a few more lines of code, we can have the websocket connections _broadcast_ back to us using the `Plezi::Placebo` API.
|
201
207
|
|
202
|
-
|
208
|
+
In your Rails app, add the logic:
|
203
209
|
|
204
210
|
```ruby
|
205
|
-
|
206
211
|
class MyReciever
|
207
212
|
def my_reciever_method arg1, arg2, arg3, arg4...
|
208
213
|
# your app's logic
|
209
214
|
end
|
210
215
|
end
|
211
|
-
|
212
216
|
Plezi::Placebo.new MyReciever
|
213
|
-
|
214
217
|
```
|
215
218
|
|
216
219
|
Plezi will now take your class and add mimick an IO connection (the Placebo connection) on it's GRHttp serever. This Placebo connection will answer the Redis broadcasts just as if your class was a websocket controller...
|
217
220
|
|
218
|
-
On the Plezi side, use multicasting, from ANY controller:
|
221
|
+
On the Plezi side, use multicasting or unicasting (but not broadcasting), from ANY controller:
|
219
222
|
|
220
223
|
```ruby
|
221
224
|
|
@@ -227,39 +230,33 @@ class ClientPleziCtrl
|
|
227
230
|
end
|
228
231
|
```
|
229
232
|
|
230
|
-
That's it! Now you have your listening object... but
|
233
|
+
That's it! Now you have your listening object... but be aware - to safely scale up this communication you might consider using unicasting instead of broadcasting.
|
234
|
+
|
235
|
+
We recommend saving the uuid of the Rails process to a Redis key and picking it up from there.
|
231
236
|
|
232
237
|
On your Rails app, add:
|
233
238
|
|
234
239
|
```ruby
|
235
240
|
#...
|
236
241
|
class MyReciever
|
237
|
-
def get_controller sender
|
238
|
-
ClientPleziCtrl.unicast sender, :_set_controller_uuid, uuid
|
239
|
-
end
|
240
242
|
def my_reciever_method arg1, arg2, arg3, arg4...
|
241
243
|
# ...
|
242
244
|
end
|
243
245
|
end
|
244
246
|
|
245
|
-
Plezi::Placebo.new MyReciever
|
247
|
+
pl = Plezi::Placebo.new MyReciever
|
248
|
+
|
249
|
+
Plezi.redis_connection.set 'MainUUIDs', pl.uuid
|
246
250
|
|
247
251
|
```
|
248
|
-
|
252
|
+
In your Plezi app, use unicasting when possible:
|
249
253
|
|
250
254
|
```ruby
|
251
255
|
class ClientPleziCtrl
|
252
|
-
def on_open
|
253
|
-
multicast :get_controller, uuid
|
254
|
-
end
|
255
256
|
def on_message data
|
256
257
|
# app logic here
|
257
|
-
|
258
|
-
|
259
|
-
def _controller_uuid controller_uuid
|
260
|
-
@main_controller = controller_uuid
|
261
|
-
# send ready flag to client using JSON?
|
262
|
-
response << "{\"state\":\"ready\""
|
258
|
+
main_uuid = Plezi.redis_connection.get 'MainUUIDs'
|
259
|
+
unicast main_uuid, :my_reciever_method, arg1, arg2, arg3, arg4... if main_uuid
|
263
260
|
end
|
264
261
|
end
|
265
262
|
|
data/bin/plezi
CHANGED
@@ -49,6 +49,8 @@ class AppTemplate
|
|
49
49
|
app_tree["Gemfile"] ||= ''
|
50
50
|
app_tree["Gemfile"] << "source 'https://rubygems.org'\n\n####################\n# core gems\n\n# include the basic plezi framework and server\ngem 'plezi', '~> #{Plezi::VERSION}'\n"
|
51
51
|
app_tree["Gemfile"] << "\n\n\nruby '#{RUBY_VERSION}'\n"
|
52
|
+
app_tree["404.html.erb"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"404.erb"), __FILE__))
|
53
|
+
app_tree["500.html.erb"] ||= IO.read(::File.expand_path(File.join("..", "..", "resources" ,"500.erb"), __FILE__))
|
52
54
|
finalize
|
53
55
|
end
|
54
56
|
|
data/lib/plezi/common/api.rb
CHANGED
@@ -32,7 +32,8 @@ module Plezi
|
|
32
32
|
raise "Can't change channel name after Redis subscription had been initiated." if @redis
|
33
33
|
@redis_channel_name = val
|
34
34
|
end
|
35
|
-
#
|
35
|
+
# Returns the Redis Channel Name used by this app.
|
36
|
+
# @return [String]
|
36
37
|
def redis_channel_name
|
37
38
|
@redis_channel_name ||= 'Plezi_Redis_Channel'
|
38
39
|
end
|
@@ -19,7 +19,7 @@ module Plezi
|
|
19
19
|
@host_params = request.io[:params]
|
20
20
|
@response = response
|
21
21
|
@cookies = request.cookies
|
22
|
-
#
|
22
|
+
# # \@response["content-type"] ||= ::Plezi.default_content_type
|
23
23
|
super()
|
24
24
|
end
|
25
25
|
|
@@ -57,19 +57,6 @@ module Plezi
|
|
57
57
|
def on_close ws
|
58
58
|
super() if defined? super
|
59
59
|
end
|
60
|
-
# handles websocket multicasting/broadcasting/unicasting.
|
61
|
-
def on_broadcast ws
|
62
|
-
data = ws.data
|
63
|
-
unless (data[:type] || data[:target]) && data[:method] && data[:data]
|
64
|
-
GReactor.warn "Broadcast message unknown... falling back on base broadcasting"
|
65
|
-
return super(data) if defined? super
|
66
|
-
return false
|
67
|
-
end
|
68
|
-
return false if data[:type] && data[:type] != :all && !self.is_a?(data[:type])
|
69
|
-
# return false if data[:target] && data[:target] != ws.uuid + Plezi::Settings.uuid # already reviewed by the GRHttp
|
70
|
-
return false unless self.class.has_method?(data[:method])
|
71
|
-
self.method(data[:method]).call *data[:data]
|
72
|
-
end
|
73
60
|
|
74
61
|
# Inner Routing
|
75
62
|
#
|
@@ -20,10 +20,10 @@ module Plezi
|
|
20
20
|
end
|
21
21
|
|
22
22
|
module InstanceMethods
|
23
|
-
|
23
|
+
|
24
24
|
public
|
25
25
|
|
26
|
-
# the request object,
|
26
|
+
# the request object, type HTTPRequest.
|
27
27
|
attr_reader :request
|
28
28
|
|
29
29
|
# the :params variable contains all the parameters set by the request (/path?locale=he => params ["locale"] == "he").
|
@@ -97,7 +97,7 @@ module Plezi
|
|
97
97
|
request.base_url + url_for(dest)
|
98
98
|
end
|
99
99
|
|
100
|
-
#
|
100
|
+
# Send raw data to be saved as a file or viewed as an attachment. Browser should believe it had recieved a file.
|
101
101
|
#
|
102
102
|
# this is usful for sending 'attachments' (data to be downloaded) rather then
|
103
103
|
# a regular response.
|
@@ -27,10 +27,10 @@ module Plezi
|
|
27
27
|
#the methods here will be injected to the Placebo controller.
|
28
28
|
module Core
|
29
29
|
def self.included base
|
30
|
+
base.send :include, Plezi::Base::WSObject
|
30
31
|
base.send :include, InstanceMethods
|
31
32
|
base.extend ClassMethods
|
32
33
|
base.superclass.instance_eval {extend SuperClassMethods}
|
33
|
-
base.send :include, Plezi::Base::WSObject
|
34
34
|
end
|
35
35
|
|
36
36
|
#the methods here will be injected to the Placebo controller as Instance methods.
|
@@ -35,6 +35,7 @@ module Plezi
|
|
35
35
|
return false
|
36
36
|
end
|
37
37
|
return false if data[:type] && data[:type] != :all && !self.is_a?(data[:type])
|
38
|
+
# return ( self.class.placebo? ? true : we.write(ws.data)) if :method == :to_client
|
38
39
|
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])
|
39
40
|
self.method(data[:method]).call *data[:data]
|
40
41
|
end
|
@@ -130,6 +131,9 @@ module Plezi
|
|
130
131
|
module SuperClassMethods
|
131
132
|
public
|
132
133
|
|
134
|
+
# answers the question if this is a placebo object.
|
135
|
+
def placebo?; false end
|
136
|
+
|
133
137
|
# WebSockets: fires an event on all of this controller's active websocket connections.
|
134
138
|
#
|
135
139
|
# Class method.
|
data/lib/plezi/version.rb
CHANGED
data/plezi.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "grhttp", "~> 0.0.
|
21
|
+
spec.add_dependency "grhttp", "~> 0.0.17"
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.7"
|
23
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
24
|
|
data/resources/environment.rb
CHANGED
@@ -40,7 +40,7 @@ Dir[File.join "{app}", "**" , "*.rb"].each {|file| load File.expand_path(file)}
|
|
40
40
|
|
41
41
|
# start a web service to listen on the first default port (3000 or the port set by the command-line).
|
42
42
|
# you can change some of the default settings here.
|
43
|
-
listen
|
43
|
+
listen public: Root.join('public').to_s,
|
44
44
|
assets: Root.join('assets').to_s,
|
45
45
|
assets_public: '/assets',
|
46
46
|
templates: Root.join('app','views').to_s,
|
data/resources/mini_app.rb
CHANGED
@@ -9,6 +9,8 @@
|
|
9
9
|
# Dir.chdir Root.to_s
|
10
10
|
## load code from a subfolder called 'code'
|
11
11
|
# Dir[File.join "{code}", "**" , "*.rb"].each {|file| load File.expand_path(file)}
|
12
|
+
## OR load code from all the ruby files in the main forlder (subfolder inclussion will fail on PaaS)
|
13
|
+
# Dir[File.join File.dirname(__FILE__), "*.rb"].each {|file| load File.expand_path(file) unless file == __FILE__}
|
12
14
|
|
13
15
|
## If this app is independant, use bundler to load gems (including the plezi gem).
|
14
16
|
## Else, use the original app's Gemfile and start Plezi's Rack mode.
|
@@ -60,7 +62,7 @@ end
|
|
60
62
|
# start a web service to listen on the first default port (3000 or the port set by the command-line).
|
61
63
|
# you can change some of the default settings here.
|
62
64
|
listen host: :default,
|
63
|
-
#
|
65
|
+
# public: Root.join('public').to_s,
|
64
66
|
# assets: Root.join('assets').to_s,
|
65
67
|
# templates: Root.join('templates').to_s,
|
66
68
|
ssl: false
|
data/resources/mini_exec.rb
CHANGED
data/resources/websockets.js
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
// Your websocket URI should be an absolute path. The following sets the base URI.
|
4
4
|
// remember to update to the specific controller's path to your websocket URI.
|
5
5
|
var ws_controller_path = window.location.pathname; // change to '/controller/path'
|
6
|
-
var ws_uri = (window.location.protocol.match(/https/) ? 'wss' : 'ws') + '://' + window.
|
6
|
+
var ws_uri = (window.location.protocol.match(/https/) ? 'wss' : 'ws') + '://' + window.document.location.host + ws_controller_path
|
7
7
|
// websocket variable.
|
8
8
|
var websocket = NaN
|
9
9
|
// count failed attempts
|
data/resources/welcome_page.html
CHANGED
@@ -177,7 +177,7 @@ input[type=submit]:active
|
|
177
177
|
// Your websocket URI should be an absolute path. The following sets the base URI.
|
178
178
|
// remember to update to the specific controller's path to your websocket URI.
|
179
179
|
var ws_controller_path = '/' // window.location.pathname; // change to '/controller/path'
|
180
|
-
var ws_uri = (window.location.protocol.match(/https/) ? 'wss' : 'ws') + '://' + window.
|
180
|
+
var ws_uri = (window.location.protocol.match(/https/) ? 'wss' : 'ws') + '://' + window.document.location.host + ws_controller_path
|
181
181
|
// websocket variable.
|
182
182
|
var websocket = NaN
|
183
183
|
// count failed attempts
|
data/test/plezi_tests.rb
CHANGED
@@ -312,28 +312,28 @@ module PleziTestTasks
|
|
312
312
|
PL.on_shutdown {puts " * Websocket unicast message test: #{RESULTS[unicast_test]}"}
|
313
313
|
end
|
314
314
|
def test_websocket_sizes
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
315
|
+
should_disconnect = false
|
316
|
+
ws = GRHttp::WSClient.connect_to("ws://localhost:3000/ws/size") do |ws|
|
317
|
+
if should_disconnect
|
318
|
+
puts " * Websocket size disconnection test: #{RESULTS[false]}"
|
319
|
+
else
|
320
|
+
puts " * Websocket message size test: got #{ws.data.bytesize} bytes"
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
ws.on_close do
|
325
|
+
puts " * Websocket size disconnection test: #{RESULTS[should_disconnect]}"
|
326
|
+
end
|
327
|
+
str = 'a'
|
328
|
+
time_now = Time.now
|
329
|
+
7.times {|i| str = str * 2**i;puts " * Websocket message size test: sending #{str.bytesize} bytes"; ws << str; }
|
330
|
+
str.clear
|
331
|
+
to_sleep = (Time.now - time_now)*2 + 1
|
332
|
+
puts "will now sleep for #{to_sleep} seconds, waiting allowing the server to respond"
|
333
|
+
sleep to_sleep rescue true
|
334
|
+
should_disconnect = true
|
335
|
+
Plezi::Settings.ws_message_size_limit = 1024
|
336
|
+
ws << ('0123'*258)
|
337
337
|
end
|
338
338
|
def test_broadcast_stress
|
339
339
|
PlaceboStressTestCtrl.create_listeners
|
@@ -464,11 +464,15 @@ puts " --- Plezi will ran async, performing some tests that than hang"
|
|
464
464
|
|
465
465
|
puts " --- Starting tests"
|
466
466
|
puts " --- Failed tests should read: #{PleziTestTasks::RESULTS[false]}"
|
467
|
-
Plezi.start_async
|
468
|
-
PleziTestTasks.run_tests
|
469
467
|
|
470
468
|
r = Plezi::Placebo.new PlaceboCtrl
|
471
469
|
puts " * Create Placebo test: #{PleziTestTasks::RESULTS[r && true]}"
|
470
|
+
puts " * Placebo admists to being placebo: #{PleziTestTasks::RESULTS[PlaceboCtrl.placebo?]}"
|
471
|
+
puts " * Regular controller answers placebo: #{PleziTestTasks::RESULTS[!PlaceboTestCtrl.placebo?]}"
|
472
|
+
|
473
|
+
|
474
|
+
Plezi.start_async
|
475
|
+
PleziTestTasks.run_tests
|
472
476
|
|
473
477
|
# ENV['PL_REDIS_URL'] ||= ENV['REDIS_URL'] || ENV['REDISCLOUD_URL'] || ENV['REDISTOGO_URL'] || "redis://test:1234@pub-redis-11008.us-east-1-4.5.ec2.garantiadata.com:11008"
|
474
478
|
# # GReactor::Settings.set_forking 4
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plezi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: grhttp
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0.
|
19
|
+
version: 0.0.17
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.0.
|
26
|
+
version: 0.0.17
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,7 +78,6 @@ files:
|
|
78
78
|
- lib/plezi/handlers/controller_core.rb
|
79
79
|
- lib/plezi/handlers/controller_magic.rb
|
80
80
|
- lib/plezi/handlers/http_router.rb
|
81
|
-
- lib/plezi/handlers/placebo old.rb
|
82
81
|
- lib/plezi/handlers/placebo.rb
|
83
82
|
- lib/plezi/handlers/route.rb
|
84
83
|
- lib/plezi/handlers/stubs.rb
|
@@ -1,161 +0,0 @@
|
|
1
|
-
module Plezi
|
2
|
-
|
3
|
-
# This API wil allows you to listen to Websocket Broadcasts sent to any object and to accept unicasts
|
4
|
-
# even when NOT connected to a websocket.
|
5
|
-
#
|
6
|
-
# Simpley create a class to handle any events and call `Plezi::Placebo.new ClassName` :
|
7
|
-
#
|
8
|
-
# class MyListener
|
9
|
-
# def _my_method_name *args
|
10
|
-
# #logic
|
11
|
-
# end
|
12
|
-
# end
|
13
|
-
#
|
14
|
-
# Plezi::Placebo.new MyListener
|
15
|
-
#
|
16
|
-
# A new instance will be created and that instance will answer any broadcasts, for ALL possible
|
17
|
-
# Plezi controllers, as long as it had a method defined that is capable to handle the broadcast.
|
18
|
-
#
|
19
|
-
# The new instance will also accept unicasts sent to it's unique UUID.
|
20
|
-
#
|
21
|
-
# Returns an instance that is a member of the class passed, after that class was inherited by Plezi and
|
22
|
-
# more methods were injected into it's subclass.
|
23
|
-
module Placebo
|
24
|
-
|
25
|
-
# the base module exposes some of the core functionality, but shouldn't be relied upon as far as it's API goes.
|
26
|
-
module Base
|
27
|
-
#the methods here will be injected to the Placebo controller.
|
28
|
-
module Core
|
29
|
-
def self.included base
|
30
|
-
base.send :include, InstanceMethods
|
31
|
-
base.extend ClassMethods
|
32
|
-
base.superclass.instance_eval {extend SuperClassMethods}
|
33
|
-
end
|
34
|
-
|
35
|
-
#the methods here will be injected to the Placebo controller as Instance methods.
|
36
|
-
module InstanceMethods
|
37
|
-
public
|
38
|
-
attr_accessor :io
|
39
|
-
def initialize io
|
40
|
-
@io = io
|
41
|
-
@io[:websocket_handler] = self
|
42
|
-
super()
|
43
|
-
end
|
44
|
-
# notice of disconnect
|
45
|
-
def on_close
|
46
|
-
return super() if defined? super
|
47
|
-
GR.warn "Placebo #{self.class.superclass.name} disconnected. Ignore if this message appears during shutdown."
|
48
|
-
end
|
49
|
-
|
50
|
-
# handles broadcasts / unicasts
|
51
|
-
def on_broadcast ws
|
52
|
-
data = ws.data
|
53
|
-
unless (data[:type] || data[:target]) && data[:method] && data[:data]
|
54
|
-
GReactor.warn "Broadcast message unknown... falling back on base broadcasting"
|
55
|
-
return super(data) if defined? super
|
56
|
-
return false
|
57
|
-
end
|
58
|
-
return false if data[:type] && data[:type] != :all && !self.is_a?(data[:type])
|
59
|
-
return ((data[:type] == :all) ? false : (raise "Placebo Broadcasting recieved but no method can handle it - dump:\r\n #{data.to_s}") ) unless self.class.has_super_method?(data[:method])
|
60
|
-
self.method(data[:method]).call *data[:data]
|
61
|
-
end
|
62
|
-
# Returns the websocket connection's UUID, used for unicasting.
|
63
|
-
def uuid
|
64
|
-
return (@uuid ||= @response.uuid + Plezi::Settings.uuid) if @response.is_a?(GRHttp::WSEvent)
|
65
|
-
end
|
66
|
-
|
67
|
-
# Performs a websocket unicast to the specified target.
|
68
|
-
def unicast target_uuid, method_name, *args
|
69
|
-
self.class.unicast target_uuid, method_name, *args
|
70
|
-
end
|
71
|
-
# broadcast to a specific controller
|
72
|
-
def broadcast controller_class, method_name, *args
|
73
|
-
GRHttp::Base::WSHandler.broadcast({data: args, type: controller_class, method: method_name}, self)
|
74
|
-
self.class.__send_to_redis data: args, type: controller_class, method: method_name
|
75
|
-
end
|
76
|
-
# multicast to all handlers.
|
77
|
-
def multicast method_name, *args
|
78
|
-
self.class.multicast method_name, *args
|
79
|
-
end
|
80
|
-
end
|
81
|
-
#the methods here will be injected to the Placebo controller as class methods.
|
82
|
-
module ClassMethods
|
83
|
-
public
|
84
|
-
def has_super_method? method_name
|
85
|
-
@super_methods_list ||= self.superclass.instance_methods.to_set
|
86
|
-
@super_methods_list.include? method_name
|
87
|
-
end
|
88
|
-
end
|
89
|
-
module SuperClassMethods
|
90
|
-
# multicast to all handlers.
|
91
|
-
def multicast method_name, *args
|
92
|
-
GRHttp::Base::WSHandler.broadcast({method: method_name, data: args, type: :all}, self)
|
93
|
-
__send_to_redis method: method_name, data: args, type: :all
|
94
|
-
end
|
95
|
-
# Broadcast to all instances (usually one instance) of THIS placebo controller.
|
96
|
-
#
|
97
|
-
# This should be used by the real websocket connections to forward messages to the placebo controller classes.
|
98
|
-
def broadcast method_name, *args
|
99
|
-
@methods_list ||= self.public_instance_methods.to_set
|
100
|
-
raise "No mothod defined to accept this broadcast." unless @methods_list.include? method_name
|
101
|
-
GRHttp::Base::WSHandler.broadcast data: args, type: self, method: method_name
|
102
|
-
__send_to_redis data: args, type: self, method: method_name
|
103
|
-
end
|
104
|
-
# Performs a websocket unicast to the specified target.
|
105
|
-
def unicast target_uuid, method_name, *args
|
106
|
-
GRHttp::Base::WSHandler.unicast target_uuid, data: args, target: target_uuid, method: method_name
|
107
|
-
__send_to_redis data: args, target: target_uuid, method: method_name
|
108
|
-
end
|
109
|
-
protected
|
110
|
-
def __send_to_redis data
|
111
|
-
raise "Wrong method name for websocket broadcasting - expecting type Symbol" unless data[:method].is_a?(Symbol) || data[:method].is_a?(Symbol)
|
112
|
-
conn = Plezi.redis_connection
|
113
|
-
data[:server] = Plezi::Settings.uuid
|
114
|
-
return conn.publish( Plezi::Settings.redis_channel_name, data.to_yaml ) if conn
|
115
|
-
false
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
class PlaceboIO < GReactor::BasicIO
|
120
|
-
def clear?
|
121
|
-
io.closed?
|
122
|
-
end
|
123
|
-
def call
|
124
|
-
self.read
|
125
|
-
GR.warn "Placebo IO recieved IO signal - this is unexpected..."
|
126
|
-
end
|
127
|
-
def on_disconnect
|
128
|
-
@params[:out].close rescue nil
|
129
|
-
@cache[:websocket_handler].on_close if @cache[:websocket_handler]
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
module_function
|
134
|
-
def new placebo_class
|
135
|
-
new_class_name = "PlaceboPlezi__#{placebo_class.name.gsub /[\:\-\#\<\>\{\}\(\)\s]/, '_'}"
|
136
|
-
new_class = nil
|
137
|
-
new_class = Module.const_get new_class_name if Module.const_defined? new_class_name
|
138
|
-
unless new_class
|
139
|
-
new_class = Class.new(placebo_class) do
|
140
|
-
include Placebo::Base::Core
|
141
|
-
end
|
142
|
-
Object.const_set(new_class_name, new_class)
|
143
|
-
end
|
144
|
-
i, o = IO.pipe
|
145
|
-
io = Placebo::Base::PlaceboIO.new i, out: o
|
146
|
-
io = GReactor.add_raw_io i, io
|
147
|
-
new_class.new(io)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
|
153
|
-
# class A
|
154
|
-
# def _hi
|
155
|
-
# 'hi'
|
156
|
-
# end
|
157
|
-
# end
|
158
|
-
# Plezi::Placebo.new A
|
159
|
-
# a = nil
|
160
|
-
# GReactor.each {|h| a= h}
|
161
|
-
# a[:websocket_handler].on_broadcast GRHttp::WSEvent.new(nil, type: true, data: [], method: :_hi)
|