plezi 0.12.18 → 0.12.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/bin/plezi +0 -1
- data/lib/plezi/common/api.rb +5 -0
- data/lib/plezi/handlers/controller_core.rb +15 -4
- data/lib/plezi/handlers/ws_object.rb +7 -0
- data/lib/plezi/version.rb +1 -1
- data/plezi.gemspec +1 -1
- data/resources/plezi_client.js +87 -61
- data/test/dispatch +10 -8
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f3d155857b95dc2f0f7a16994780b14ac4cdf1a
|
4
|
+
data.tar.gz: e7a44459df52631f7893c15338da94b4f1e464c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c502627effcdaf0b6e4478122349236524f095f76184c0691f3902ac96a52c7d0afe4027e096a69e3ed34f8b1c31fe893cee7fddf8ab50aea2ec21070649b410
|
7
|
+
data.tar.gz: daafec0faebb5c8eeecd8be08b47ea15f13935c2c0a1be902cccaebeb0dbf4fb1642174bf9f65ebb6ec74ca15f1ee1a026524202904053779fff279d774e37c4
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
|
3
3
|
***
|
4
4
|
|
5
|
+
Change log v.0.12.19
|
6
|
+
|
7
|
+
**Updates**: Auto-Dispatch updates:
|
8
|
+
|
9
|
+
* Updated the Auto-Dispatch API conventions, so that the client and the server conventions are the same (both map events to methods with the same name (without the `on` prefix) and map unknown events to the `unknown` callback).
|
10
|
+
|
11
|
+
* Auto-Dispatch callbacks can return a Hash as well as a String when the return value is meant to be written to the websockets.
|
12
|
+
|
13
|
+
* Auto-Dispatch sends an `_ack_` event whenever an event contains an event ID (`_EID_`) property.
|
14
|
+
|
15
|
+
* Auto-Dispatch client's `emit` supports timeout callbacks (for easier fallback to AJAX).
|
16
|
+
|
17
|
+
* A `:client` route allows serving Auto-Dispatch's updated client rather than the original client provided in the template. This allows the application to serve the updated client when Plezi is updated.
|
18
|
+
|
19
|
+
***
|
20
|
+
|
5
21
|
Change log v.0.12.18
|
6
22
|
|
7
23
|
**Feature**: Auto-dispatching allows, when enabled, to automatically map JSON websocket messages to controller methods, according to their `event` property. Also, when using the auto-dispatch, Plezi will automatically send the returned value for dispatch methods that return a String (just like when using Http). This means that unifying Websocket and RESTful APIs is now easier than ever.
|
data/bin/plezi
CHANGED
@@ -50,7 +50,6 @@ end
|
|
50
50
|
if ARGV[0] == 'new' || ARGV[0] == 'n' || ARGV[0] == "force" || ARGV[0] == 'mini' || ARGV[0] == 'm'
|
51
51
|
#########
|
52
52
|
## set up building environment
|
53
|
-
NO_PLEZI_AUTO_START = true
|
54
53
|
ARGV[1] = ARGV[1].gsub /[^a-zA-Z0-9]/, '_'
|
55
54
|
if Dir.exists?(ARGV[1]) && ARGV[0] != "force"
|
56
55
|
puts ""
|
data/lib/plezi/common/api.rb
CHANGED
@@ -13,6 +13,11 @@ module Plezi
|
|
13
13
|
|
14
14
|
# adds a route to the last server created
|
15
15
|
def route(path, controller = nil, &block)
|
16
|
+
if controller == :client
|
17
|
+
client_path = File.expand_path(File.join('..','..','..','..','resources','plezi_client.js'), __FILE__)
|
18
|
+
controller = nil
|
19
|
+
block = Proc.new { Plezi.cache_needs_update?(client_path) ? Plezi.reload_file(client_path) : Plezi.load_file(client_path) }
|
20
|
+
end
|
16
21
|
::Plezi::Base::HTTPRouter.add_route path, controller, &block
|
17
22
|
end
|
18
23
|
|
@@ -56,6 +56,7 @@ module Plezi
|
|
56
56
|
end
|
57
57
|
begin
|
58
58
|
data = JSON.parse data
|
59
|
+
return close unless data.is_a?(Hash)
|
59
60
|
rescue
|
60
61
|
return close
|
61
62
|
end
|
@@ -64,12 +65,22 @@ module Plezi
|
|
64
65
|
Plezi::Base::WSObject::SuperInstanceMethods.instance_methods +
|
65
66
|
Plezi::ControllerMagic::InstanceMethods.instance_methods +
|
66
67
|
Plezi::Base::ControllerCore::InstanceMethods.instance_methods +
|
67
|
-
[:before, :after, :initialize]) ).delete_if {|m| m.to_s[0] == '_'}).to_set unless self.class.instance_variable_get(:@allow_dispatch)
|
68
|
+
[:before, :after, :initialize, :unknown , :unknown_event]) ).delete_if {|m| m.to_s[0] == '_'}).to_set unless self.class.instance_variable_get(:@allow_dispatch)
|
68
69
|
Plezi::Base::Helpers.make_hash_accept_symbols data
|
69
|
-
|
70
|
-
|
70
|
+
ret = nil
|
71
|
+
begin
|
72
|
+
if data['_EID_'.freeze]
|
73
|
+
write "{\"event\":\"_ack_\",\"_EID_\":#{data['_EID_'.freeze]}}"
|
74
|
+
end
|
75
|
+
if self.class.has_super_method?(data['event'.freeze] = data['event'.freeze].to_s.to_sym) && self.class.instance_variable_get(:@allow_dispatch).include?(data['event'.freeze])
|
76
|
+
ret = self.__send__(data['event'.freeze], data)
|
77
|
+
else
|
78
|
+
ret = (self.class.has_super_method?(:unknown) && ( unknown(data) || true)) || (self.class.has_super_method?(:unknown_event) && Iodine.warn('Auto-Dispatch API updated: use `unknown` instead of `unknown_event`') && ( unknown_event(data) || true)) || ({ event: :err, status: 404, result: "not found", request: data }.to_json)
|
79
|
+
end
|
80
|
+
rescue ArgumentError => e
|
81
|
+
Iodine.error "Auto-Dispatch Error for event :#{data['event'.freeze]} - #{e.message}"
|
71
82
|
end
|
72
|
-
ret =
|
83
|
+
ret = ret.to_json if ret.is_a?(Hash)
|
73
84
|
write(ret) if ret.is_a?(String)
|
74
85
|
end
|
75
86
|
|
@@ -103,6 +103,13 @@ module Plezi
|
|
103
103
|
(@ws_io || @response) << data
|
104
104
|
end
|
105
105
|
|
106
|
+
# @!visibility public
|
107
|
+
# Closes the connection
|
108
|
+
def close
|
109
|
+
# @request[:io] contains the Websockets Protocol instance
|
110
|
+
(@ws_io || @request[:io]).go_away
|
111
|
+
end
|
112
|
+
|
106
113
|
# @!visibility public
|
107
114
|
# Performs a websocket unicast to the specified target.
|
108
115
|
def unicast target_uuid, method_name, *args
|
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 "iodine", "~> 0.1.
|
21
|
+
spec.add_dependency "iodine", "~> 0.1.19"
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.7"
|
23
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
24
|
|
data/resources/plezi_client.js
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
// This is a commonly used structure for WebSocket messanging.
|
2
|
+
// The documentation is available on the www.plezi.io website:
|
3
|
+
// http://www.plezi.io/docs/websockets#websocket-json-auto-dispatch
|
2
4
|
//
|
3
|
-
//
|
4
|
-
//
|
5
|
+
// Basics:
|
6
|
+
// To open a websocket connection to the current location:
|
5
7
|
//
|
6
8
|
// var client = new PleziClient()
|
7
9
|
//
|
@@ -9,104 +11,128 @@
|
|
9
11
|
//
|
10
12
|
// var client = new PleziClient(PleziClient.origin + "/path")
|
11
13
|
//
|
12
|
-
// i.e., to open a connection to the root ("/"), use:
|
13
|
-
//
|
14
|
-
// var client = new PleziClient(PleziClient.origin + "/")
|
15
|
-
//
|
16
|
-
// To open a connection to a different URL or path, use:
|
17
|
-
//
|
18
|
-
// var client = new PleziClient("ws://full.url.com/path")
|
19
|
-
//
|
20
14
|
// To automatically renew the connection when disconnections are reported by the browser, use:
|
21
15
|
//
|
22
|
-
// client.
|
23
|
-
// client.reconnect_interval = 250 // sets how long to wait before reconnection attempts. default is
|
16
|
+
// client.autoreconnect = true
|
17
|
+
// client.reconnect_interval = 250 // sets how long to wait before reconnection attempts. default is 250 ms.
|
24
18
|
//
|
25
|
-
//
|
19
|
+
// To set up event handling, directly set an `<event name>` callback. i.e., for an event called `chat`:
|
26
20
|
//
|
27
|
-
//
|
28
|
-
// client.reconnect_interval = 250 // Or use the default 50 ms.
|
29
|
-
//
|
30
|
-
// To set up event handling, directly set an `on<event name>` callback. i.e., for an event called `chat`:
|
31
|
-
//
|
32
|
-
// client.onchat = function(event) { "..." }
|
21
|
+
// client.chat = function(event) { "..." }
|
33
22
|
//
|
34
23
|
// To sent / emit event in JSON format, use the `emit` method:
|
35
24
|
//
|
36
25
|
// client.emit({event: "chat", data: "the message"})
|
37
26
|
//
|
38
|
-
|
39
|
-
//
|
40
|
-
// i.e. sending a string:
|
41
|
-
//
|
42
|
-
// client.send("string")
|
43
|
-
//
|
44
|
-
// Manually closing the connection will prevent automatic reconnection:
|
45
|
-
//
|
46
|
-
// client.close()
|
47
|
-
//
|
48
|
-
function PleziClient(url, reconnect) {
|
49
|
-
this.connected = NaN;
|
27
|
+
function PleziClient(url, autoreconnect) {
|
28
|
+
// Set URL
|
50
29
|
if(url) {
|
51
30
|
this.url = url
|
52
31
|
} else {
|
53
32
|
this.url = PleziClient.origin + window.location.pathname
|
54
33
|
}
|
55
|
-
|
56
|
-
this.
|
57
|
-
|
58
|
-
this.
|
59
|
-
this.reconnect_interval =
|
60
|
-
|
61
|
-
this.
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
34
|
+
// Connect Websocket
|
35
|
+
this.reconnect();
|
36
|
+
// auto-reconnection
|
37
|
+
this.autoreconnect = false;
|
38
|
+
this.reconnect_interval = 200
|
39
|
+
// the timeout for a message ack receipt
|
40
|
+
this.emit_timeout = false
|
41
|
+
// Set the autoreconnect property
|
42
|
+
if(autoreconnect) {this.autoreconnect = true;}
|
43
|
+
}
|
44
|
+
// The Websocket onopen callback
|
45
|
+
PleziClient.prototype.___on_open = function(e) {
|
46
|
+
this.owner.connected = true;
|
47
|
+
if (this.owner.onopen) { this.owner.onopen(e) }
|
48
|
+
}
|
49
|
+
// The Websocket onclose callback
|
50
|
+
PleziClient.prototype.___on_close = function(e) {
|
51
|
+
this.owner.connected = false;
|
52
|
+
if (this.owner.onclose) { this.owner.onclose(e) }
|
53
|
+
if(this.owner.autoreconnect) {
|
54
|
+
setTimeout( function(obj) {
|
55
|
+
obj.reconnect();
|
56
|
+
}, this.owner.reconnect_interval, this.owner);
|
75
57
|
}
|
76
|
-
this.ws.onerror = function(e) { if (this.owner.onerror) {this.owner.onerror(e)} }
|
77
|
-
this.ws.onmessage = this.___on_message
|
78
58
|
}
|
79
|
-
|
59
|
+
// The Websocket onerror callback
|
60
|
+
PleziClient.prototype.___on_error = function(e) {
|
61
|
+
if (this.owner.onerror) {this.owner.onerror(e)}
|
62
|
+
}
|
63
|
+
// The Websocket onmessage callback
|
80
64
|
PleziClient.prototype.___on_message = function(e) {
|
81
65
|
try {
|
82
66
|
var msg = JSON.parse(e.data);
|
83
|
-
if (
|
67
|
+
if ( msg.event == '_ack_') { clearTimeout(msg._EID_) }
|
68
|
+
if ( (msg.event) && (this.owner[msg.event])) {
|
69
|
+
this.owner[msg.event](msg);
|
70
|
+
} else if ( (msg.event) && (this.owner['on' + msg.event])) {
|
71
|
+
console.warn('PleziClient: use a callback called "' + msg.event +
|
72
|
+
'" instead of of "on' + msg.event + '"');
|
84
73
|
this.owner['on' + msg.event](msg);
|
85
74
|
} else
|
86
75
|
{
|
87
|
-
if (this.owner['unknown']) {this.owner['unknown'](msg)};
|
76
|
+
if (this.owner['unknown'] && (msg.event != '_ack_') ) {this.owner['unknown'](msg)};
|
88
77
|
}
|
89
78
|
} catch(err) {
|
90
|
-
console.error(
|
79
|
+
console.error("PleziClient experienced an error while responding to the following onmessage event",
|
80
|
+
err, e)
|
91
81
|
}
|
92
82
|
}
|
83
|
+
// Sets a timeout for the websocket message
|
84
|
+
PleziClient.prototype.___set_failed_timeout = function(event, callback, timeout) {
|
85
|
+
if(event._EID_) {return event;};
|
86
|
+
if(!timeout) { timeout = this.emit_timeout; };
|
87
|
+
if(!callback) { callback = this.___on_timeout; };
|
88
|
+
if(!timeout) { return event; };
|
89
|
+
event._EID_ = setTimeout(callback, timeout, event, this);
|
90
|
+
return event;
|
91
|
+
}
|
92
|
+
// Removes the _client_ property from the event and calls
|
93
|
+
// the ontimeout callback within the correct scope
|
94
|
+
PleziClient.prototype.___on_timeout = function(event, client) {
|
95
|
+
client.ontimeout(event)
|
96
|
+
}
|
97
|
+
// The timeout callback
|
98
|
+
PleziClient.prototype.ontimeout = function(event) {
|
99
|
+
console.warn("Timeout reached - it's assumed the connection was lost " +
|
100
|
+
"and the following event was ignored by the server:", event);
|
101
|
+
console.log(this);
|
102
|
+
}
|
103
|
+
|
104
|
+
PleziClient.prototype.reconnect = function() {
|
105
|
+
this.connected = NaN;
|
106
|
+
this.ws = new WebSocket(this.url);
|
107
|
+
// lets us access the client from the callbacks
|
108
|
+
this.ws.owner = this
|
109
|
+
// The Websocket onopen callback
|
110
|
+
this.ws.on_open = this.___on_open
|
111
|
+
// The Websocket onclose callback
|
112
|
+
this.ws.onclose = this.___on_close
|
113
|
+
// The Websocket onerror callback
|
114
|
+
this.ws.onerror = this.___on_error
|
115
|
+
// The Websocket onmessage callback
|
116
|
+
this.ws.onmessage = this.___on_message
|
117
|
+
}
|
93
118
|
|
94
119
|
PleziClient.prototype.close = function() {
|
95
|
-
this.
|
120
|
+
this.autoreconnect = false;
|
96
121
|
this.ws.close();
|
97
122
|
}
|
98
123
|
|
99
124
|
PleziClient.origin = (window.location.protocol.match(/https/) ? 'wws' : 'ws') + '://' + window.location.hostname + (window.location.port == '' ? '' : (':' + window.location.port) );
|
100
125
|
|
101
|
-
PleziClient.prototype.
|
126
|
+
PleziClient.prototype.sendraw = function(data) {
|
102
127
|
if (this.ws.readyState != 1) { return false; }
|
103
128
|
this.ws.send(data);
|
104
129
|
if (this.ws.readyState != 1) { return false; }
|
105
130
|
return true
|
106
131
|
}
|
107
132
|
|
108
|
-
PleziClient.prototype.emit = function(
|
109
|
-
|
133
|
+
PleziClient.prototype.emit = function(event, callback, timeout) {
|
134
|
+
this.___set_failed_timeout(event, callback, timeout)
|
135
|
+
return this.sendraw( JSON.stringify(event) );
|
110
136
|
}
|
111
137
|
|
112
138
|
PleziClient.prototype.readyState = function() { return this.ws.readyState; }
|
data/test/dispatch
CHANGED
@@ -25,22 +25,23 @@ class DispatchTest
|
|
25
25
|
data[:data] ||= "test"
|
26
26
|
{event: 'alert', data: data[:data]}.to_json
|
27
27
|
end
|
28
|
-
def index
|
29
|
-
%q{<html><head><script src='/
|
28
|
+
def index event = nil
|
29
|
+
%q{<html><head><script src='/client.js'></script>
|
30
30
|
</head>
|
31
31
|
<body>
|
32
32
|
<button onclick='connection.emit({event: "test", data: "Woohooo!"});' value='test'>Test!</button>
|
33
33
|
<script>
|
34
34
|
document.body.onload = function() {
|
35
35
|
connection = new PleziClient();
|
36
|
-
connection.
|
36
|
+
connection.alert = function(data) {
|
37
37
|
alert(JSON.stringify(data));
|
38
38
|
console.log(data);
|
39
39
|
}
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
connection.err = function(data) {
|
41
|
+
alert("Error: " + JSON.stringify(data));
|
42
|
+
console.log(data);
|
43
|
+
}
|
44
|
+
connection.emit_timeout = 3000;
|
44
45
|
connection.unknown = function(data) {
|
45
46
|
alert("Unknown event: " + JSON.stringify(data));
|
46
47
|
console.log(data);
|
@@ -49,5 +50,6 @@ document.body.onload = function() {
|
|
49
50
|
</script></body></html>}
|
50
51
|
end
|
51
52
|
end
|
52
|
-
host
|
53
|
+
host
|
54
|
+
route '/client.js', :client
|
53
55
|
route '/', DispatchTest
|
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.12.
|
4
|
+
version: 0.12.19
|
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-
|
11
|
+
date: 2015-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: iodine
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.1.
|
19
|
+
version: 0.1.19
|
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.1.
|
26
|
+
version: 0.1.19
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|