websocket-rails 0.4.7 → 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +13 -1
- data/Gemfile +1 -1
- data/lib/assets/javascripts/websocket_rails/channel.js.coffee +6 -0
- data/lib/assets/javascripts/websocket_rails/websocket_connection.js.coffee +2 -2
- data/lib/assets/javascripts/websocket_rails/websocket_rails.js.coffee +5 -0
- data/lib/websocket_rails/base_controller.rb +3 -1
- data/lib/websocket_rails/connection_adapters/http.rb +4 -0
- data/lib/websocket_rails/connection_adapters/web_socket.rb +6 -2
- data/lib/websocket_rails/internal_events.rb +8 -1
- data/lib/websocket_rails/version.rb +1 -1
- data/spec/dummy/log/test.log +3 -0
- data/spec/javascripts/generated/assets/channel.js +17 -9
- data/spec/javascripts/generated/assets/event.js +0 -8
- data/spec/javascripts/generated/assets/http_connection.js +3 -8
- data/spec/javascripts/generated/assets/websocket_connection.js +2 -9
- data/spec/javascripts/generated/assets/websocket_rails.js +13 -17
- data/spec/javascripts/generated/specs/channel_spec.js +0 -1
- data/spec/javascripts/generated/specs/event_spec.js +0 -1
- data/spec/javascripts/generated/specs/websocket_connection_spec.js +26 -7
- data/spec/javascripts/generated/specs/websocket_rails_spec.js +8 -1
- data/spec/javascripts/support/jasmine.yml +1 -1
- data/spec/javascripts/support/vendor/sinon-1.7.1.js +4343 -0
- data/spec/javascripts/websocket_rails/websocket_connection_spec.coffee +28 -5
- data/spec/javascripts/websocket_rails/websocket_rails_spec.coffee +6 -0
- data/spec/unit/base_controller_spec.rb +33 -0
- data/spec/unit/connection_adapters/http_spec.rb +7 -0
- data/spec/unit/connection_adapters/web_socket_spec.rb +11 -4
- data/spec/unit/logging_spec.rb +2 -1
- metadata +7 -10
- data/spec/javascripts/generated/assets/upload_event.js +0 -56
- data/spec/javascripts/generated/specs/upload_event_spec.js +0 -55
- data/spec/javascripts/support/vendor/sinon-1.3.4.js +0 -3555
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# WebsocketRails Change Log
|
2
2
|
|
3
|
+
## Version 0.4.8
|
4
|
+
|
5
|
+
July 6 2013
|
6
|
+
|
7
|
+
* Fix error with class reloading in development with Rails 4
|
8
|
+
* Added `connection.close!` method to allow for manually disconnecting users from a WebsocketRails controller.
|
9
|
+
* Add a way to unsubscribe from channels via the JavaScript client. - Thanks to @Oxynum
|
10
|
+
* Fix handling of `on_error` event in the JavaScript client. - Thanks to @imton
|
11
|
+
|
3
12
|
## Version 0.4.7
|
4
13
|
|
5
14
|
June 6 2013
|
@@ -8,9 +17,12 @@ June 6 2013
|
|
8
17
|
* Fix spelling mistake in ConnectionAdapters#inspect - Thanks to
|
9
18
|
@bmxpert1
|
10
19
|
* Prevent duplicate events from being triggered when events are added
|
11
|
-
directly to Redis from an outside process. - Thanks to @
|
20
|
+
directly to Redis from an outside process. - Thanks to @moaa
|
12
21
|
* Only log event data if it is a Hash or String to drastically reduce
|
13
22
|
the log file size. - Thanks to @florianguenther
|
23
|
+
* Fix the intermittent uninitialized constant
|
24
|
+
"WebsocketRails::InternalEvents" error in development. - Thanks to
|
25
|
+
@DarkSwoop
|
14
26
|
|
15
27
|
## Version 0.4.6
|
16
28
|
|
data/Gemfile
CHANGED
@@ -19,6 +19,12 @@ class WebSocketRails.Channel
|
|
19
19
|
@_dispatcher.trigger_event event
|
20
20
|
@_callbacks = {}
|
21
21
|
|
22
|
+
destroy: () =>
|
23
|
+
event_name = 'websocket_rails.unsubscribe'
|
24
|
+
event = new WebSocketRails.Event( [event_name, {data: {channel: @name}}, @_dispatcher.connection_id] )
|
25
|
+
@_dispatcher.trigger_event event
|
26
|
+
@_callbacks = {}
|
27
|
+
|
22
28
|
bind: (event_name, callback) =>
|
23
29
|
@_callbacks[event_name] ?= []
|
24
30
|
@_callbacks[event_name].push callback
|
@@ -22,11 +22,11 @@ class WebSocketRails.WebSocketConnection
|
|
22
22
|
@dispatcher.new_message data
|
23
23
|
|
24
24
|
on_close: (event) =>
|
25
|
-
close_event = new WebSocketRails.Event(['connection_closed',
|
25
|
+
close_event = new WebSocketRails.Event(['connection_closed', event])
|
26
26
|
@dispatcher.dispatch close_event
|
27
27
|
|
28
28
|
on_error: (event) =>
|
29
|
-
error_event = new WebSocketRails.Event(['connection_error',event
|
29
|
+
error_event = new WebSocketRails.Event(['connection_error', event])
|
30
30
|
@dispatcher.dispatch error_event
|
31
31
|
|
32
32
|
flush_queue: =>
|
@@ -87,6 +87,11 @@ class window.WebSocketRails
|
|
87
87
|
else
|
88
88
|
@channels[channel_name]
|
89
89
|
|
90
|
+
unsubscribe: (channel_name) =>
|
91
|
+
return unless @channels[channel_name]?
|
92
|
+
@channels[channel_name].destroy()
|
93
|
+
delete @channels[channel_name]
|
94
|
+
|
90
95
|
dispatch_channel: (event) =>
|
91
96
|
return unless @channels[event.channel]?
|
92
97
|
@channels[event.channel].dispatch event.name, event.data
|
@@ -21,7 +21,9 @@ module WebsocketRails
|
|
21
21
|
# Tell Rails that BaseController and children can be reloaded when in
|
22
22
|
# the Development environment.
|
23
23
|
def self.inherited(controller)
|
24
|
-
|
24
|
+
unless controller.name == "WebsocketRails::InternalController" || Rails.version =~/^4/
|
25
|
+
unloadable controller
|
26
|
+
end
|
25
27
|
end
|
26
28
|
|
27
29
|
# Add observers to specific events or the controller in general. This functionality is similar
|
@@ -6,9 +6,9 @@ module WebsocketRails
|
|
6
6
|
Faye::WebSocket.websocket?( env )
|
7
7
|
end
|
8
8
|
|
9
|
-
def initialize(request,dispatcher)
|
9
|
+
def initialize(request, dispatcher)
|
10
10
|
super
|
11
|
-
@connection = Faye::WebSocket.new(
|
11
|
+
@connection = Faye::WebSocket.new(request.env)
|
12
12
|
@connection.onmessage = method(:on_message)
|
13
13
|
@connection.onerror = method(:on_error)
|
14
14
|
@connection.onclose = method(:on_close)
|
@@ -24,6 +24,10 @@ module WebsocketRails
|
|
24
24
|
super data
|
25
25
|
end
|
26
26
|
|
27
|
+
def close!
|
28
|
+
@connection.close
|
29
|
+
end
|
30
|
+
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
@@ -5,6 +5,7 @@ module WebsocketRails
|
|
5
5
|
namespace :websocket_rails do
|
6
6
|
subscribe :pong, :to => InternalController, :with_method => :do_pong
|
7
7
|
subscribe :subscribe, :to => InternalController, :with_method => :subscribe_to_channel
|
8
|
+
subscribe :unsubscribe, :to => InternalController, :with_method => :unsubscribe_to_channel
|
8
9
|
end
|
9
10
|
end
|
10
11
|
end
|
@@ -19,10 +20,16 @@ module WebsocketRails
|
|
19
20
|
WebsocketRails[channel_name].subscribe connection
|
20
21
|
trigger_success
|
21
22
|
else
|
22
|
-
trigger_failure( { :reason => "channel is private", :hint => "use
|
23
|
+
trigger_failure( { :reason => "channel is private", :hint => "use subscribe_private instead." } )
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
27
|
+
def unsubscribe_to_channel
|
28
|
+
channel_name = event.data[:channel]
|
29
|
+
WebsocketRails[channel_name].unsubscribe connection
|
30
|
+
trigger_success
|
31
|
+
end
|
32
|
+
|
26
33
|
def do_pong
|
27
34
|
connection.pong = true
|
28
35
|
end
|
data/spec/dummy/log/test.log
CHANGED
@@ -153,3 +153,6 @@ Connecting to database specified by database.yml
|
|
153
153
|
Connecting to database specified by database.yml
|
154
154
|
Connecting to database specified by database.yml
|
155
155
|
Connecting to database specified by database.yml
|
156
|
+
Connecting to database specified by database.yml
|
157
|
+
Connecting to database specified by database.yml
|
158
|
+
Connecting to database specified by database.yml
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
/*
|
3
2
|
The channel object is returned when you subscribe to a channel.
|
4
3
|
|
@@ -14,22 +13,17 @@ For instance:
|
|
14
13
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
15
14
|
|
16
15
|
WebSocketRails.Channel = (function() {
|
17
|
-
|
18
16
|
function Channel(name, _dispatcher, is_private) {
|
19
17
|
var event, event_name;
|
20
18
|
this.name = name;
|
21
19
|
this._dispatcher = _dispatcher;
|
22
20
|
this.is_private = is_private;
|
23
21
|
this._failure_launcher = __bind(this._failure_launcher, this);
|
24
|
-
|
25
22
|
this._success_launcher = __bind(this._success_launcher, this);
|
26
|
-
|
27
23
|
this.dispatch = __bind(this.dispatch, this);
|
28
|
-
|
29
24
|
this.trigger = __bind(this.trigger, this);
|
30
|
-
|
31
25
|
this.bind = __bind(this.bind, this);
|
32
|
-
|
26
|
+
this.destroy = __bind(this.destroy, this);
|
33
27
|
if (this.is_private) {
|
34
28
|
event_name = 'websocket_rails.subscribe_private';
|
35
29
|
} else {
|
@@ -46,9 +40,23 @@ For instance:
|
|
46
40
|
this._callbacks = {};
|
47
41
|
}
|
48
42
|
|
43
|
+
Channel.prototype.destroy = function() {
|
44
|
+
var event, event_name;
|
45
|
+
event_name = 'websocket_rails.unsubscribe';
|
46
|
+
event = new WebSocketRails.Event([
|
47
|
+
event_name, {
|
48
|
+
data: {
|
49
|
+
channel: this.name
|
50
|
+
}
|
51
|
+
}, this._dispatcher.connection_id
|
52
|
+
]);
|
53
|
+
this._dispatcher.trigger_event(event);
|
54
|
+
return this._callbacks = {};
|
55
|
+
};
|
56
|
+
|
49
57
|
Channel.prototype.bind = function(event_name, callback) {
|
50
|
-
var _base
|
51
|
-
if ((
|
58
|
+
var _base;
|
59
|
+
if ((_base = this._callbacks)[event_name] == null) {
|
52
60
|
_base[event_name] = [];
|
53
61
|
}
|
54
62
|
return this._callbacks[event_name].push(callback);
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
/*
|
3
2
|
The Event object stores all the relevant event information.
|
4
3
|
*/
|
@@ -8,23 +7,16 @@ The Event object stores all the relevant event information.
|
|
8
7
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
9
8
|
|
10
9
|
WebSocketRails.Event = (function() {
|
11
|
-
|
12
10
|
function Event(data, success_callback, failure_callback) {
|
13
11
|
var attr;
|
14
12
|
this.success_callback = success_callback;
|
15
13
|
this.failure_callback = failure_callback;
|
16
14
|
this.run_callbacks = __bind(this.run_callbacks, this);
|
17
|
-
|
18
15
|
this.attributes = __bind(this.attributes, this);
|
19
|
-
|
20
16
|
this.serialize = __bind(this.serialize, this);
|
21
|
-
|
22
17
|
this.is_ping = __bind(this.is_ping, this);
|
23
|
-
|
24
18
|
this.is_result = __bind(this.is_result, this);
|
25
|
-
|
26
19
|
this.is_channel = __bind(this.is_channel, this);
|
27
|
-
|
28
20
|
this.name = data[0];
|
29
21
|
attr = data[1];
|
30
22
|
if (attr != null) {
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
/*
|
3
2
|
HTTP Interface for the WebSocketRails client.
|
4
3
|
*/
|
@@ -8,7 +7,6 @@
|
|
8
7
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
9
8
|
|
10
9
|
WebSocketRails.HttpConnection = (function() {
|
11
|
-
|
12
10
|
HttpConnection.prototype.httpFactories = function() {
|
13
11
|
return [
|
14
12
|
function() {
|
@@ -24,14 +22,15 @@
|
|
24
22
|
};
|
25
23
|
|
26
24
|
HttpConnection.prototype.createXMLHttpObject = function() {
|
27
|
-
var factories, factory, xmlhttp, _i, _len;
|
25
|
+
var e, factories, factory, xmlhttp, _i, _len;
|
28
26
|
xmlhttp = false;
|
29
27
|
factories = this.httpFactories();
|
30
28
|
for (_i = 0, _len = factories.length; _i < _len; _i++) {
|
31
29
|
factory = factories[_i];
|
32
30
|
try {
|
33
31
|
xmlhttp = factory();
|
34
|
-
} catch (
|
32
|
+
} catch (_error) {
|
33
|
+
e = _error;
|
35
34
|
continue;
|
36
35
|
}
|
37
36
|
break;
|
@@ -43,13 +42,9 @@
|
|
43
42
|
this.url = url;
|
44
43
|
this.dispatcher = dispatcher;
|
45
44
|
this.flush_queue = __bind(this.flush_queue, this);
|
46
|
-
|
47
45
|
this.trigger = __bind(this.trigger, this);
|
48
|
-
|
49
46
|
this.parse_stream = __bind(this.parse_stream, this);
|
50
|
-
|
51
47
|
this.createXMLHttpObject = __bind(this.createXMLHttpObject, this);
|
52
|
-
|
53
48
|
this._url = this.url;
|
54
49
|
this._conn = this.createXMLHttpObject();
|
55
50
|
this.last_pos = 0;
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
/*
|
3
2
|
WebSocket Interface for the WebSocketRails client.
|
4
3
|
*/
|
@@ -8,20 +7,14 @@ WebSocket Interface for the WebSocketRails client.
|
|
8
7
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
9
8
|
|
10
9
|
WebSocketRails.WebSocketConnection = (function() {
|
11
|
-
|
12
10
|
function WebSocketConnection(url, dispatcher) {
|
13
11
|
this.url = url;
|
14
12
|
this.dispatcher = dispatcher;
|
15
13
|
this.flush_queue = __bind(this.flush_queue, this);
|
16
|
-
|
17
14
|
this.on_error = __bind(this.on_error, this);
|
18
|
-
|
19
15
|
this.on_close = __bind(this.on_close, this);
|
20
|
-
|
21
16
|
this.on_message = __bind(this.on_message, this);
|
22
|
-
|
23
17
|
this.trigger = __bind(this.trigger, this);
|
24
|
-
|
25
18
|
if (!this.url.match(/^wss?:\/\//)) {
|
26
19
|
this.url = "ws://" + this.url;
|
27
20
|
}
|
@@ -48,13 +41,13 @@ WebSocket Interface for the WebSocketRails client.
|
|
48
41
|
|
49
42
|
WebSocketConnection.prototype.on_close = function(event) {
|
50
43
|
var close_event;
|
51
|
-
close_event = new WebSocketRails.Event(['connection_closed',
|
44
|
+
close_event = new WebSocketRails.Event(['connection_closed', event]);
|
52
45
|
return this.dispatcher.dispatch(close_event);
|
53
46
|
};
|
54
47
|
|
55
48
|
WebSocketConnection.prototype.on_error = function(event) {
|
56
49
|
var error_event;
|
57
|
-
error_event = new WebSocketRails.Event(['connection_error', event
|
50
|
+
error_event = new WebSocketRails.Event(['connection_error', event]);
|
58
51
|
return this.dispatcher.dispatch(error_event);
|
59
52
|
};
|
60
53
|
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
/*
|
3
2
|
WebsocketRails JavaScript Client
|
4
3
|
|
@@ -23,32 +22,21 @@ Listening for new events from the server
|
|
23
22
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
24
23
|
|
25
24
|
window.WebSocketRails = (function() {
|
26
|
-
|
27
25
|
function WebSocketRails(url, use_websockets) {
|
28
26
|
this.url = url;
|
29
27
|
this.use_websockets = use_websockets != null ? use_websockets : true;
|
30
28
|
this.pong = __bind(this.pong, this);
|
31
|
-
|
32
29
|
this.supports_websockets = __bind(this.supports_websockets, this);
|
33
|
-
|
34
30
|
this.dispatch_channel = __bind(this.dispatch_channel, this);
|
35
|
-
|
31
|
+
this.unsubscribe = __bind(this.unsubscribe, this);
|
36
32
|
this.subscribe_private = __bind(this.subscribe_private, this);
|
37
|
-
|
38
33
|
this.subscribe = __bind(this.subscribe, this);
|
39
|
-
|
40
34
|
this.dispatch = __bind(this.dispatch, this);
|
41
|
-
|
42
35
|
this.trigger_event = __bind(this.trigger_event, this);
|
43
|
-
|
44
36
|
this.trigger = __bind(this.trigger, this);
|
45
|
-
|
46
37
|
this.bind = __bind(this.bind, this);
|
47
|
-
|
48
38
|
this.connection_established = __bind(this.connection_established, this);
|
49
|
-
|
50
39
|
this.new_message = __bind(this.new_message, this);
|
51
|
-
|
52
40
|
this.state = 'connecting';
|
53
41
|
this.callbacks = {};
|
54
42
|
this.channels = {};
|
@@ -98,8 +86,8 @@ Listening for new events from the server
|
|
98
86
|
};
|
99
87
|
|
100
88
|
WebSocketRails.prototype.bind = function(event_name, callback) {
|
101
|
-
var _base
|
102
|
-
if ((
|
89
|
+
var _base;
|
90
|
+
if ((_base = this.callbacks)[event_name] == null) {
|
103
91
|
_base[event_name] = [];
|
104
92
|
}
|
105
93
|
return this.callbacks[event_name].push(callback);
|
@@ -113,8 +101,8 @@ Listening for new events from the server
|
|
113
101
|
};
|
114
102
|
|
115
103
|
WebSocketRails.prototype.trigger_event = function(event) {
|
116
|
-
var _base, _name
|
117
|
-
if ((
|
104
|
+
var _base, _name;
|
105
|
+
if ((_base = this.queue)[_name = event.id] == null) {
|
118
106
|
_base[_name] = event;
|
119
107
|
}
|
120
108
|
return this._conn.trigger(event);
|
@@ -156,6 +144,14 @@ Listening for new events from the server
|
|
156
144
|
}
|
157
145
|
};
|
158
146
|
|
147
|
+
WebSocketRails.prototype.unsubscribe = function(channel_name) {
|
148
|
+
if (this.channels[channel_name] == null) {
|
149
|
+
return;
|
150
|
+
}
|
151
|
+
this.channels[channel_name].destroy();
|
152
|
+
return delete this.channels[channel_name];
|
153
|
+
};
|
154
|
+
|
159
155
|
WebSocketRails.prototype.dispatch_channel = function(event) {
|
160
156
|
if (this.channels[event.channel] == null) {
|
161
157
|
return;
|
@@ -1,5 +1,4 @@
|
|
1
1
|
(function() {
|
2
|
-
|
3
2
|
describe('WebsocketRails.WebSocketConnection:', function() {
|
4
3
|
beforeEach(function() {
|
5
4
|
var dispatcher;
|
@@ -18,6 +17,7 @@
|
|
18
17
|
return true;
|
19
18
|
};
|
20
19
|
};
|
20
|
+
this.dispatcher = dispatcher;
|
21
21
|
return this.connection = new WebSocketRails.WebSocketConnection('localhost:3000/websocket', dispatcher);
|
22
22
|
});
|
23
23
|
describe('constructor', function() {
|
@@ -81,12 +81,31 @@
|
|
81
81
|
});
|
82
82
|
});
|
83
83
|
describe('.on_close', function() {
|
84
|
-
return it('should dispatch the connection_closed event', function() {
|
85
|
-
var
|
86
|
-
|
87
|
-
|
88
|
-
this.
|
89
|
-
|
84
|
+
return it('should dispatch the connection_closed event and pass the original event', function() {
|
85
|
+
var close_event, dispatcher, event, lastCall;
|
86
|
+
event = new WebSocketRails.Event(['event', 'message']);
|
87
|
+
close_event = new WebSocketRails.Event(['connection_closed', event]);
|
88
|
+
sinon.spy(this.dispatcher, 'dispatch');
|
89
|
+
this.connection.on_close(event);
|
90
|
+
dispatcher = this.dispatcher.dispatch;
|
91
|
+
lastCall = dispatcher.lastCall.args[0];
|
92
|
+
expect(dispatcher.calledOnce).toBe(true);
|
93
|
+
expect(lastCall.data).toEqual(event.data);
|
94
|
+
return dispatcher.restore();
|
95
|
+
});
|
96
|
+
});
|
97
|
+
describe('.on_error', function() {
|
98
|
+
return it('should dispatch the connection_error event and pass the original event', function() {
|
99
|
+
var dispatcher, error_event, event, lastCall;
|
100
|
+
event = new WebSocketRails.Event(['event', 'message']);
|
101
|
+
error_event = new WebSocketRails.Event(['connection_error', event]);
|
102
|
+
sinon.spy(this.dispatcher, 'dispatch');
|
103
|
+
this.connection.on_error(event);
|
104
|
+
dispatcher = this.dispatcher.dispatch;
|
105
|
+
lastCall = dispatcher.lastCall.args[0];
|
106
|
+
expect(dispatcher.calledOnce).toBe(true);
|
107
|
+
expect(lastCall.data).toEqual(event.data);
|
108
|
+
return dispatcher.restore();
|
90
109
|
});
|
91
110
|
});
|
92
111
|
return describe('.flush_queue', function() {
|