faye-authentication 0.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.drone.yml +10 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +0 -3
- data/README.md +47 -26
- data/VERSION +1 -0
- data/app/assets/javascripts/faye-authentication.js +18 -11
- data/faye-authentication.gemspec +3 -2
- data/lib/faye/authentication/client_extension.rb +1 -1
- data/lib/faye/authentication/server_extension.rb +3 -2
- data/lib/faye/authentication/version.rb +1 -1
- data/lib/faye/authentication.rb +20 -8
- data/spec/javascripts/faye-authentication_spec.js +151 -48
- data/spec/javascripts/faye-extension_spec.js +1 -1
- data/spec/javascripts/support/jasmine.yml +1 -1
- data/spec/lib/faye/authentication/server_extension_spec.rb +14 -24
- data/spec/lib/faye/authentication_spec.rb +91 -1
- data/spec/utils/javascripts/faye.js +388 -290
- metadata +27 -15
- data/spec/utils/javascripts/core.js +0 -712
- data/spec/utils/javascripts/sha1.js +0 -136
@@ -31,7 +31,7 @@ describe('Faye extension', function() {
|
|
31
31
|
function stubSignature(context, callback) {
|
32
32
|
var self = context;
|
33
33
|
self.client.handshake(function() {
|
34
|
-
var jwtsign = new jwt.WebToken('{"clientId": "' + self.client.
|
34
|
+
var jwtsign = new jwt.WebToken('{"clientId": "' + self.client._dispatcher.clientId + '", "channel": "/foobar", "exp": 2803694528}', '{"alg": "HS256"}');
|
35
35
|
var signature = jwtsign.serialize("macaroni");
|
36
36
|
|
37
37
|
jasmine.Ajax.stubRequest('/faye/auth').andReturn({
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'faye/authentication
|
2
|
+
require 'faye/authentication'
|
3
3
|
|
4
4
|
describe Faye::Authentication::ServerExtension do
|
5
5
|
|
6
6
|
let(:secret) { 'macaroni' }
|
7
7
|
let(:extension) { Faye::Authentication::ServerExtension.new(secret) }
|
8
|
+
let(:channel) { '/channel' }
|
8
9
|
|
9
10
|
describe '#incoming' do
|
10
11
|
shared_examples 'signature_has_error' do
|
@@ -22,31 +23,20 @@ describe Faye::Authentication::ServerExtension do
|
|
22
23
|
end
|
23
24
|
|
24
25
|
shared_examples 'authentication_actions' do
|
25
|
-
context 'not
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
it_should_behave_like 'signature_has_no_error'
|
30
|
-
end
|
26
|
+
context 'does not require signature' do
|
27
|
+
before { expect(Faye::Authentication).to receive(:authentication_required?).with(message, {}).and_return(false) }
|
28
|
+
it_should_behave_like 'signature_has_no_error'
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
context 'requires signature' do
|
32
|
+
before { expect(Faye::Authentication).to receive(:authentication_required?).with(message, {}).and_return(true) }
|
33
|
+
context 'with signature' do
|
34
|
+
before { message['signature'] = Faye::Authentication.sign(message.merge({'channel' => channel}), secret) }
|
35
|
+
it_should_behave_like 'signature_has_no_error'
|
36
36
|
end
|
37
37
|
|
38
|
-
context '
|
39
|
-
|
40
|
-
let(:channel) { '/whatever' }
|
41
|
-
it_should_behave_like 'signature_has_error'
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'signed' do
|
45
|
-
let(:channel) { '/foo/bar' }
|
46
|
-
before { message['signature'] = Faye::Authentication.sign(message.merge({'channel' => channel}), secret) }
|
47
|
-
it_should_behave_like 'signature_has_no_error'
|
48
|
-
end
|
49
|
-
|
38
|
+
context 'without signature' do
|
39
|
+
it_should_behave_like 'signature_has_error'
|
50
40
|
end
|
51
41
|
end
|
52
42
|
end
|
@@ -70,7 +60,7 @@ describe Faye::Authentication::ServerExtension do
|
|
70
60
|
['/meta/handshake', '/meta/connect', '/meta/unsubscribe', '/meta/disconnect'].each do |channel|
|
71
61
|
it "does not check the signature for #{channel}" do
|
72
62
|
message = {'channel' => channel, 'clientId' => '42', 'text' => 'whatever', 'signature' => 'hello'}
|
73
|
-
expect(Faye::Authentication).to_not receive(:
|
63
|
+
expect(Faye::Authentication).to_not receive(:validate)
|
74
64
|
extension.incoming(message, ->(_) {});
|
75
65
|
end
|
76
66
|
end
|
@@ -8,7 +8,7 @@ describe Faye::Authentication do
|
|
8
8
|
let(:message) { {'channel' => channel, 'clientId' => clientId, 'text' => 'whatever'} }
|
9
9
|
let(:secret) { 'helloworld' }
|
10
10
|
let(:signature) { Faye::Authentication.sign(message, secret) }
|
11
|
-
|
11
|
+
|
12
12
|
describe '#sign' do
|
13
13
|
it 'returns with a default expiry'
|
14
14
|
end
|
@@ -55,4 +55,94 @@ describe Faye::Authentication do
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
describe '#authentication_required?' do
|
59
|
+
|
60
|
+
before(:each) { Faye.logger = nil }
|
61
|
+
|
62
|
+
shared_examples 'subscribe_and_publish' do
|
63
|
+
it 'returns true if no options are passed' do
|
64
|
+
expect(Faye::Authentication.authentication_required?(message)).to be(true)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'returns true if empty options are passed' do
|
68
|
+
expect(Faye::Authentication.authentication_required?(message, {})).to be(true)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns true if not a lamda / proc' do
|
72
|
+
expect(Faye::Authentication.authentication_required?(message, {whitelist: 42})).to be(true)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'calls the lambda with the channel or subscription' do
|
76
|
+
block = double
|
77
|
+
expect(block).to receive(:call).with(message['subscription'] || message['channel'])
|
78
|
+
Faye::Authentication.authentication_required?(message, {whitelist: block})
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'returns true if lambda raises' do
|
82
|
+
expect(Faye::Authentication.authentication_required?(message, {whitelist: lambda { |message| raise "oops" }})).to be(true)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'logs the error if lambda raises' do
|
86
|
+
Faye.logger = double()
|
87
|
+
expect(Faye.logger).to receive(:error).with("[Module] Error caught when evaluating whitelist lambda : oops")
|
88
|
+
Faye::Authentication.authentication_required?(message, {whitelist: lambda { |message| raise "oops" }})
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns true if lambda returns false' do
|
92
|
+
expect(Faye::Authentication.authentication_required?(message, {whitelist: lambda { |message| false }})).to be(true)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns false if lambda returns true' do
|
96
|
+
expect(Faye::Authentication.authentication_required?(message, {whitelist: lambda { |message| true }})).to be(false)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
shared_examples 'meta_except_subscribe' do
|
101
|
+
it 'returns false if no options are passed' do
|
102
|
+
expect(Faye::Authentication.authentication_required?(message)).to be(false)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'returns false if empty options are passed' do
|
106
|
+
expect(Faye::Authentication.authentication_required?(message, {})).to be(false)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'returns false even if lambda returns false' do
|
110
|
+
expect(Faye::Authentication.authentication_required?(message, {whitelist: lambda { |message| false }})).to be(false)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'does not call lambda / proc' do
|
114
|
+
not_called = double()
|
115
|
+
expect(not_called).to_not receive(:call)
|
116
|
+
(Faye::Authentication.authentication_required?(message, {whitelist: not_called}))
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'publish' do
|
122
|
+
let(:message) { {'channel' => '/foobar'} }
|
123
|
+
it_behaves_like 'subscribe_and_publish'
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'subscribe' do
|
127
|
+
let(:message) { {'channel' => '/meta/subscribe', 'subscription' => '/foobar'} }
|
128
|
+
it_behaves_like 'subscribe_and_publish'
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'handshake' do
|
132
|
+
let(:message) { {'channel' => '/meta/handshake'} }
|
133
|
+
it_behaves_like 'meta_except_subscribe'
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'connect' do
|
137
|
+
let(:message) { {'channel' => '/meta/connect'} }
|
138
|
+
it_behaves_like 'meta_except_subscribe'
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'unsubscribe' do
|
142
|
+
let(:message) { {'channel' => '/meta/unsubscribe', 'subscription' => '/foobar'} }
|
143
|
+
it_behaves_like 'meta_except_subscribe'
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
58
148
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
'use strict';
|
3
3
|
|
4
4
|
var Faye = {
|
5
|
-
VERSION: '1.0.
|
5
|
+
VERSION: '1.0.3',
|
6
6
|
|
7
7
|
BAYEUX_VERSION: '1.0',
|
8
8
|
ID_LENGTH: 160,
|
@@ -26,7 +26,10 @@ var Faye = {
|
|
26
26
|
|
27
27
|
random: function(bitlength) {
|
28
28
|
bitlength = bitlength || this.ID_LENGTH;
|
29
|
-
|
29
|
+
var maxLength = Math.ceil(bitlength * Math.log(2) / Math.log(36));
|
30
|
+
var string = csprng(bitlength, 36);
|
31
|
+
while (string.length < maxLength) string = '0' + string;
|
32
|
+
return string;
|
30
33
|
},
|
31
34
|
|
32
35
|
clientIdFromMessages: function(messages) {
|
@@ -744,7 +747,7 @@ Faye.Deferrable = {
|
|
744
747
|
setDeferredStatus: function(status, value) {
|
745
748
|
if (this._timer) Faye.ENV.clearTimeout(this._timer);
|
746
749
|
|
747
|
-
|
750
|
+
this.then();
|
748
751
|
|
749
752
|
if (status === 'succeeded')
|
750
753
|
this._fulfill(value);
|
@@ -801,7 +804,7 @@ Faye.Timeouts = {
|
|
801
804
|
this._timeouts = this._timeouts || {};
|
802
805
|
var timeout = this._timeouts[name];
|
803
806
|
if (!timeout) return;
|
804
|
-
clearTimeout(timeout);
|
807
|
+
Faye.ENV.clearTimeout(timeout);
|
805
808
|
delete this._timeouts[name];
|
806
809
|
},
|
807
810
|
|
@@ -823,13 +826,13 @@ Faye.Logging = {
|
|
823
826
|
writeLog: function(messageArgs, level) {
|
824
827
|
if (!Faye.logger) return;
|
825
828
|
|
826
|
-
var
|
827
|
-
banner
|
828
|
-
klass
|
829
|
+
var args = Array.prototype.slice.apply(messageArgs),
|
830
|
+
banner = '[Faye',
|
831
|
+
klass = this.className,
|
829
832
|
|
830
|
-
message =
|
833
|
+
message = args.shift().replace(/\?/g, function() {
|
831
834
|
try {
|
832
|
-
return Faye.toJSON(
|
835
|
+
return Faye.toJSON(args.shift());
|
833
836
|
} catch (e) {
|
834
837
|
return '[Object]';
|
835
838
|
}
|
@@ -852,11 +855,11 @@ Faye.Logging = {
|
|
852
855
|
|
853
856
|
(function() {
|
854
857
|
for (var key in Faye.Logging.LOG_LEVELS)
|
855
|
-
(function(level
|
858
|
+
(function(level) {
|
856
859
|
Faye.Logging[level] = function() {
|
857
860
|
this.writeLog(arguments, level);
|
858
861
|
};
|
859
|
-
})(key
|
862
|
+
})(key);
|
860
863
|
})();
|
861
864
|
|
862
865
|
Faye.Grammar = {
|
@@ -999,12 +1002,11 @@ Faye.extend(Faye.Channel, {
|
|
999
1002
|
},
|
1000
1003
|
|
1001
1004
|
subscribe: function(names, callback, context) {
|
1002
|
-
if (!callback) return;
|
1003
1005
|
var name;
|
1004
1006
|
for (var i = 0, n = names.length; i < n; i++) {
|
1005
1007
|
name = names[i];
|
1006
1008
|
var channel = this._channels[name] = this._channels[name] || new Faye.Channel(name);
|
1007
|
-
channel.bind('message', callback, context);
|
1009
|
+
if (callback) channel.bind('message', callback, context);
|
1008
1010
|
}
|
1009
1011
|
},
|
1010
1012
|
|
@@ -1032,17 +1034,6 @@ Faye.extend(Faye.Channel, {
|
|
1032
1034
|
})
|
1033
1035
|
});
|
1034
1036
|
|
1035
|
-
Faye.Envelope = Faye.Class({
|
1036
|
-
initialize: function(message, timeout) {
|
1037
|
-
this.id = message.id;
|
1038
|
-
this.message = message;
|
1039
|
-
|
1040
|
-
if (timeout !== undefined) this.timeout(timeout / 1000, false);
|
1041
|
-
}
|
1042
|
-
});
|
1043
|
-
|
1044
|
-
Faye.extend(Faye.Envelope.prototype, Faye.Deferrable);
|
1045
|
-
|
1046
1037
|
Faye.Publication = Faye.Class(Faye.Deferrable);
|
1047
1038
|
|
1048
1039
|
Faye.Subscription = Faye.Class({
|
@@ -1068,65 +1059,55 @@ Faye.Subscription = Faye.Class({
|
|
1068
1059
|
Faye.extend(Faye.Subscription.prototype, Faye.Deferrable);
|
1069
1060
|
|
1070
1061
|
Faye.Client = Faye.Class({
|
1071
|
-
UNCONNECTED:
|
1072
|
-
CONNECTING:
|
1073
|
-
CONNECTED:
|
1074
|
-
DISCONNECTED:
|
1062
|
+
UNCONNECTED: 1,
|
1063
|
+
CONNECTING: 2,
|
1064
|
+
CONNECTED: 3,
|
1065
|
+
DISCONNECTED: 4,
|
1075
1066
|
|
1076
|
-
HANDSHAKE:
|
1077
|
-
RETRY:
|
1078
|
-
NONE:
|
1067
|
+
HANDSHAKE: 'handshake',
|
1068
|
+
RETRY: 'retry',
|
1069
|
+
NONE: 'none',
|
1079
1070
|
|
1080
|
-
CONNECTION_TIMEOUT:
|
1081
|
-
DEFAULT_RETRY: 5,
|
1082
|
-
MAX_REQUEST_SIZE: 2048,
|
1071
|
+
CONNECTION_TIMEOUT: 60,
|
1083
1072
|
|
1084
|
-
DEFAULT_ENDPOINT:
|
1085
|
-
INTERVAL:
|
1073
|
+
DEFAULT_ENDPOINT: '/bayeux',
|
1074
|
+
INTERVAL: 0,
|
1086
1075
|
|
1087
1076
|
initialize: function(endpoint, options) {
|
1088
1077
|
this.info('New client created for ?', endpoint);
|
1078
|
+
options = options || {};
|
1089
1079
|
|
1090
|
-
this.
|
1091
|
-
this.
|
1092
|
-
this.
|
1093
|
-
this.transports = {};
|
1094
|
-
this.cookies = Faye.CookieJar && new Faye.CookieJar();
|
1095
|
-
this.headers = {};
|
1096
|
-
this.ca = this._options.ca;
|
1097
|
-
this._disabled = [];
|
1098
|
-
this._retry = this._options.retry || this.DEFAULT_RETRY;
|
1099
|
-
|
1100
|
-
for (var key in this.endpoints)
|
1101
|
-
this.endpoints[key] = Faye.URI.parse(this.endpoints[key]);
|
1102
|
-
|
1103
|
-
this.maxRequestSize = this.MAX_REQUEST_SIZE;
|
1080
|
+
this._endpoint = endpoint || this.DEFAULT_ENDPOINT;
|
1081
|
+
this._channels = new Faye.Channel.Set();
|
1082
|
+
this._dispatcher = new Faye.Dispatcher(this, this._endpoint, options);
|
1104
1083
|
|
1105
|
-
this._state = this.UNCONNECTED;
|
1106
|
-
this._channels = new Faye.Channel.Set();
|
1107
1084
|
this._messageId = 0;
|
1085
|
+
this._state = this.UNCONNECTED;
|
1108
1086
|
|
1109
1087
|
this._responseCallbacks = {};
|
1110
1088
|
|
1111
1089
|
this._advice = {
|
1112
1090
|
reconnect: this.RETRY,
|
1113
|
-
interval: 1000 * (
|
1114
|
-
timeout: 1000 * (
|
1091
|
+
interval: 1000 * (options.interval || this.INTERVAL),
|
1092
|
+
timeout: 1000 * (options.timeout || this.CONNECTION_TIMEOUT)
|
1115
1093
|
};
|
1094
|
+
this._dispatcher.timeout = this._advice.timeout / 1000;
|
1095
|
+
|
1096
|
+
this._dispatcher.bind('message', this._receiveMessage, this);
|
1116
1097
|
|
1117
1098
|
if (Faye.Event && Faye.ENV.onbeforeunload !== undefined)
|
1118
1099
|
Faye.Event.on(Faye.ENV, 'beforeunload', function() {
|
1119
|
-
if (Faye.indexOf(this._disabled, 'autodisconnect') < 0)
|
1100
|
+
if (Faye.indexOf(this._dispatcher._disabled, 'autodisconnect') < 0)
|
1120
1101
|
this.disconnect();
|
1121
1102
|
}, this);
|
1122
1103
|
},
|
1123
1104
|
|
1124
1105
|
disable: function(feature) {
|
1125
|
-
this.
|
1106
|
+
return this._dispatcher.disable(feature);
|
1126
1107
|
},
|
1127
1108
|
|
1128
1109
|
setHeader: function(name, value) {
|
1129
|
-
this.
|
1110
|
+
return this._dispatcher.setHeader(name, value);
|
1130
1111
|
},
|
1131
1112
|
|
1132
1113
|
// Request
|
@@ -1155,30 +1136,30 @@ Faye.Client = Faye.Class({
|
|
1155
1136
|
this._state = this.CONNECTING;
|
1156
1137
|
var self = this;
|
1157
1138
|
|
1158
|
-
this.info('Initiating handshake with ?', Faye.URI.stringify(this.
|
1159
|
-
this.
|
1139
|
+
this.info('Initiating handshake with ?', Faye.URI.stringify(this._endpoint));
|
1140
|
+
this._dispatcher.selectTransport(Faye.MANDATORY_CONNECTION_TYPES);
|
1160
1141
|
|
1161
|
-
this.
|
1142
|
+
this._sendMessage({
|
1162
1143
|
channel: Faye.Channel.HANDSHAKE,
|
1163
1144
|
version: Faye.BAYEUX_VERSION,
|
1164
|
-
supportedConnectionTypes: [this.
|
1145
|
+
supportedConnectionTypes: [this._dispatcher.connectionType]
|
1165
1146
|
|
1166
|
-
}, function(response) {
|
1147
|
+
}, {}, function(response) {
|
1167
1148
|
|
1168
1149
|
if (response.successful) {
|
1169
|
-
this._state
|
1170
|
-
this.
|
1150
|
+
this._state = this.CONNECTED;
|
1151
|
+
this._dispatcher.clientId = response.clientId;
|
1171
1152
|
|
1172
|
-
this.
|
1153
|
+
this._dispatcher.selectTransport(response.supportedConnectionTypes);
|
1173
1154
|
|
1174
|
-
this.info('Handshake successful: ?', this.
|
1155
|
+
this.info('Handshake successful: ?', this._dispatcher.clientId);
|
1175
1156
|
|
1176
1157
|
this.subscribe(this._channels.getKeys(), true);
|
1177
1158
|
if (callback) Faye.Promise.defer(function() { callback.call(context) });
|
1178
1159
|
|
1179
1160
|
} else {
|
1180
1161
|
this.info('Handshake unsuccessful');
|
1181
|
-
Faye.ENV.setTimeout(function() { self.handshake(callback, context) }, this.
|
1162
|
+
Faye.ENV.setTimeout(function() { self.handshake(callback, context) }, this._dispatcher.retry * 1000);
|
1182
1163
|
this._state = this.UNCONNECTED;
|
1183
1164
|
}
|
1184
1165
|
}, this);
|
@@ -1203,21 +1184,21 @@ Faye.Client = Faye.Class({
|
|
1203
1184
|
this.callback(callback, context);
|
1204
1185
|
if (this._state !== this.CONNECTED) return;
|
1205
1186
|
|
1206
|
-
this.info('Calling deferred actions for ?', this.
|
1187
|
+
this.info('Calling deferred actions for ?', this._dispatcher.clientId);
|
1207
1188
|
this.setDeferredStatus('succeeded');
|
1208
1189
|
this.setDeferredStatus('unknown');
|
1209
1190
|
|
1210
1191
|
if (this._connectRequest) return;
|
1211
1192
|
this._connectRequest = true;
|
1212
1193
|
|
1213
|
-
this.info('Initiating connection for ?', this.
|
1194
|
+
this.info('Initiating connection for ?', this._dispatcher.clientId);
|
1214
1195
|
|
1215
|
-
this.
|
1196
|
+
this._sendMessage({
|
1216
1197
|
channel: Faye.Channel.CONNECT,
|
1217
|
-
clientId: this.
|
1218
|
-
connectionType: this.
|
1198
|
+
clientId: this._dispatcher.clientId,
|
1199
|
+
connectionType: this._dispatcher.connectionType
|
1219
1200
|
|
1220
|
-
}, this._cycleConnection, this);
|
1201
|
+
}, {}, this._cycleConnection, this);
|
1221
1202
|
},
|
1222
1203
|
|
1223
1204
|
// Request Response
|
@@ -1231,19 +1212,17 @@ Faye.Client = Faye.Class({
|
|
1231
1212
|
if (this._state !== this.CONNECTED) return;
|
1232
1213
|
this._state = this.DISCONNECTED;
|
1233
1214
|
|
1234
|
-
this.info('Disconnecting ?', this.
|
1215
|
+
this.info('Disconnecting ?', this._dispatcher.clientId);
|
1235
1216
|
|
1236
|
-
this.
|
1217
|
+
this._sendMessage({
|
1237
1218
|
channel: Faye.Channel.DISCONNECT,
|
1238
|
-
clientId: this.
|
1219
|
+
clientId: this._dispatcher.clientId
|
1239
1220
|
|
1240
|
-
}, function(response) {
|
1241
|
-
if (
|
1242
|
-
this._transport.close();
|
1243
|
-
delete this._transport;
|
1221
|
+
}, {}, function(response) {
|
1222
|
+
if (response.successful) this._dispatcher.close();
|
1244
1223
|
}, this);
|
1245
1224
|
|
1246
|
-
this.info('Clearing channel listeners for ?', this.
|
1225
|
+
this.info('Clearing channel listeners for ?', this._dispatcher.clientId);
|
1247
1226
|
this._channels = new Faye.Channel.Set();
|
1248
1227
|
},
|
1249
1228
|
|
@@ -1274,22 +1253,22 @@ Faye.Client = Faye.Class({
|
|
1274
1253
|
}
|
1275
1254
|
|
1276
1255
|
this.connect(function() {
|
1277
|
-
this.info('Client ? attempting to subscribe to ?', this.
|
1256
|
+
this.info('Client ? attempting to subscribe to ?', this._dispatcher.clientId, channel);
|
1278
1257
|
if (!force) this._channels.subscribe([channel], callback, context);
|
1279
1258
|
|
1280
|
-
this.
|
1259
|
+
this._sendMessage({
|
1281
1260
|
channel: Faye.Channel.SUBSCRIBE,
|
1282
|
-
clientId: this.
|
1261
|
+
clientId: this._dispatcher.clientId,
|
1283
1262
|
subscription: channel
|
1284
1263
|
|
1285
|
-
}, function(response) {
|
1264
|
+
}, {}, function(response) {
|
1286
1265
|
if (!response.successful) {
|
1287
1266
|
subscription.setDeferredStatus('failed', Faye.Error.parse(response.error));
|
1288
1267
|
return this._channels.unsubscribe(channel, callback, context);
|
1289
1268
|
}
|
1290
1269
|
|
1291
1270
|
var channels = [].concat(response.subscription);
|
1292
|
-
this.info('Subscription acknowledged for ? to ?', this.
|
1271
|
+
this.info('Subscription acknowledged for ? to ?', this._dispatcher.clientId, channels);
|
1293
1272
|
subscription.setDeferredStatus('succeeded');
|
1294
1273
|
}, this);
|
1295
1274
|
}, this);
|
@@ -1317,18 +1296,18 @@ Faye.Client = Faye.Class({
|
|
1317
1296
|
if (!dead) return;
|
1318
1297
|
|
1319
1298
|
this.connect(function() {
|
1320
|
-
this.info('Client ? attempting to unsubscribe from ?', this.
|
1299
|
+
this.info('Client ? attempting to unsubscribe from ?', this._dispatcher.clientId, channel);
|
1321
1300
|
|
1322
|
-
this.
|
1301
|
+
this._sendMessage({
|
1323
1302
|
channel: Faye.Channel.UNSUBSCRIBE,
|
1324
|
-
clientId: this.
|
1303
|
+
clientId: this._dispatcher.clientId,
|
1325
1304
|
subscription: channel
|
1326
1305
|
|
1327
|
-
}, function(response) {
|
1306
|
+
}, {}, function(response) {
|
1328
1307
|
if (!response.successful) return;
|
1329
1308
|
|
1330
1309
|
var channels = [].concat(response.subscription);
|
1331
|
-
this.info('Unsubscription acknowledged for ? from ?', this.
|
1310
|
+
this.info('Unsubscription acknowledged for ? from ?', this._dispatcher.clientId, channels);
|
1332
1311
|
}, this);
|
1333
1312
|
}, this);
|
1334
1313
|
},
|
@@ -1339,18 +1318,18 @@ Faye.Client = Faye.Class({
|
|
1339
1318
|
// MAY include: * clientId MAY include: * id
|
1340
1319
|
// * id * error
|
1341
1320
|
// * ext * ext
|
1342
|
-
publish: function(channel, data) {
|
1321
|
+
publish: function(channel, data, options) {
|
1343
1322
|
var publication = new Faye.Publication();
|
1344
1323
|
|
1345
1324
|
this.connect(function() {
|
1346
|
-
this.info('Client ? queueing published message to ?: ?', this.
|
1325
|
+
this.info('Client ? queueing published message to ?: ?', this._dispatcher.clientId, channel, data);
|
1347
1326
|
|
1348
|
-
this.
|
1327
|
+
this._sendMessage({
|
1349
1328
|
channel: channel,
|
1350
1329
|
data: data,
|
1351
|
-
clientId: this.
|
1330
|
+
clientId: this._dispatcher.clientId
|
1352
1331
|
|
1353
|
-
}, function(response) {
|
1332
|
+
}, options, function(response) {
|
1354
1333
|
if (response.successful)
|
1355
1334
|
publication.setDeferredStatus('succeeded');
|
1356
1335
|
else
|
@@ -1361,8 +1340,28 @@ Faye.Client = Faye.Class({
|
|
1361
1340
|
return publication;
|
1362
1341
|
},
|
1363
1342
|
|
1364
|
-
|
1365
|
-
|
1343
|
+
_sendMessage: function(message, options, callback, context) {
|
1344
|
+
message.id = this._generateMessageId();
|
1345
|
+
|
1346
|
+
var timeout = this._advice.timeout
|
1347
|
+
? 1.2 * this._advice.timeout / 1000
|
1348
|
+
: 1.2 * this._dispatcher.retry;
|
1349
|
+
|
1350
|
+
this.pipeThroughExtensions('outgoing', message, null, function(message) {
|
1351
|
+
if (!message) return;
|
1352
|
+
if (callback) this._responseCallbacks[message.id] = [callback, context];
|
1353
|
+
this._dispatcher.sendMessage(message, timeout, options || {});
|
1354
|
+
}, this);
|
1355
|
+
},
|
1356
|
+
|
1357
|
+
_generateMessageId: function() {
|
1358
|
+
this._messageId += 1;
|
1359
|
+
if (this._messageId >= Math.pow(2,32)) this._messageId = 0;
|
1360
|
+
return this._messageId.toString(36);
|
1361
|
+
},
|
1362
|
+
|
1363
|
+
_receiveMessage: function(message) {
|
1364
|
+
var id = message.id, callback;
|
1366
1365
|
|
1367
1366
|
if (message.successful !== undefined) {
|
1368
1367
|
callback = this._responseCallbacks[id];
|
@@ -1371,39 +1370,90 @@ Faye.Client = Faye.Class({
|
|
1371
1370
|
|
1372
1371
|
this.pipeThroughExtensions('incoming', message, null, function(message) {
|
1373
1372
|
if (!message) return;
|
1374
|
-
|
1375
1373
|
if (message.advice) this._handleAdvice(message.advice);
|
1376
1374
|
this._deliverMessage(message);
|
1377
|
-
|
1378
1375
|
if (callback) callback[0].call(callback[1], message);
|
1379
1376
|
}, this);
|
1380
|
-
|
1381
|
-
if (this._transportUp === true) return;
|
1382
|
-
this._transportUp = true;
|
1383
|
-
this.trigger('transport:up');
|
1384
1377
|
},
|
1385
1378
|
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
id, message, timeout;
|
1379
|
+
_handleAdvice: function(advice) {
|
1380
|
+
Faye.extend(this._advice, advice);
|
1381
|
+
this._dispatcher.timeout = this._advice.timeout / 1000;
|
1390
1382
|
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1383
|
+
if (this._advice.reconnect === this.HANDSHAKE && this._state !== this.DISCONNECTED) {
|
1384
|
+
this._state = this.UNCONNECTED;
|
1385
|
+
this._dispatcher.clientId = null;
|
1386
|
+
this._cycleConnection();
|
1387
|
+
}
|
1388
|
+
},
|
1394
1389
|
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1390
|
+
_deliverMessage: function(message) {
|
1391
|
+
if (!message.channel || message.data === undefined) return;
|
1392
|
+
this.info('Client ? calling listeners for ? with ?', this._dispatcher.clientId, message.channel, message.data);
|
1393
|
+
this._channels.distributeMessage(message);
|
1394
|
+
},
|
1395
|
+
|
1396
|
+
_cycleConnection: function() {
|
1397
|
+
if (this._connectRequest) {
|
1398
|
+
this._connectRequest = null;
|
1399
|
+
this.info('Closed connection for ?', this._dispatcher.clientId);
|
1399
1400
|
}
|
1401
|
+
var self = this;
|
1402
|
+
Faye.ENV.setTimeout(function() { self.connect() }, this._advice.interval);
|
1403
|
+
}
|
1404
|
+
});
|
1405
|
+
|
1406
|
+
Faye.extend(Faye.Client.prototype, Faye.Deferrable);
|
1407
|
+
Faye.extend(Faye.Client.prototype, Faye.Publisher);
|
1408
|
+
Faye.extend(Faye.Client.prototype, Faye.Logging);
|
1409
|
+
Faye.extend(Faye.Client.prototype, Faye.Extensible);
|
1410
|
+
|
1411
|
+
Faye.Dispatcher = Faye.Class({
|
1412
|
+
MAX_REQUEST_SIZE: 2048,
|
1413
|
+
DEFAULT_RETRY: 5,
|
1414
|
+
|
1415
|
+
UP: 1,
|
1416
|
+
DOWN: 2,
|
1417
|
+
|
1418
|
+
initialize: function(client, endpoint, options) {
|
1419
|
+
this._client = client;
|
1420
|
+
this.endpoint = Faye.URI.parse(endpoint);
|
1421
|
+
this._alternates = options.endpoints || {};
|
1422
|
+
|
1423
|
+
this.ca = options.ca;
|
1424
|
+
this.cookies = Faye.Cookies && new Faye.Cookies.CookieJar();
|
1425
|
+
this._disabled = [];
|
1426
|
+
this._envelopes = {};
|
1427
|
+
this.headers = {};
|
1428
|
+
this.retry = options.retry || this.DEFAULT_RETRY;
|
1429
|
+
this._state = 0;
|
1430
|
+
this.transports = {};
|
1431
|
+
|
1432
|
+
for (var type in this._alternates)
|
1433
|
+
this._alternates[type] = Faye.URI.parse(this._alternates[type]);
|
1434
|
+
|
1435
|
+
this.maxRequestSize = this.MAX_REQUEST_SIZE;
|
1436
|
+
},
|
1400
1437
|
|
1401
|
-
|
1402
|
-
this.
|
1403
|
-
this.trigger('transport:down');
|
1438
|
+
endpointFor: function(connectionType) {
|
1439
|
+
return this._alternates[connectionType] || this.endpoint;
|
1404
1440
|
},
|
1405
1441
|
|
1406
|
-
|
1442
|
+
disable: function(feature) {
|
1443
|
+
this._disabled.push(feature);
|
1444
|
+
},
|
1445
|
+
|
1446
|
+
setHeader: function(name, value) {
|
1447
|
+
this.headers[name] = value;
|
1448
|
+
},
|
1449
|
+
|
1450
|
+
close: function() {
|
1451
|
+
var transport = this._transport;
|
1452
|
+
delete this._transport;
|
1453
|
+
if (transport) transport.close();
|
1454
|
+
},
|
1455
|
+
|
1456
|
+
selectTransport: function(transportTypes) {
|
1407
1457
|
Faye.Transport.get(this, transportTypes, this._disabled, function(transport) {
|
1408
1458
|
this.debug('Selected ? transport for ?', transport.connectionType, Faye.URI.stringify(transport.endpoint));
|
1409
1459
|
|
@@ -1411,186 +1461,220 @@ Faye.Client = Faye.Class({
|
|
1411
1461
|
if (this._transport) this._transport.close();
|
1412
1462
|
|
1413
1463
|
this._transport = transport;
|
1464
|
+
this.connectionType = transport.connectionType;
|
1414
1465
|
}, this);
|
1415
1466
|
},
|
1416
1467
|
|
1417
|
-
|
1468
|
+
sendMessage: function(message, timeout, options) {
|
1418
1469
|
if (!this._transport) return;
|
1419
|
-
|
1470
|
+
options = options || {};
|
1420
1471
|
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
}, this);
|
1426
|
-
},
|
1472
|
+
var self = this,
|
1473
|
+
id = message.id,
|
1474
|
+
attempts = options.attempts,
|
1475
|
+
deadline = options.deadline && new Date().getTime() + (options.deadline * 1000),
|
1427
1476
|
|
1428
|
-
|
1429
|
-
|
1477
|
+
envelope = this._envelopes[id] = this._envelopes[id] ||
|
1478
|
+
{message: message, timeout: timeout, attempts: attempts, deadline: deadline};
|
1430
1479
|
|
1431
|
-
|
1432
|
-
envelope = new Faye.Envelope(message, timeout);
|
1480
|
+
if (envelope.request || envelope.timer) return;
|
1433
1481
|
|
1434
|
-
envelope.
|
1435
|
-
this.
|
1436
|
-
|
1482
|
+
if (this._attemptsExhausted(envelope) || this._deadlinePassed(envelope)) {
|
1483
|
+
delete this._envelopes[id];
|
1484
|
+
return;
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
envelope.timer = Faye.ENV.setTimeout(function() {
|
1488
|
+
self.handleError(message);
|
1489
|
+
}, timeout * 1000);
|
1437
1490
|
|
1438
|
-
this._transport.
|
1491
|
+
envelope.request = this._transport.sendMessage(message);
|
1439
1492
|
},
|
1440
1493
|
|
1441
|
-
|
1442
|
-
this.
|
1443
|
-
|
1444
|
-
|
1494
|
+
handleResponse: function(reply) {
|
1495
|
+
var envelope = this._envelopes[reply.id];
|
1496
|
+
|
1497
|
+
if (reply.successful !== undefined && envelope) {
|
1498
|
+
delete this._envelopes[reply.id];
|
1499
|
+
Faye.ENV.clearTimeout(envelope.timer);
|
1500
|
+
}
|
1501
|
+
|
1502
|
+
this.trigger('message', reply);
|
1503
|
+
|
1504
|
+
if (this._state === this.UP) return;
|
1505
|
+
this._state = this.UP;
|
1506
|
+
this._client.trigger('transport:up');
|
1445
1507
|
},
|
1446
1508
|
|
1447
|
-
|
1448
|
-
|
1509
|
+
handleError: function(message, immediate) {
|
1510
|
+
var envelope = this._envelopes[message.id],
|
1511
|
+
request = envelope && envelope.request,
|
1512
|
+
self = this;
|
1449
1513
|
|
1450
|
-
if (
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1514
|
+
if (!request) return;
|
1515
|
+
|
1516
|
+
request.then(function(req) {
|
1517
|
+
if (req && req.abort) req.abort();
|
1518
|
+
});
|
1519
|
+
|
1520
|
+
Faye.ENV.clearTimeout(envelope.timer);
|
1521
|
+
envelope.request = envelope.timer = null;
|
1522
|
+
|
1523
|
+
if (immediate) {
|
1524
|
+
this.sendMessage(envelope.message, envelope.timeout);
|
1525
|
+
} else {
|
1526
|
+
envelope.timer = Faye.ENV.setTimeout(function() {
|
1527
|
+
envelope.timer = null;
|
1528
|
+
self.sendMessage(envelope.message, envelope.timeout);
|
1529
|
+
}, this.retry * 1000);
|
1454
1530
|
}
|
1531
|
+
|
1532
|
+
if (this._state === this.DOWN) return;
|
1533
|
+
this._state = this.DOWN;
|
1534
|
+
this._client.trigger('transport:down');
|
1455
1535
|
},
|
1456
1536
|
|
1457
|
-
|
1458
|
-
if (
|
1459
|
-
|
1460
|
-
|
1537
|
+
_attemptsExhausted: function(envelope) {
|
1538
|
+
if (envelope.attempts === undefined) return false;
|
1539
|
+
envelope.attempts -= 1;
|
1540
|
+
if (envelope.attempts >= 0) return false;
|
1541
|
+
return true;
|
1461
1542
|
},
|
1462
1543
|
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
var self = this;
|
1469
|
-
Faye.ENV.setTimeout(function() { self.connect() }, this._advice.interval);
|
1544
|
+
_deadlinePassed: function(envelope) {
|
1545
|
+
var deadline = envelope.deadline;
|
1546
|
+
if (deadline === undefined) return false;
|
1547
|
+
if (new Date().getTime() <= deadline) return false;
|
1548
|
+
return true;
|
1470
1549
|
}
|
1471
1550
|
});
|
1472
1551
|
|
1473
|
-
Faye.extend(Faye.
|
1474
|
-
Faye.extend(Faye.
|
1475
|
-
Faye.extend(Faye.Client.prototype, Faye.Logging);
|
1476
|
-
Faye.extend(Faye.Client.prototype, Faye.Extensible);
|
1552
|
+
Faye.extend(Faye.Dispatcher.prototype, Faye.Publisher);
|
1553
|
+
Faye.extend(Faye.Dispatcher.prototype, Faye.Logging);
|
1477
1554
|
|
1478
1555
|
Faye.Transport = Faye.extend(Faye.Class({
|
1479
1556
|
MAX_DELAY: 0,
|
1480
1557
|
batching: true,
|
1481
1558
|
|
1482
|
-
initialize: function(
|
1483
|
-
this.
|
1484
|
-
this.endpoint
|
1485
|
-
this._outbox
|
1559
|
+
initialize: function(dispatcher, endpoint) {
|
1560
|
+
this._dispatcher = dispatcher;
|
1561
|
+
this.endpoint = endpoint;
|
1562
|
+
this._outbox = [];
|
1486
1563
|
},
|
1487
1564
|
|
1488
1565
|
close: function() {},
|
1489
1566
|
|
1490
|
-
encode: function(
|
1567
|
+
encode: function(messages) {
|
1491
1568
|
return '';
|
1492
1569
|
},
|
1493
1570
|
|
1494
|
-
|
1495
|
-
var message = envelope.message;
|
1496
|
-
|
1571
|
+
sendMessage: function(message) {
|
1497
1572
|
this.debug('Client ? sending message to ?: ?',
|
1498
|
-
this.
|
1573
|
+
this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), message);
|
1499
1574
|
|
1500
|
-
if (!this.batching) return this.request([
|
1575
|
+
if (!this.batching) return Faye.Promise.fulfilled(this.request([message]));
|
1501
1576
|
|
1502
|
-
this._outbox.push(
|
1577
|
+
this._outbox.push(message);
|
1578
|
+
this._flushLargeBatch();
|
1579
|
+
this._promise = this._promise || new Faye.Promise();
|
1503
1580
|
|
1504
|
-
if (message.channel === Faye.Channel.HANDSHAKE)
|
1505
|
-
|
1581
|
+
if (message.channel === Faye.Channel.HANDSHAKE) {
|
1582
|
+
this.addTimeout('publish', 0.01, this._flush, this);
|
1583
|
+
return this._promise;
|
1584
|
+
}
|
1506
1585
|
|
1507
1586
|
if (message.channel === Faye.Channel.CONNECT)
|
1508
1587
|
this._connectMessage = message;
|
1509
1588
|
|
1510
|
-
this.
|
1511
|
-
|
1589
|
+
this.addTimeout('publish', this.MAX_DELAY, this._flush, this);
|
1590
|
+
return this._promise;
|
1512
1591
|
},
|
1513
1592
|
|
1514
|
-
|
1593
|
+
_flush: function() {
|
1515
1594
|
this.removeTimeout('publish');
|
1516
1595
|
|
1517
1596
|
if (this._outbox.length > 1 && this._connectMessage)
|
1518
1597
|
this._connectMessage.advice = {timeout: 0};
|
1519
1598
|
|
1520
|
-
this.request(this._outbox);
|
1599
|
+
Faye.Promise.fulfill(this._promise, this.request(this._outbox));
|
1600
|
+
delete this._promise;
|
1521
1601
|
|
1522
1602
|
this._connectMessage = null;
|
1523
1603
|
this._outbox = [];
|
1524
1604
|
},
|
1525
1605
|
|
1526
|
-
|
1606
|
+
_flushLargeBatch: function() {
|
1527
1607
|
var string = this.encode(this._outbox);
|
1528
|
-
if (string.length < this.
|
1608
|
+
if (string.length < this._dispatcher.maxRequestSize) return;
|
1529
1609
|
var last = this._outbox.pop();
|
1530
|
-
this.
|
1610
|
+
this._flush();
|
1531
1611
|
if (last) this._outbox.push(last);
|
1532
1612
|
},
|
1533
1613
|
|
1534
|
-
|
1535
|
-
|
1536
|
-
while (n--) envelopes[n].setDeferredStatus('succeeded');
|
1537
|
-
|
1538
|
-
responses = [].concat(responses);
|
1614
|
+
_receive: function(replies) {
|
1615
|
+
replies = [].concat(replies);
|
1539
1616
|
|
1540
|
-
this.debug('Client ? received from ?: ?',
|
1541
|
-
this.
|
1617
|
+
this.debug('Client ? received from ? via ?: ?',
|
1618
|
+
this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), this.connectionType, replies);
|
1542
1619
|
|
1543
|
-
for (var i = 0, n =
|
1544
|
-
this.
|
1620
|
+
for (var i = 0, n = replies.length; i < n; i++)
|
1621
|
+
this._dispatcher.handleResponse(replies[i]);
|
1545
1622
|
},
|
1546
1623
|
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1624
|
+
_handleError: function(messages, immediate) {
|
1625
|
+
messages = [].concat(messages);
|
1626
|
+
|
1627
|
+
this.debug('Client ? failed to send to ? via ?: ?',
|
1628
|
+
this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), this.connectionType, messages);
|
1629
|
+
|
1630
|
+
for (var i = 0, n = messages.length; i < n; i++)
|
1631
|
+
this._dispatcher.handleError(messages[i]);
|
1550
1632
|
},
|
1551
1633
|
|
1552
1634
|
_getCookies: function() {
|
1553
|
-
var cookies = this.
|
1635
|
+
var cookies = this._dispatcher.cookies,
|
1636
|
+
url = Faye.URI.stringify(this.endpoint);
|
1637
|
+
|
1554
1638
|
if (!cookies) return '';
|
1555
1639
|
|
1556
|
-
return cookies.
|
1557
|
-
|
1558
|
-
|
1559
|
-
secure: this.endpoint.protocol === 'https:'
|
1560
|
-
}).toValueString();
|
1640
|
+
return Faye.map(cookies.getCookiesSync(url), function(cookie) {
|
1641
|
+
return cookie.cookieString();
|
1642
|
+
}).join('; ');
|
1561
1643
|
},
|
1562
1644
|
|
1563
1645
|
_storeCookies: function(setCookie) {
|
1564
|
-
|
1646
|
+
var cookies = this._dispatcher.cookies,
|
1647
|
+
url = Faye.URI.stringify(this.endpoint),
|
1648
|
+
cookie;
|
1649
|
+
|
1650
|
+
if (!setCookie || !cookies) return;
|
1565
1651
|
setCookie = [].concat(setCookie);
|
1566
|
-
var cookie;
|
1567
1652
|
|
1568
1653
|
for (var i = 0, n = setCookie.length; i < n; i++) {
|
1569
|
-
cookie =
|
1570
|
-
cookie
|
1571
|
-
cookie.domain = cookie.domain || this.endpoint.hostname;
|
1654
|
+
cookie = Faye.Cookies.Cookie.parse(setCookie[i]);
|
1655
|
+
cookies.setCookieSync(cookie, url);
|
1572
1656
|
}
|
1573
1657
|
}
|
1574
1658
|
|
1575
1659
|
}), {
|
1576
|
-
get: function(
|
1577
|
-
var endpoint =
|
1660
|
+
get: function(dispatcher, allowed, disabled, callback, context) {
|
1661
|
+
var endpoint = dispatcher.endpoint;
|
1578
1662
|
|
1579
1663
|
Faye.asyncEach(this._transports, function(pair, resume) {
|
1580
1664
|
var connType = pair[0], klass = pair[1],
|
1581
|
-
connEndpoint =
|
1665
|
+
connEndpoint = dispatcher.endpointFor(connType);
|
1582
1666
|
|
1583
1667
|
if (Faye.indexOf(disabled, connType) >= 0)
|
1584
1668
|
return resume();
|
1585
1669
|
|
1586
1670
|
if (Faye.indexOf(allowed, connType) < 0) {
|
1587
|
-
klass.isUsable(
|
1671
|
+
klass.isUsable(dispatcher, connEndpoint, function() {});
|
1588
1672
|
return resume();
|
1589
1673
|
}
|
1590
1674
|
|
1591
|
-
klass.isUsable(
|
1675
|
+
klass.isUsable(dispatcher, connEndpoint, function(isUsable) {
|
1592
1676
|
if (!isUsable) return resume();
|
1593
|
-
var transport = klass.hasOwnProperty('create') ? klass.create(
|
1677
|
+
var transport = klass.hasOwnProperty('create') ? klass.create(dispatcher, connEndpoint) : new klass(dispatcher, connEndpoint);
|
1594
1678
|
callback.call(context, transport);
|
1595
1679
|
});
|
1596
1680
|
}, function() {
|
@@ -2154,16 +2238,23 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2154
2238
|
this.connect();
|
2155
2239
|
},
|
2156
2240
|
|
2157
|
-
request: function(
|
2241
|
+
request: function(messages) {
|
2158
2242
|
this._pending = this._pending || new Faye.Set();
|
2159
|
-
for (var i = 0, n =
|
2243
|
+
for (var i = 0, n = messages.length; i < n; i++) this._pending.add(messages[i]);
|
2244
|
+
|
2245
|
+
var promise = new Faye.Promise();
|
2160
2246
|
|
2161
2247
|
this.callback(function(socket) {
|
2162
2248
|
if (!socket) return;
|
2163
|
-
var messages = Faye.map(envelopes, function(e) { return e.message });
|
2164
2249
|
socket.send(Faye.toJSON(messages));
|
2250
|
+
Faye.Promise.fulfill(promise, socket);
|
2165
2251
|
}, this);
|
2252
|
+
|
2166
2253
|
this.connect();
|
2254
|
+
|
2255
|
+
return {
|
2256
|
+
abort: function() { promise.then(function(ws) { ws.close() }) }
|
2257
|
+
};
|
2167
2258
|
},
|
2168
2259
|
|
2169
2260
|
connect: function() {
|
@@ -2204,28 +2295,25 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2204
2295
|
delete self._pending;
|
2205
2296
|
|
2206
2297
|
if (wasConnected) {
|
2207
|
-
self.
|
2298
|
+
self._handleError(pending, true);
|
2208
2299
|
} else if (self._everConnected) {
|
2209
|
-
self.
|
2300
|
+
self._handleError(pending);
|
2210
2301
|
} else {
|
2211
2302
|
self.setDeferredStatus('failed');
|
2212
2303
|
}
|
2213
2304
|
};
|
2214
2305
|
|
2215
2306
|
socket.onmessage = function(event) {
|
2216
|
-
var
|
2217
|
-
|
2218
|
-
envelope;
|
2307
|
+
var replies = JSON.parse(event.data);
|
2308
|
+
if (!replies) return;
|
2219
2309
|
|
2220
|
-
|
2221
|
-
messages = [].concat(messages);
|
2310
|
+
replies = [].concat(replies);
|
2222
2311
|
|
2223
|
-
for (var i = 0, n =
|
2224
|
-
if (
|
2225
|
-
|
2226
|
-
if (envelope) envelopes.push(envelope);
|
2312
|
+
for (var i = 0, n = replies.length; i < n; i++) {
|
2313
|
+
if (replies[i].successful === undefined) continue;
|
2314
|
+
self._pending.remove(replies[i]);
|
2227
2315
|
}
|
2228
|
-
self.
|
2316
|
+
self._receive(replies);
|
2229
2317
|
};
|
2230
2318
|
},
|
2231
2319
|
|
@@ -2236,7 +2324,8 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2236
2324
|
|
2237
2325
|
_createSocket: function() {
|
2238
2326
|
var url = Faye.Transport.WebSocket.getSocketUrl(this.endpoint),
|
2239
|
-
|
2327
|
+
headers = Faye.copyObject(this._dispatcher.headers),
|
2328
|
+
options = {headers: headers, ca: this._dispatcher.ca};
|
2240
2329
|
|
2241
2330
|
options.headers['Cookie'] = this._getCookies();
|
2242
2331
|
|
@@ -2248,7 +2337,7 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2248
2337
|
_ping: function() {
|
2249
2338
|
if (!this._socket) return;
|
2250
2339
|
this._socket.send('[]');
|
2251
|
-
this.addTimeout('ping', this.
|
2340
|
+
this.addTimeout('ping', this._dispatcher.timeout / 2, this._ping, this);
|
2252
2341
|
}
|
2253
2342
|
|
2254
2343
|
}), {
|
@@ -2257,9 +2346,9 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2257
2346
|
'https:': 'wss:'
|
2258
2347
|
},
|
2259
2348
|
|
2260
|
-
create: function(
|
2261
|
-
var sockets =
|
2262
|
-
sockets[endpoint.href] = sockets[endpoint.href] || new this(
|
2349
|
+
create: function(dispatcher, endpoint) {
|
2350
|
+
var sockets = dispatcher.transports.websocket = dispatcher.transports.websocket || {};
|
2351
|
+
sockets[endpoint.href] = sockets[endpoint.href] || new this(dispatcher, endpoint);
|
2263
2352
|
return sockets[endpoint.href];
|
2264
2353
|
},
|
2265
2354
|
|
@@ -2269,28 +2358,28 @@ Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2269
2358
|
return Faye.URI.stringify(endpoint);
|
2270
2359
|
},
|
2271
2360
|
|
2272
|
-
isUsable: function(
|
2273
|
-
this.create(
|
2361
|
+
isUsable: function(dispatcher, endpoint, callback, context) {
|
2362
|
+
this.create(dispatcher, endpoint).isUsable(callback, context);
|
2274
2363
|
}
|
2275
2364
|
});
|
2276
2365
|
|
2277
2366
|
Faye.extend(Faye.Transport.WebSocket.prototype, Faye.Deferrable);
|
2278
2367
|
Faye.Transport.register('websocket', Faye.Transport.WebSocket);
|
2279
2368
|
|
2280
|
-
if (Faye.Event)
|
2369
|
+
if (Faye.Event && Faye.ENV.onbeforeunload !== undefined)
|
2281
2370
|
Faye.Event.on(Faye.ENV, 'beforeunload', function() {
|
2282
2371
|
Faye.Transport.WebSocket._unloaded = true;
|
2283
2372
|
});
|
2284
2373
|
|
2285
2374
|
Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
|
2286
|
-
initialize: function(
|
2287
|
-
Faye.Transport.prototype.initialize.call(this,
|
2375
|
+
initialize: function(dispatcher, endpoint) {
|
2376
|
+
Faye.Transport.prototype.initialize.call(this, dispatcher, endpoint);
|
2288
2377
|
if (!Faye.ENV.EventSource) return this.setDeferredStatus('failed');
|
2289
2378
|
|
2290
|
-
this._xhr = new Faye.Transport.XHR(
|
2379
|
+
this._xhr = new Faye.Transport.XHR(dispatcher, endpoint);
|
2291
2380
|
|
2292
2381
|
endpoint = Faye.copyObject(endpoint);
|
2293
|
-
endpoint.pathname += '/' +
|
2382
|
+
endpoint.pathname += '/' + dispatcher.clientId;
|
2294
2383
|
|
2295
2384
|
var socket = new EventSource(Faye.URI.stringify(endpoint)),
|
2296
2385
|
self = this;
|
@@ -2302,7 +2391,7 @@ Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2302
2391
|
|
2303
2392
|
socket.onerror = function() {
|
2304
2393
|
if (self._everConnected) {
|
2305
|
-
self.
|
2394
|
+
self._handleError([]);
|
2306
2395
|
} else {
|
2307
2396
|
self.setDeferredStatus('failed');
|
2308
2397
|
socket.close();
|
@@ -2310,7 +2399,7 @@ Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2310
2399
|
};
|
2311
2400
|
|
2312
2401
|
socket.onmessage = function(event) {
|
2313
|
-
self.
|
2402
|
+
self._receive(JSON.parse(event.data));
|
2314
2403
|
};
|
2315
2404
|
|
2316
2405
|
this._socket = socket;
|
@@ -2328,34 +2417,34 @@ Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2328
2417
|
this.errback(function() { callback.call(context, false) });
|
2329
2418
|
},
|
2330
2419
|
|
2331
|
-
encode: function(
|
2332
|
-
return this._xhr.encode(
|
2420
|
+
encode: function(messages) {
|
2421
|
+
return this._xhr.encode(messages);
|
2333
2422
|
},
|
2334
2423
|
|
2335
|
-
request: function(
|
2336
|
-
this._xhr.request(
|
2424
|
+
request: function(messages) {
|
2425
|
+
return this._xhr.request(messages);
|
2337
2426
|
}
|
2338
2427
|
|
2339
2428
|
}), {
|
2340
|
-
isUsable: function(
|
2341
|
-
var id =
|
2429
|
+
isUsable: function(dispatcher, endpoint, callback, context) {
|
2430
|
+
var id = dispatcher.clientId;
|
2342
2431
|
if (!id) return callback.call(context, false);
|
2343
2432
|
|
2344
|
-
Faye.Transport.XHR.isUsable(
|
2433
|
+
Faye.Transport.XHR.isUsable(dispatcher, endpoint, function(usable) {
|
2345
2434
|
if (!usable) return callback.call(context, false);
|
2346
|
-
this.create(
|
2435
|
+
this.create(dispatcher, endpoint).isUsable(callback, context);
|
2347
2436
|
}, this);
|
2348
2437
|
},
|
2349
2438
|
|
2350
|
-
create: function(
|
2351
|
-
var sockets =
|
2352
|
-
id =
|
2439
|
+
create: function(dispatcher, endpoint) {
|
2440
|
+
var sockets = dispatcher.transports.eventsource = dispatcher.transports.eventsource || {},
|
2441
|
+
id = dispatcher.clientId;
|
2353
2442
|
|
2354
2443
|
endpoint = Faye.copyObject(endpoint);
|
2355
2444
|
endpoint.pathname += '/' + (id || '');
|
2356
2445
|
var url = Faye.URI.stringify(endpoint);
|
2357
2446
|
|
2358
|
-
sockets[url] = sockets[url] || new this(
|
2447
|
+
sockets[url] = sockets[url] || new this(dispatcher, endpoint);
|
2359
2448
|
return sockets[url];
|
2360
2449
|
}
|
2361
2450
|
});
|
@@ -2364,58 +2453,58 @@ Faye.extend(Faye.Transport.EventSource.prototype, Faye.Deferrable);
|
|
2364
2453
|
Faye.Transport.register('eventsource', Faye.Transport.EventSource);
|
2365
2454
|
|
2366
2455
|
Faye.Transport.XHR = Faye.extend(Faye.Class(Faye.Transport, {
|
2367
|
-
encode: function(
|
2368
|
-
var messages = Faye.map(envelopes, function(e) { return e.message });
|
2456
|
+
encode: function(messages) {
|
2369
2457
|
return Faye.toJSON(messages);
|
2370
2458
|
},
|
2371
2459
|
|
2372
|
-
request: function(
|
2373
|
-
var
|
2460
|
+
request: function(messages) {
|
2461
|
+
var href = this.endpoint.href,
|
2374
2462
|
xhr = Faye.ENV.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest(),
|
2375
2463
|
self = this;
|
2376
2464
|
|
2377
|
-
xhr.open('POST',
|
2465
|
+
xhr.open('POST', href, true);
|
2378
2466
|
xhr.setRequestHeader('Content-Type', 'application/json');
|
2379
2467
|
xhr.setRequestHeader('Pragma', 'no-cache');
|
2380
2468
|
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
2381
2469
|
|
2382
|
-
var headers = this.
|
2470
|
+
var headers = this._dispatcher.headers;
|
2383
2471
|
for (var key in headers) {
|
2384
2472
|
if (!headers.hasOwnProperty(key)) continue;
|
2385
2473
|
xhr.setRequestHeader(key, headers[key]);
|
2386
2474
|
}
|
2387
2475
|
|
2388
2476
|
var abort = function() { xhr.abort() };
|
2389
|
-
Faye.Event.on(Faye.ENV, 'beforeunload', abort);
|
2477
|
+
if (Faye.ENV.onbeforeunload !== undefined) Faye.Event.on(Faye.ENV, 'beforeunload', abort);
|
2390
2478
|
|
2391
2479
|
xhr.onreadystatechange = function() {
|
2392
2480
|
if (!xhr || xhr.readyState !== 4) return;
|
2393
2481
|
|
2394
|
-
var
|
2395
|
-
status
|
2396
|
-
text
|
2397
|
-
successful
|
2482
|
+
var replies = null,
|
2483
|
+
status = xhr.status,
|
2484
|
+
text = xhr.responseText,
|
2485
|
+
successful = (status >= 200 && status < 300) || status === 304 || status === 1223;
|
2398
2486
|
|
2399
|
-
Faye.Event.detach(Faye.ENV, 'beforeunload', abort);
|
2487
|
+
if (Faye.ENV.onbeforeunload !== undefined) Faye.Event.detach(Faye.ENV, 'beforeunload', abort);
|
2400
2488
|
xhr.onreadystatechange = function() {};
|
2401
2489
|
xhr = null;
|
2402
2490
|
|
2403
|
-
if (!successful) return self.
|
2491
|
+
if (!successful) return self._handleError(messages);
|
2404
2492
|
|
2405
2493
|
try {
|
2406
|
-
|
2494
|
+
replies = JSON.parse(text);
|
2407
2495
|
} catch (e) {}
|
2408
2496
|
|
2409
|
-
if (
|
2410
|
-
self.
|
2497
|
+
if (replies)
|
2498
|
+
self._receive(replies);
|
2411
2499
|
else
|
2412
|
-
self.
|
2500
|
+
self._handleError(messages);
|
2413
2501
|
};
|
2414
2502
|
|
2415
|
-
xhr.send(this.encode(
|
2503
|
+
xhr.send(this.encode(messages));
|
2504
|
+
return xhr;
|
2416
2505
|
}
|
2417
2506
|
}), {
|
2418
|
-
isUsable: function(
|
2507
|
+
isUsable: function(dispatcher, endpoint, callback, context) {
|
2419
2508
|
callback.call(context, Faye.URI.isSameOrigin(endpoint));
|
2420
2509
|
}
|
2421
2510
|
});
|
@@ -2423,15 +2512,14 @@ Faye.Transport.XHR = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2423
2512
|
Faye.Transport.register('long-polling', Faye.Transport.XHR);
|
2424
2513
|
|
2425
2514
|
Faye.Transport.CORS = Faye.extend(Faye.Class(Faye.Transport, {
|
2426
|
-
encode: function(
|
2427
|
-
var messages = Faye.map(envelopes, function(e) { return e.message });
|
2515
|
+
encode: function(messages) {
|
2428
2516
|
return 'message=' + encodeURIComponent(Faye.toJSON(messages));
|
2429
2517
|
},
|
2430
2518
|
|
2431
|
-
request: function(
|
2519
|
+
request: function(messages) {
|
2432
2520
|
var xhrClass = Faye.ENV.XDomainRequest ? XDomainRequest : XMLHttpRequest,
|
2433
2521
|
xhr = new xhrClass(),
|
2434
|
-
headers = this.
|
2522
|
+
headers = this._dispatcher.headers,
|
2435
2523
|
self = this,
|
2436
2524
|
key;
|
2437
2525
|
|
@@ -2452,29 +2540,30 @@ Faye.Transport.CORS = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2452
2540
|
};
|
2453
2541
|
|
2454
2542
|
xhr.onload = function() {
|
2455
|
-
var
|
2543
|
+
var replies = null;
|
2456
2544
|
try {
|
2457
|
-
|
2545
|
+
replies = JSON.parse(xhr.responseText);
|
2458
2546
|
} catch (e) {}
|
2459
2547
|
|
2460
2548
|
cleanUp();
|
2461
2549
|
|
2462
|
-
if (
|
2463
|
-
self.
|
2550
|
+
if (replies)
|
2551
|
+
self._receive(replies);
|
2464
2552
|
else
|
2465
|
-
self.
|
2553
|
+
self._handleError(messages);
|
2466
2554
|
};
|
2467
2555
|
|
2468
2556
|
xhr.onerror = xhr.ontimeout = function() {
|
2469
2557
|
cleanUp();
|
2470
|
-
self.
|
2558
|
+
self._handleError(messages);
|
2471
2559
|
};
|
2472
2560
|
|
2473
2561
|
xhr.onprogress = function() {};
|
2474
|
-
xhr.send(this.encode(
|
2562
|
+
xhr.send(this.encode(messages));
|
2563
|
+
return xhr;
|
2475
2564
|
}
|
2476
2565
|
}), {
|
2477
|
-
isUsable: function(
|
2566
|
+
isUsable: function(dispatcher, endpoint, callback, context) {
|
2478
2567
|
if (Faye.URI.isSameOrigin(endpoint))
|
2479
2568
|
return callback.call(context, false);
|
2480
2569
|
|
@@ -2492,17 +2581,15 @@ Faye.Transport.CORS = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2492
2581
|
Faye.Transport.register('cross-origin-long-polling', Faye.Transport.CORS);
|
2493
2582
|
|
2494
2583
|
Faye.Transport.JSONP = Faye.extend(Faye.Class(Faye.Transport, {
|
2495
|
-
encode: function(
|
2496
|
-
var messages = Faye.map(envelopes, function(e) { return e.message });
|
2584
|
+
encode: function(messages) {
|
2497
2585
|
var url = Faye.copyObject(this.endpoint);
|
2498
2586
|
url.query.message = Faye.toJSON(messages);
|
2499
2587
|
url.query.jsonp = '__jsonp' + Faye.Transport.JSONP._cbCount + '__';
|
2500
2588
|
return Faye.URI.stringify(url);
|
2501
2589
|
},
|
2502
2590
|
|
2503
|
-
request: function(
|
2504
|
-
var
|
2505
|
-
head = document.getElementsByTagName('head')[0],
|
2591
|
+
request: function(messages) {
|
2592
|
+
var head = document.getElementsByTagName('head')[0],
|
2506
2593
|
script = document.createElement('script'),
|
2507
2594
|
callbackName = Faye.Transport.JSONP.getCallbackName(),
|
2508
2595
|
endpoint = Faye.copyObject(this.endpoint),
|
@@ -2511,17 +2598,28 @@ Faye.Transport.JSONP = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2511
2598
|
endpoint.query.message = Faye.toJSON(messages);
|
2512
2599
|
endpoint.query.jsonp = callbackName;
|
2513
2600
|
|
2514
|
-
|
2601
|
+
var cleanup = function() {
|
2515
2602
|
if (!Faye.ENV[callbackName]) return false;
|
2516
2603
|
Faye.ENV[callbackName] = undefined;
|
2517
2604
|
try { delete Faye.ENV[callbackName] } catch (e) {}
|
2518
2605
|
script.parentNode.removeChild(script);
|
2519
|
-
|
2606
|
+
};
|
2607
|
+
|
2608
|
+
Faye.ENV[callbackName] = function(replies) {
|
2609
|
+
cleanup();
|
2610
|
+
self._receive(replies);
|
2520
2611
|
};
|
2521
2612
|
|
2522
2613
|
script.type = 'text/javascript';
|
2523
2614
|
script.src = Faye.URI.stringify(endpoint);
|
2524
2615
|
head.appendChild(script);
|
2616
|
+
|
2617
|
+
script.onerror = function() {
|
2618
|
+
cleanup();
|
2619
|
+
self._handleError(messages);
|
2620
|
+
};
|
2621
|
+
|
2622
|
+
return {abort: cleanup};
|
2525
2623
|
}
|
2526
2624
|
}), {
|
2527
2625
|
_cbCount: 0,
|
@@ -2531,11 +2629,11 @@ Faye.Transport.JSONP = Faye.extend(Faye.Class(Faye.Transport, {
|
|
2531
2629
|
return '__jsonp' + this._cbCount + '__';
|
2532
2630
|
},
|
2533
2631
|
|
2534
|
-
isUsable: function(
|
2632
|
+
isUsable: function(dispatcher, endpoint, callback, context) {
|
2535
2633
|
callback.call(context, true);
|
2536
2634
|
}
|
2537
2635
|
});
|
2538
2636
|
|
2539
2637
|
Faye.Transport.register('callback-polling', Faye.Transport.JSONP);
|
2540
2638
|
|
2541
|
-
})();
|
2639
|
+
})();
|