pusher_rails 0.1.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.
- data/README.md +9 -0
- data/pusher_rails-0.1.0.gem +0 -0
- data/pusher_rails.gemspec +11 -0
- data/vendor/assets/javascripts/pusher.js +1037 -0
- metadata +48 -0
data/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = 'pusher_rails'
|
|
3
|
+
s.version = '0.1.0'
|
|
4
|
+
s.author = 'David Grandinetti'
|
|
5
|
+
s.email = 'dave@wegoto12.com'
|
|
6
|
+
s.summary = 'Pusher integration for Rails 3.1+'
|
|
7
|
+
s.description = 'Adds pusher.js to the asset pipeline'
|
|
8
|
+
s.homepage = 'https://github.com/dbgrandi/pusher_rails'
|
|
9
|
+
|
|
10
|
+
s.files = Dir["#{File.dirname(__FILE__)}/**/*"]
|
|
11
|
+
end
|
|
@@ -0,0 +1,1037 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Pusher JavaScript Library v1.9.1
|
|
3
|
+
* http://pusherapp.com/
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2011, Pusher
|
|
6
|
+
* Released under the MIT licence.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
if (typeof Function.prototype.scopedTo === 'undefined') {
|
|
10
|
+
Function.prototype.scopedTo = function(context, args) {
|
|
11
|
+
var f = this;
|
|
12
|
+
return function() {
|
|
13
|
+
return f.apply(context, Array.prototype.slice.call(args || [])
|
|
14
|
+
.concat(Array.prototype.slice.call(arguments)));
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
var Pusher = function(app_key, options) {
|
|
20
|
+
this.options = options || {};
|
|
21
|
+
this.path = '/app/' + app_key + '?client=js&version=' + Pusher.VERSION;
|
|
22
|
+
this.key = app_key;
|
|
23
|
+
this.channels = new Pusher.Channels();
|
|
24
|
+
this.global_channel = new Pusher.Channel('pusher_global_channel');
|
|
25
|
+
this.global_channel.global = true;
|
|
26
|
+
|
|
27
|
+
var self = this;
|
|
28
|
+
|
|
29
|
+
this.connection = new Pusher.Connection(this.key, this.options);
|
|
30
|
+
|
|
31
|
+
// Setup / teardown connection
|
|
32
|
+
this.connection
|
|
33
|
+
.bind('connected', function() {
|
|
34
|
+
self.subscribeAll();
|
|
35
|
+
})
|
|
36
|
+
.bind('message', function(params) {
|
|
37
|
+
self.send_local_event(params.event, params.data, params.channel);
|
|
38
|
+
})
|
|
39
|
+
.bind('disconnected', function() {
|
|
40
|
+
self.channels.disconnect();
|
|
41
|
+
})
|
|
42
|
+
.bind('error', function(err) {
|
|
43
|
+
Pusher.debug('Error', err);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
Pusher.instances.push(this);
|
|
47
|
+
|
|
48
|
+
if (Pusher.isReady) self.connect();
|
|
49
|
+
};
|
|
50
|
+
Pusher.instances = [];
|
|
51
|
+
Pusher.prototype = {
|
|
52
|
+
channel: function(name) {
|
|
53
|
+
return this.channels.find(name);
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
connect: function() {
|
|
57
|
+
this.connection.connect();
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
disconnect: function() {
|
|
61
|
+
Pusher.debug('Disconnecting');
|
|
62
|
+
this.connection.disconnect();
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
bind: function(event_name, callback) {
|
|
66
|
+
this.global_channel.bind(event_name, callback);
|
|
67
|
+
return this;
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
bind_all: function(callback) {
|
|
71
|
+
this.global_channel.bind_all(callback);
|
|
72
|
+
return this;
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
subscribeAll: function() {
|
|
76
|
+
var channel;
|
|
77
|
+
for (channel in this.channels.channels) {
|
|
78
|
+
if (this.channels.channels.hasOwnProperty(channel)) {
|
|
79
|
+
this.subscribe(channel);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
subscribe: function(channel_name) {
|
|
85
|
+
var self = this;
|
|
86
|
+
var channel = this.channels.add(channel_name, this);
|
|
87
|
+
if (this.connection.state === 'connected') {
|
|
88
|
+
channel.authorize(this, function(data) {
|
|
89
|
+
self.send_event('pusher:subscribe', {
|
|
90
|
+
channel: channel_name,
|
|
91
|
+
auth: data.auth,
|
|
92
|
+
channel_data: data.channel_data
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return channel;
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
unsubscribe: function(channel_name) {
|
|
100
|
+
this.channels.remove(channel_name);
|
|
101
|
+
if (this.connection.state === 'connected') {
|
|
102
|
+
this.send_event('pusher:unsubscribe', {
|
|
103
|
+
channel: channel_name
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
send_event: function(event_name, data, channel) {
|
|
109
|
+
Pusher.debug("Event sent (channel,event,data)", channel, event_name, data);
|
|
110
|
+
|
|
111
|
+
var payload = {
|
|
112
|
+
event: event_name,
|
|
113
|
+
data: data
|
|
114
|
+
};
|
|
115
|
+
if (channel) payload['channel'] = channel;
|
|
116
|
+
|
|
117
|
+
this.connection.send(JSON.stringify(payload));
|
|
118
|
+
return this;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
send_local_event: function(event_name, event_data, channel_name) {
|
|
122
|
+
event_data = Pusher.data_decorator(event_name, event_data);
|
|
123
|
+
if (channel_name) {
|
|
124
|
+
var channel = this.channel(channel_name);
|
|
125
|
+
if (channel) {
|
|
126
|
+
channel.dispatch_with_all(event_name, event_data);
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
// Bit hacky but these events won't get logged otherwise
|
|
130
|
+
Pusher.debug("Event recd (event,data)", event_name, event_data);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.global_channel.dispatch_with_all(event_name, event_data);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
Pusher.Util = {
|
|
138
|
+
extend: function extend(target, extensions) {
|
|
139
|
+
for (var property in extensions) {
|
|
140
|
+
if (extensions[property] && extensions[property].constructor &&
|
|
141
|
+
extensions[property].constructor === Object) {
|
|
142
|
+
target[property] = extend(target[property] || {}, extensions[property]);
|
|
143
|
+
} else {
|
|
144
|
+
target[property] = extensions[property];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return target;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// To receive log output provide a Pusher.log function, for example
|
|
152
|
+
// Pusher.log = function(m){console.log(m)}
|
|
153
|
+
Pusher.debug = function() {
|
|
154
|
+
if (!Pusher.log) { return }
|
|
155
|
+
var m = ["Pusher"]
|
|
156
|
+
for (var i = 0; i < arguments.length; i++){
|
|
157
|
+
if (typeof arguments[i] === "string") {
|
|
158
|
+
m.push(arguments[i])
|
|
159
|
+
} else {
|
|
160
|
+
if (window['JSON'] == undefined) {
|
|
161
|
+
m.push(arguments[i].toString());
|
|
162
|
+
} else {
|
|
163
|
+
m.push(JSON.stringify(arguments[i]))
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
Pusher.log(m.join(" : "))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Pusher defaults
|
|
171
|
+
Pusher.VERSION = '1.9.1';
|
|
172
|
+
|
|
173
|
+
Pusher.host = 'ws.pusherapp.com';
|
|
174
|
+
Pusher.ws_port = 80;
|
|
175
|
+
Pusher.wss_port = 443;
|
|
176
|
+
Pusher.channel_auth_endpoint = '/pusher/auth';
|
|
177
|
+
Pusher.connection_timeout = 5000;
|
|
178
|
+
Pusher.cdn_http = 'http://js.pusherapp.com/'
|
|
179
|
+
Pusher.cdn_https = 'https://d3ds63zw57jt09.cloudfront.net/'
|
|
180
|
+
Pusher.data_decorator = function(event_name, event_data){ return event_data }; // wrap event_data before dispatching
|
|
181
|
+
Pusher.allow_reconnect = true;
|
|
182
|
+
Pusher.channel_auth_transport = 'ajax';
|
|
183
|
+
|
|
184
|
+
Pusher.isReady = false;
|
|
185
|
+
Pusher.ready = function() {
|
|
186
|
+
Pusher.isReady = true;
|
|
187
|
+
for (var i = 0, l = Pusher.instances.length; i < l; i++) {
|
|
188
|
+
Pusher.instances[i].connect();
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
;(function() {
|
|
193
|
+
/* Abstract event binding
|
|
194
|
+
Example:
|
|
195
|
+
|
|
196
|
+
var MyEventEmitter = function(){};
|
|
197
|
+
MyEventEmitter.prototype = new Pusher.EventsDispatcher;
|
|
198
|
+
|
|
199
|
+
var emitter = new MyEventEmitter();
|
|
200
|
+
|
|
201
|
+
// Bind to single event
|
|
202
|
+
emitter.bind('foo_event', function(data){ alert(data)} );
|
|
203
|
+
|
|
204
|
+
// Bind to all
|
|
205
|
+
emitter.bind_all(function(event_name, data){ alert(data) });
|
|
206
|
+
|
|
207
|
+
--------------------------------------------------------*/
|
|
208
|
+
function EventsDispatcher() {
|
|
209
|
+
this.callbacks = {};
|
|
210
|
+
this.global_callbacks = [];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
EventsDispatcher.prototype.bind = function(event_name, callback) {
|
|
214
|
+
this.callbacks[event_name] = this.callbacks[event_name] || [];
|
|
215
|
+
this.callbacks[event_name].push(callback);
|
|
216
|
+
return this;// chainable
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
EventsDispatcher.prototype.emit = function(event_name, data) {
|
|
220
|
+
this.dispatch_global_callbacks(event_name, data);
|
|
221
|
+
this.dispatch(event_name, data);
|
|
222
|
+
return this;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
EventsDispatcher.prototype.bind_all = function(callback) {
|
|
226
|
+
this.global_callbacks.push(callback);
|
|
227
|
+
return this;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
EventsDispatcher.prototype.dispatch = function(event_name, event_data) {
|
|
231
|
+
var callbacks = this.callbacks[event_name];
|
|
232
|
+
|
|
233
|
+
if (callbacks) {
|
|
234
|
+
for (var i = 0; i < callbacks.length; i++) {
|
|
235
|
+
callbacks[i](event_data);
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
// Log is un-necessary in case of global channel or connection object
|
|
239
|
+
if (!(this.global || this instanceof Pusher.Connection || this instanceof Pusher.Machine)) {
|
|
240
|
+
Pusher.debug('No callbacks for ' + event_name, event_data);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
EventsDispatcher.prototype.dispatch_global_callbacks = function(event_name, data) {
|
|
246
|
+
for (var i = 0; i < this.global_callbacks.length; i++) {
|
|
247
|
+
this.global_callbacks[i](event_name, data);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
EventsDispatcher.prototype.dispatch_with_all = function(event_name, data) {
|
|
252
|
+
this.dispatch(event_name, data);
|
|
253
|
+
this.dispatch_global_callbacks(event_name, data);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
this.Pusher.EventsDispatcher = EventsDispatcher;
|
|
257
|
+
}).call(this);
|
|
258
|
+
|
|
259
|
+
;(function() {
|
|
260
|
+
var Pusher = this.Pusher;
|
|
261
|
+
|
|
262
|
+
/*-----------------------------------------------
|
|
263
|
+
Helpers:
|
|
264
|
+
-----------------------------------------------*/
|
|
265
|
+
|
|
266
|
+
// MSIE doesn't have array.indexOf
|
|
267
|
+
var nativeIndexOf = Array.prototype.indexOf;
|
|
268
|
+
function indexOf(array, item) {
|
|
269
|
+
if (array == null) return -1;
|
|
270
|
+
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
|
|
271
|
+
for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
|
|
272
|
+
return -1;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
function capitalize(str) {
|
|
277
|
+
return str.substr(0, 1).toUpperCase() + str.substr(1);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
function safeCall(method, obj, data) {
|
|
282
|
+
if (obj[method] !== undefined) {
|
|
283
|
+
obj[method](data);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/*-----------------------------------------------
|
|
288
|
+
The State Machine
|
|
289
|
+
-----------------------------------------------*/
|
|
290
|
+
function Machine(actor, initialState, transitions, stateActions) {
|
|
291
|
+
Pusher.EventsDispatcher.call(this);
|
|
292
|
+
|
|
293
|
+
this.actor = actor;
|
|
294
|
+
this.state = undefined;
|
|
295
|
+
this.errors = [];
|
|
296
|
+
|
|
297
|
+
// functions for each state
|
|
298
|
+
this.stateActions = stateActions;
|
|
299
|
+
|
|
300
|
+
// set up the transitions
|
|
301
|
+
this.transitions = transitions;
|
|
302
|
+
|
|
303
|
+
this.transition(initialState);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
Machine.prototype.transition = function(nextState, data) {
|
|
307
|
+
var prevState = this.state;
|
|
308
|
+
var stateCallbacks = this.stateActions;
|
|
309
|
+
|
|
310
|
+
if (prevState && (indexOf(this.transitions[prevState], nextState) == -1)) {
|
|
311
|
+
throw new Error(this.actor.key + ': Invalid transition [' + prevState + ' to ' + nextState + ']');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// exit
|
|
315
|
+
safeCall(prevState + 'Exit', stateCallbacks, data);
|
|
316
|
+
|
|
317
|
+
// tween
|
|
318
|
+
safeCall(prevState + 'To' + capitalize(nextState), stateCallbacks, data);
|
|
319
|
+
|
|
320
|
+
// pre
|
|
321
|
+
safeCall(nextState + 'Pre', stateCallbacks, data);
|
|
322
|
+
|
|
323
|
+
// change state:
|
|
324
|
+
this.state = nextState;
|
|
325
|
+
|
|
326
|
+
// handy to bind to
|
|
327
|
+
this.emit('state_change', {
|
|
328
|
+
oldState: prevState,
|
|
329
|
+
newState: nextState
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Post:
|
|
333
|
+
safeCall(nextState + 'Post', stateCallbacks, data);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
Machine.prototype.is = function(state) {
|
|
337
|
+
return this.state === state;
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
Machine.prototype.isNot = function(state) {
|
|
341
|
+
return this.state !== state;
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
Pusher.Util.extend(Machine.prototype, Pusher.EventsDispatcher.prototype);
|
|
345
|
+
|
|
346
|
+
this.Pusher.Machine = Machine;
|
|
347
|
+
}).call(this);
|
|
348
|
+
|
|
349
|
+
;(function() {
|
|
350
|
+
var Pusher = this.Pusher;
|
|
351
|
+
|
|
352
|
+
var machineTransitions = {
|
|
353
|
+
'initialized': ['waiting', 'failed'],
|
|
354
|
+
'waiting': ['connecting', 'permanentlyClosed'],
|
|
355
|
+
'connecting': ['open', 'permanentlyClosing', 'impermanentlyClosing', 'waiting'],
|
|
356
|
+
'open': ['connected', 'permanentlyClosing', 'impermanentlyClosing', 'waiting'],
|
|
357
|
+
'connected': ['permanentlyClosing', 'impermanentlyClosing', 'waiting'],
|
|
358
|
+
'impermanentlyClosing': ['waiting', 'permanentlyClosing'],
|
|
359
|
+
'permanentlyClosing': ['permanentlyClosed'],
|
|
360
|
+
'permanentlyClosed': ['waiting']
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
// Amount to add to time between connection attemtpts per failed attempt.
|
|
365
|
+
var UNSUCCESSFUL_CONNECTION_ATTEMPT_ADDITIONAL_WAIT = 2000;
|
|
366
|
+
var UNSUCCESSFUL_OPEN_ATTEMPT_ADDITIONAL_TIMEOUT = 2000;
|
|
367
|
+
var UNSUCCESSFUL_CONNECTED_ATTEMPT_ADDITIONAL_TIMEOUT = 2000;
|
|
368
|
+
|
|
369
|
+
var MAX_CONNECTION_ATTEMPT_WAIT = 5 * UNSUCCESSFUL_CONNECTION_ATTEMPT_ADDITIONAL_WAIT;
|
|
370
|
+
var MAX_OPEN_ATTEMPT_TIMEOUT = 5 * UNSUCCESSFUL_OPEN_ATTEMPT_ADDITIONAL_TIMEOUT;
|
|
371
|
+
var MAX_CONNECTED_ATTEMPT_TIMEOUT = 5 * UNSUCCESSFUL_CONNECTED_ATTEMPT_ADDITIONAL_TIMEOUT;
|
|
372
|
+
|
|
373
|
+
function resetConnectionParameters(connection) {
|
|
374
|
+
connection.connectionWait = 0;
|
|
375
|
+
|
|
376
|
+
if (Pusher.TransportType === 'flash') {
|
|
377
|
+
// Flash needs a bit more time
|
|
378
|
+
connection.openTimeout = 5000;
|
|
379
|
+
} else {
|
|
380
|
+
connection.openTimeout = 2000;
|
|
381
|
+
}
|
|
382
|
+
connection.connectedTimeout = 2000;
|
|
383
|
+
connection.connectionSecure = connection.compulsorySecure;
|
|
384
|
+
connection.connectionAttempts = 0;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function Connection(key, options) {
|
|
388
|
+
var self = this;
|
|
389
|
+
|
|
390
|
+
Pusher.EventsDispatcher.call(this);
|
|
391
|
+
|
|
392
|
+
this.options = Pusher.Util.extend({encrypted: false}, options || {});
|
|
393
|
+
|
|
394
|
+
// define the state machine that runs the connection
|
|
395
|
+
this._machine = new Pusher.Machine(self, 'initialized', machineTransitions, {
|
|
396
|
+
|
|
397
|
+
// TODO: Use the constructor for this.
|
|
398
|
+
initializedPre: function() {
|
|
399
|
+
self.compulsorySecure = self.options.encrypted;
|
|
400
|
+
|
|
401
|
+
self.key = key;
|
|
402
|
+
self.socket = null;
|
|
403
|
+
self.socket_id = null;
|
|
404
|
+
|
|
405
|
+
self.state = 'initialized';
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
waitingPre: function() {
|
|
409
|
+
self._waitingTimer = setTimeout(function() {
|
|
410
|
+
self._machine.transition('connecting');
|
|
411
|
+
}, self.connectionWait);
|
|
412
|
+
|
|
413
|
+
if (self.connectionWait > 0) {
|
|
414
|
+
informUser('connecting_in', self.connectionWait);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (self.connectionAttempts > 4) {
|
|
418
|
+
triggerStateChange('unavailable');
|
|
419
|
+
} else {
|
|
420
|
+
triggerStateChange('connecting');
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
waitingExit: function() {
|
|
425
|
+
clearTimeout(self._waitingTimer);
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
connectingPre: function() {
|
|
429
|
+
// removed: if not closed, something is wrong that we should fix
|
|
430
|
+
// if(self.socket !== undefined) self.socket.close();
|
|
431
|
+
var url = formatURL(self.key, self.connectionSecure);
|
|
432
|
+
Pusher.debug('Connecting', url);
|
|
433
|
+
self.socket = new Pusher.Transport(url);
|
|
434
|
+
// now that the socket connection attempt has been started,
|
|
435
|
+
// set up the callbacks fired by the socket for different outcomes
|
|
436
|
+
self.socket.onopen = ws_onopen;
|
|
437
|
+
self.socket.onclose = transitionToWaiting;
|
|
438
|
+
self.socket.onerror = ws_onError;
|
|
439
|
+
|
|
440
|
+
// allow time to get ws_onOpen, otherwise close socket and try again
|
|
441
|
+
self._connectingTimer = setTimeout(TransitionToImpermanentClosing, self.openTimeout);
|
|
442
|
+
},
|
|
443
|
+
|
|
444
|
+
connectingExit: function() {
|
|
445
|
+
clearTimeout(self._connectingTimer);
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
connectingToWaiting: function() {
|
|
449
|
+
updateConnectionParameters();
|
|
450
|
+
|
|
451
|
+
// FUTURE: update only ssl
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
connectingToImpermanentlyClosing: function() {
|
|
455
|
+
updateConnectionParameters();
|
|
456
|
+
|
|
457
|
+
// FUTURE: update only timeout
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
openPre: function() {
|
|
461
|
+
self.socket.onmessage = ws_onMessage;
|
|
462
|
+
self.socket.onerror = ws_onError;
|
|
463
|
+
self.socket.onclose = function() {
|
|
464
|
+
self._machine.transition('waiting');
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
// allow time to get connected-to-Pusher message, otherwise close socket, try again
|
|
468
|
+
self._openTimer = setTimeout(TransitionToImpermanentClosing, self.connectedTimeout);
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
openExit: function() {
|
|
472
|
+
clearTimeout(self._openTimer);
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
openToWaiting: function() {
|
|
476
|
+
updateConnectionParameters();
|
|
477
|
+
},
|
|
478
|
+
|
|
479
|
+
openToImpermanentlyClosing: function() {
|
|
480
|
+
updateConnectionParameters();
|
|
481
|
+
},
|
|
482
|
+
|
|
483
|
+
connectedPre: function(socket_id) {
|
|
484
|
+
self.socket_id = socket_id;
|
|
485
|
+
|
|
486
|
+
self.socket.onmessage = ws_onMessage;
|
|
487
|
+
self.socket.onerror = ws_onError;
|
|
488
|
+
self.socket.onclose = function() {
|
|
489
|
+
self._machine.transition('waiting');
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
resetConnectionParameters(self);
|
|
493
|
+
},
|
|
494
|
+
|
|
495
|
+
connectedPost: function() {
|
|
496
|
+
triggerStateChange('connected');
|
|
497
|
+
},
|
|
498
|
+
|
|
499
|
+
connectedExit: function() {
|
|
500
|
+
triggerStateChange('disconnected');
|
|
501
|
+
},
|
|
502
|
+
|
|
503
|
+
impermanentlyClosingPost: function() {
|
|
504
|
+
self.socket.onclose = transitionToWaiting;
|
|
505
|
+
self.socket.close();
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
permanentlyClosingPost: function() {
|
|
509
|
+
self.socket.onclose = function() {
|
|
510
|
+
resetConnectionParameters(self);
|
|
511
|
+
self._machine.transition('permanentlyClosed');
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
self.socket.close();
|
|
515
|
+
},
|
|
516
|
+
|
|
517
|
+
failedPre: function() {
|
|
518
|
+
triggerStateChange('failed');
|
|
519
|
+
Pusher.debug('WebSockets are not available in this browser.');
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
/*-----------------------------------------------
|
|
524
|
+
-----------------------------------------------*/
|
|
525
|
+
|
|
526
|
+
function updateConnectionParameters() {
|
|
527
|
+
if (self.connectionWait < MAX_CONNECTION_ATTEMPT_WAIT) {
|
|
528
|
+
self.connectionWait += UNSUCCESSFUL_CONNECTION_ATTEMPT_ADDITIONAL_WAIT;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (self.openTimeout < MAX_OPEN_ATTEMPT_TIMEOUT) {
|
|
532
|
+
self.openTimeout += UNSUCCESSFUL_OPEN_ATTEMPT_ADDITIONAL_TIMEOUT;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (self.connectedTimeout < MAX_CONNECTED_ATTEMPT_TIMEOUT) {
|
|
536
|
+
self.connectedTimeout += UNSUCCESSFUL_CONNECTED_ATTEMPT_ADDITIONAL_TIMEOUT;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (self.compulsorySecure !== true) {
|
|
540
|
+
self.connectionSecure = !self.connectionSecure;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
self.connectionAttempts++;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function formatURL(key, isSecure) {
|
|
547
|
+
var port = Pusher.ws_port;
|
|
548
|
+
var protocol = 'ws://';
|
|
549
|
+
|
|
550
|
+
if (isSecure) {
|
|
551
|
+
port = Pusher.wss_port;
|
|
552
|
+
protocol = 'wss://';
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return protocol + Pusher.host + ':' + port + '/app/' + key + '?client=js&version=' + Pusher.VERSION;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// callback for close and retry. Used on timeouts.
|
|
559
|
+
function TransitionToImpermanentClosing() {
|
|
560
|
+
self._machine.transition('impermanentlyClosing');
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/*-----------------------------------------------
|
|
564
|
+
WebSocket Callbacks
|
|
565
|
+
-----------------------------------------------*/
|
|
566
|
+
|
|
567
|
+
// no-op, as we only care when we get pusher:connection_established
|
|
568
|
+
function ws_onopen() {
|
|
569
|
+
self._machine.transition('open');
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
function ws_onMessage(event) {
|
|
573
|
+
var params = parseWebSocketEvent(event);
|
|
574
|
+
|
|
575
|
+
// case of invalid JSON payload sent
|
|
576
|
+
// we have to handle the error in the parseWebSocketEvent
|
|
577
|
+
// method as JavaScript error objects are kinda icky.
|
|
578
|
+
if (typeof params === 'undefined') return;
|
|
579
|
+
|
|
580
|
+
Pusher.debug('Event recd (event,data)', params.event, params.data);
|
|
581
|
+
|
|
582
|
+
// Continue to work with valid payloads:
|
|
583
|
+
if (params.event === 'pusher:connection_established') {
|
|
584
|
+
self._machine.transition('connected', params.data.socket_id);
|
|
585
|
+
} else if (params.event === 'pusher:error') {
|
|
586
|
+
// first inform the end-developer of this error
|
|
587
|
+
informUser('error', {type: 'PusherError', data: params.data});
|
|
588
|
+
|
|
589
|
+
// App not found by key - close connection
|
|
590
|
+
if (params.data.code === 4001) {
|
|
591
|
+
self._machine.transition('permanentlyClosing');
|
|
592
|
+
}
|
|
593
|
+
} else if (params.event === 'pusher:heartbeat') {
|
|
594
|
+
} else if (self._machine.is('connected')) {
|
|
595
|
+
informUser('message', params);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Parses an event from the WebSocket to get
|
|
602
|
+
* the JSON payload that we require
|
|
603
|
+
*
|
|
604
|
+
* @param {MessageEvent} event The event from the WebSocket.onmessage handler.
|
|
605
|
+
**/
|
|
606
|
+
function parseWebSocketEvent(event) {
|
|
607
|
+
try {
|
|
608
|
+
var params = JSON.parse(event.data);
|
|
609
|
+
|
|
610
|
+
if (typeof params.data === 'string') {
|
|
611
|
+
try {
|
|
612
|
+
params.data = JSON.parse(params.data);
|
|
613
|
+
} catch (e) {
|
|
614
|
+
if (!(e instanceof SyntaxError)) {
|
|
615
|
+
throw e;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return params;
|
|
621
|
+
} catch (e) {
|
|
622
|
+
informUser('error', {type: 'MessageParseError', error: e, data: event.data});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function transitionToWaiting() {
|
|
627
|
+
self._machine.transition('waiting');
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function ws_onError() {
|
|
631
|
+
informUser('error', {
|
|
632
|
+
type: 'WebSocketError'
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
// note: required? is the socket auto closed in the case of error?
|
|
636
|
+
self.socket.close();
|
|
637
|
+
self._machine.transition('impermanentlyClosing');
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function informUser(eventName, data) {
|
|
641
|
+
self.emit(eventName, data);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function triggerStateChange(newState, data) {
|
|
645
|
+
// avoid emitting and changing the state
|
|
646
|
+
// multiple times when it's the same.
|
|
647
|
+
if (self.state === newState) return;
|
|
648
|
+
|
|
649
|
+
var prevState = self.state;
|
|
650
|
+
|
|
651
|
+
self.state = newState;
|
|
652
|
+
|
|
653
|
+
Pusher.debug('State changed', prevState + ' -> ' + newState);
|
|
654
|
+
|
|
655
|
+
self.emit('state_change', {previous: prevState, current: newState});
|
|
656
|
+
self.emit(newState, data);
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
Connection.prototype.connect = function() {
|
|
661
|
+
// no WebSockets
|
|
662
|
+
if (Pusher.Transport === null) {
|
|
663
|
+
this._machine.transition('failed');
|
|
664
|
+
}
|
|
665
|
+
// initial open of connection
|
|
666
|
+
else if(this._machine.is('initialized')) {
|
|
667
|
+
resetConnectionParameters(this);
|
|
668
|
+
this._machine.transition('waiting');
|
|
669
|
+
}
|
|
670
|
+
// user skipping connection wait
|
|
671
|
+
else if (this._machine.is('waiting')) {
|
|
672
|
+
this._machine.transition('connecting');
|
|
673
|
+
}
|
|
674
|
+
// user re-opening connection after closing it
|
|
675
|
+
else if(this._machine.is("permanentlyClosed")) {
|
|
676
|
+
this._machine.transition('waiting');
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
Connection.prototype.send = function(data) {
|
|
681
|
+
if (this._machine.is('connected')) {
|
|
682
|
+
this.socket.send(data);
|
|
683
|
+
return true;
|
|
684
|
+
} else {
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
Connection.prototype.disconnect = function() {
|
|
690
|
+
if (this._machine.is('waiting')) {
|
|
691
|
+
this._machine.transition('permanentlyClosed');
|
|
692
|
+
} else {
|
|
693
|
+
this._machine.transition('permanentlyClosing');
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
Pusher.Util.extend(Connection.prototype, Pusher.EventsDispatcher.prototype);
|
|
698
|
+
|
|
699
|
+
this.Pusher.Connection = Connection;
|
|
700
|
+
}).call(this);
|
|
701
|
+
|
|
702
|
+
Pusher.Channels = function() {
|
|
703
|
+
this.channels = {};
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
Pusher.Channels.prototype = {
|
|
707
|
+
add: function(channel_name, pusher) {
|
|
708
|
+
var existing_channel = this.find(channel_name);
|
|
709
|
+
if (!existing_channel) {
|
|
710
|
+
var channel = Pusher.Channel.factory(channel_name, pusher);
|
|
711
|
+
this.channels[channel_name] = channel;
|
|
712
|
+
return channel;
|
|
713
|
+
} else {
|
|
714
|
+
return existing_channel;
|
|
715
|
+
}
|
|
716
|
+
},
|
|
717
|
+
|
|
718
|
+
find: function(channel_name) {
|
|
719
|
+
return this.channels[channel_name];
|
|
720
|
+
},
|
|
721
|
+
|
|
722
|
+
remove: function(channel_name) {
|
|
723
|
+
delete this.channels[channel_name];
|
|
724
|
+
},
|
|
725
|
+
|
|
726
|
+
disconnect: function () {
|
|
727
|
+
for(var channel_name in this.channels){
|
|
728
|
+
this.channels[channel_name].disconnect()
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
Pusher.Channel = function(channel_name, pusher) {
|
|
734
|
+
Pusher.EventsDispatcher.call(this);
|
|
735
|
+
|
|
736
|
+
this.pusher = pusher;
|
|
737
|
+
this.name = channel_name;
|
|
738
|
+
this.subscribed = false;
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
Pusher.Channel.prototype = {
|
|
742
|
+
// inheritable constructor
|
|
743
|
+
init: function(){
|
|
744
|
+
|
|
745
|
+
},
|
|
746
|
+
|
|
747
|
+
disconnect: function(){
|
|
748
|
+
|
|
749
|
+
},
|
|
750
|
+
|
|
751
|
+
// Activate after successful subscription. Called on top-level pusher:subscription_succeeded
|
|
752
|
+
acknowledge_subscription: function(data){
|
|
753
|
+
this.subscribed = true;
|
|
754
|
+
},
|
|
755
|
+
|
|
756
|
+
is_private: function(){
|
|
757
|
+
return false;
|
|
758
|
+
},
|
|
759
|
+
|
|
760
|
+
is_presence: function(){
|
|
761
|
+
return false;
|
|
762
|
+
},
|
|
763
|
+
|
|
764
|
+
authorize: function(pusher, callback){
|
|
765
|
+
callback({}); // normal channels don't require auth
|
|
766
|
+
},
|
|
767
|
+
|
|
768
|
+
trigger: function(event, data) {
|
|
769
|
+
this.pusher.send_event(event, data, this.name);
|
|
770
|
+
return this;
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
Pusher.Util.extend(Pusher.Channel.prototype, Pusher.EventsDispatcher.prototype);
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
Pusher.auth_callbacks = {};
|
|
779
|
+
|
|
780
|
+
Pusher.authorizers = {
|
|
781
|
+
ajax: function(pusher, callback){
|
|
782
|
+
var self = this;
|
|
783
|
+
var xhr = window.XMLHttpRequest ?
|
|
784
|
+
new XMLHttpRequest() :
|
|
785
|
+
new ActiveXObject("Microsoft.XMLHTTP");
|
|
786
|
+
xhr.open("POST", Pusher.channel_auth_endpoint, true);
|
|
787
|
+
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
|
|
788
|
+
xhr.onreadystatechange = function() {
|
|
789
|
+
if (xhr.readyState == 4) {
|
|
790
|
+
if (xhr.status == 200) {
|
|
791
|
+
var data = JSON.parse(xhr.responseText);
|
|
792
|
+
callback(data);
|
|
793
|
+
} else {
|
|
794
|
+
Pusher.debug("Couldn't get auth info from your webapp", status);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
xhr.send('socket_id=' + encodeURIComponent(pusher.connection.socket_id) + '&channel_name=' + encodeURIComponent(self.name));
|
|
799
|
+
},
|
|
800
|
+
jsonp: function(pusher, callback){
|
|
801
|
+
var qstring = 'socket_id=' + encodeURIComponent(pusher.connection.socket_id) + '&channel_name=' + encodeURIComponent(this.name);
|
|
802
|
+
var script = document.createElement("script");
|
|
803
|
+
Pusher.auth_callbacks[this.name] = callback;
|
|
804
|
+
var callback_name = "Pusher.auth_callbacks['" + this.name + "']";
|
|
805
|
+
script.src = Pusher.channel_auth_endpoint+'?callback='+encodeURIComponent(callback_name)+'&'+qstring;
|
|
806
|
+
var head = document.getElementsByTagName("head")[0] || document.documentElement;
|
|
807
|
+
head.insertBefore( script, head.firstChild );
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
Pusher.Channel.PrivateChannel = {
|
|
812
|
+
is_private: function(){
|
|
813
|
+
return true;
|
|
814
|
+
},
|
|
815
|
+
|
|
816
|
+
authorize: function(pusher, callback){
|
|
817
|
+
Pusher.authorizers[Pusher.channel_auth_transport].scopedTo(this)(pusher, callback);
|
|
818
|
+
}
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
Pusher.Channel.PresenceChannel = {
|
|
822
|
+
|
|
823
|
+
init: function(){
|
|
824
|
+
this.bind('pusher_internal:subscription_succeeded', function(sub_data){
|
|
825
|
+
this.acknowledge_subscription(sub_data);
|
|
826
|
+
this.dispatch_with_all('pusher:subscription_succeeded', this.members);
|
|
827
|
+
}.scopedTo(this));
|
|
828
|
+
|
|
829
|
+
this.bind('pusher_internal:member_added', function(data){
|
|
830
|
+
var member = this.members.add(data.user_id, data.user_info);
|
|
831
|
+
this.dispatch_with_all('pusher:member_added', member);
|
|
832
|
+
}.scopedTo(this))
|
|
833
|
+
|
|
834
|
+
this.bind('pusher_internal:member_removed', function(data){
|
|
835
|
+
var member = this.members.remove(data.user_id);
|
|
836
|
+
if (member) {
|
|
837
|
+
this.dispatch_with_all('pusher:member_removed', member);
|
|
838
|
+
}
|
|
839
|
+
}.scopedTo(this))
|
|
840
|
+
},
|
|
841
|
+
|
|
842
|
+
disconnect: function(){
|
|
843
|
+
this.members.clear();
|
|
844
|
+
},
|
|
845
|
+
|
|
846
|
+
acknowledge_subscription: function(sub_data){
|
|
847
|
+
this.members._members_map = sub_data.presence.hash;
|
|
848
|
+
this.members.count = sub_data.presence.count;
|
|
849
|
+
this.subscribed = true;
|
|
850
|
+
},
|
|
851
|
+
|
|
852
|
+
is_presence: function(){
|
|
853
|
+
return true;
|
|
854
|
+
},
|
|
855
|
+
|
|
856
|
+
members: {
|
|
857
|
+
_members_map: {},
|
|
858
|
+
count: 0,
|
|
859
|
+
|
|
860
|
+
each: function(callback) {
|
|
861
|
+
for(var i in this._members_map) {
|
|
862
|
+
callback({
|
|
863
|
+
id: i,
|
|
864
|
+
info: this._members_map[i]
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
},
|
|
868
|
+
|
|
869
|
+
add: function(id, info) {
|
|
870
|
+
this._members_map[id] = info;
|
|
871
|
+
this.count++;
|
|
872
|
+
return this.get(id);
|
|
873
|
+
},
|
|
874
|
+
|
|
875
|
+
remove: function(user_id) {
|
|
876
|
+
var member = this.get(user_id);
|
|
877
|
+
if (member) {
|
|
878
|
+
delete this._members_map[user_id];
|
|
879
|
+
this.count--;
|
|
880
|
+
}
|
|
881
|
+
return member;
|
|
882
|
+
},
|
|
883
|
+
|
|
884
|
+
get: function(user_id) {
|
|
885
|
+
var user_info = this._members_map[user_id];
|
|
886
|
+
if (user_info) {
|
|
887
|
+
return {
|
|
888
|
+
id: user_id,
|
|
889
|
+
info: user_info
|
|
890
|
+
}
|
|
891
|
+
} else {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
},
|
|
895
|
+
|
|
896
|
+
clear: function() {
|
|
897
|
+
this._members_map = {};
|
|
898
|
+
this.count = 0;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
Pusher.Channel.factory = function(channel_name, pusher){
|
|
904
|
+
var channel = new Pusher.Channel(channel_name, pusher);
|
|
905
|
+
if(channel_name.indexOf(Pusher.Channel.private_prefix) === 0) {
|
|
906
|
+
Pusher.Util.extend(channel, Pusher.Channel.PrivateChannel);
|
|
907
|
+
} else if(channel_name.indexOf(Pusher.Channel.presence_prefix) === 0) {
|
|
908
|
+
Pusher.Util.extend(channel, Pusher.Channel.PrivateChannel);
|
|
909
|
+
Pusher.Util.extend(channel, Pusher.Channel.PresenceChannel);
|
|
910
|
+
};
|
|
911
|
+
channel.init();// inheritable constructor
|
|
912
|
+
return channel;
|
|
913
|
+
};
|
|
914
|
+
|
|
915
|
+
Pusher.Channel.private_prefix = "private-";
|
|
916
|
+
Pusher.Channel.presence_prefix = "presence-";
|
|
917
|
+
|
|
918
|
+
var _require = (function () {
|
|
919
|
+
|
|
920
|
+
var handleScriptLoaded;
|
|
921
|
+
if (document.addEventListener) {
|
|
922
|
+
handleScriptLoaded = function (elem, callback) {
|
|
923
|
+
elem.addEventListener('load', callback, false)
|
|
924
|
+
}
|
|
925
|
+
} else {
|
|
926
|
+
handleScriptLoaded = function(elem, callback) {
|
|
927
|
+
elem.attachEvent('onreadystatechange', function () {
|
|
928
|
+
if(elem.readyState == 'loaded' || elem.readyState == 'complete') callback()
|
|
929
|
+
})
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
return function (deps, callback) {
|
|
934
|
+
var dep_count = 0,
|
|
935
|
+
dep_length = deps.length;
|
|
936
|
+
|
|
937
|
+
function checkReady (callback) {
|
|
938
|
+
dep_count++;
|
|
939
|
+
if ( dep_length == dep_count ) {
|
|
940
|
+
// Opera needs the timeout for page initialization weirdness
|
|
941
|
+
setTimeout(callback, 0);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
function addScript (src, callback) {
|
|
946
|
+
callback = callback || function(){}
|
|
947
|
+
var head = document.getElementsByTagName('head')[0];
|
|
948
|
+
var script = document.createElement('script');
|
|
949
|
+
script.setAttribute('src', src);
|
|
950
|
+
script.setAttribute("type","text/javascript");
|
|
951
|
+
script.setAttribute('async', true);
|
|
952
|
+
|
|
953
|
+
handleScriptLoaded(script, function () {
|
|
954
|
+
checkReady(callback);
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
head.appendChild(script);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
for(var i = 0; i < dep_length; i++) {
|
|
961
|
+
addScript(deps[i], callback);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
})();
|
|
965
|
+
|
|
966
|
+
;(function() {
|
|
967
|
+
var cdn = (document.location.protocol == 'http:') ? Pusher.cdn_http : Pusher.cdn_https;
|
|
968
|
+
var root = cdn + Pusher.VERSION;
|
|
969
|
+
|
|
970
|
+
var deps = [];
|
|
971
|
+
if (typeof window['JSON'] === undefined) {
|
|
972
|
+
deps.push(root + '/json2.js');
|
|
973
|
+
}
|
|
974
|
+
if (typeof window['WebSocket'] === 'undefined') {
|
|
975
|
+
// We manually initialize web-socket-js to iron out cross browser issues
|
|
976
|
+
window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true;
|
|
977
|
+
deps.push(root + '/flashfallback.js');
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
var initialize = function() {
|
|
981
|
+
if (typeof window['WebSocket'] === 'undefined' && typeof window['MozWebSocket'] === 'undefined') {
|
|
982
|
+
return function() {
|
|
983
|
+
// This runs after flashfallback.js has loaded
|
|
984
|
+
if (typeof window['WebSocket'] !== 'undefined') {
|
|
985
|
+
// window['WebSocket'] is a flash emulation of WebSocket
|
|
986
|
+
Pusher.Transport = window['WebSocket'];
|
|
987
|
+
Pusher.TransportType = 'flash';
|
|
988
|
+
|
|
989
|
+
window.WEB_SOCKET_SWF_LOCATION = root + "/WebSocketMain.swf";
|
|
990
|
+
WebSocket.__addTask(function() {
|
|
991
|
+
Pusher.ready();
|
|
992
|
+
})
|
|
993
|
+
WebSocket.__initialize();
|
|
994
|
+
} else {
|
|
995
|
+
// Flash must not be installed
|
|
996
|
+
Pusher.Transport = null;
|
|
997
|
+
Pusher.TransportType = 'none';
|
|
998
|
+
Pusher.ready();
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
} else {
|
|
1002
|
+
return function() {
|
|
1003
|
+
// This is because Mozilla have decided to
|
|
1004
|
+
// prefix the WebSocket constructor with "Moz".
|
|
1005
|
+
if (typeof window['MozWebSocket'] !== 'undefined') {
|
|
1006
|
+
Pusher.Transport = window['MozWebSocket'];
|
|
1007
|
+
} else {
|
|
1008
|
+
Pusher.Transport = window['WebSocket'];
|
|
1009
|
+
}
|
|
1010
|
+
// We have some form of a native websocket,
|
|
1011
|
+
// even if the constructor is prefixed:
|
|
1012
|
+
Pusher.TransportType = 'native';
|
|
1013
|
+
|
|
1014
|
+
// Initialise Pusher.
|
|
1015
|
+
Pusher.ready();
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}();
|
|
1019
|
+
|
|
1020
|
+
var ondocumentbody = function(callback) {
|
|
1021
|
+
var load_body = function() {
|
|
1022
|
+
document.body ? callback() : setTimeout(load_body, 0);
|
|
1023
|
+
}
|
|
1024
|
+
load_body();
|
|
1025
|
+
};
|
|
1026
|
+
|
|
1027
|
+
var initializeOnDocumentBody = function() {
|
|
1028
|
+
ondocumentbody(initialize);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
if (deps.length > 0) {
|
|
1032
|
+
_require(deps, initializeOnDocumentBody);
|
|
1033
|
+
} else {
|
|
1034
|
+
initializeOnDocumentBody();
|
|
1035
|
+
}
|
|
1036
|
+
})();
|
|
1037
|
+
|
metadata
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pusher_rails
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- David Grandinetti
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2011-07-27 00:00:00.000000000Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: Adds pusher.js to the asset pipeline
|
|
15
|
+
email: dave@wegoto12.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- ./pusher_rails-0.1.0.gem
|
|
21
|
+
- ./pusher_rails.gemspec
|
|
22
|
+
- ./README.md
|
|
23
|
+
- ./vendor/assets/javascripts/pusher.js
|
|
24
|
+
homepage: https://github.com/dbgrandi/pusher_rails
|
|
25
|
+
licenses: []
|
|
26
|
+
post_install_message:
|
|
27
|
+
rdoc_options: []
|
|
28
|
+
require_paths:
|
|
29
|
+
- lib
|
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
31
|
+
none: false
|
|
32
|
+
requirements:
|
|
33
|
+
- - ! '>='
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '0'
|
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
37
|
+
none: false
|
|
38
|
+
requirements:
|
|
39
|
+
- - ! '>='
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0'
|
|
42
|
+
requirements: []
|
|
43
|
+
rubyforge_project:
|
|
44
|
+
rubygems_version: 1.8.5
|
|
45
|
+
signing_key:
|
|
46
|
+
specification_version: 3
|
|
47
|
+
summary: Pusher integration for Rails 3.1+
|
|
48
|
+
test_files: []
|