pusher-fake 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,206 +1,211 @@
1
1
  /*!
2
- * Pusher JavaScript Library v1.11.2
2
+ * Pusher JavaScript Library v1.12.1
3
3
  * http://pusherapp.com/
4
4
  *
5
5
  * Copyright 2011, Pusher
6
6
  * Released under the MIT licence.
7
7
  */
8
8
 
9
- if (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)));
9
+ ;(function() {
10
+ if (Function.prototype.scopedTo === undefined) {
11
+ Function.prototype.scopedTo = function(context, args) {
12
+ var f = this;
13
+ return function() {
14
+ return f.apply(context, Array.prototype.slice.call(args || [])
15
+ .concat(Array.prototype.slice.call(arguments)));
16
+ };
15
17
  };
16
- };
17
- }
18
-
19
- var Pusher = function(app_key, options) {
20
- this.options = options || {};
21
- this.key = app_key;
22
- this.channels = new Pusher.Channels();
23
- this.global_emitter = new Pusher.EventsDispatcher()
24
-
25
- var self = this;
26
-
27
- this.checkAppKey();
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
- var internal = (params.event.indexOf('pusher_internal:') === 0);
38
- if (params.channel) {
39
- var channel;
40
- if (channel = self.channel(params.channel)) {
41
- channel.emit(params.event, params.data);
18
+ }
19
+
20
+ var Pusher = function(app_key, options) {
21
+ this.options = options || {};
22
+ this.key = app_key;
23
+ this.channels = new Pusher.Channels();
24
+ this.global_emitter = new Pusher.EventsDispatcher()
25
+
26
+ var self = this;
27
+
28
+ this.checkAppKey();
29
+
30
+ this.connection = new Pusher.Connection(this.key, this.options);
31
+
32
+ // Setup / teardown connection
33
+ this.connection
34
+ .bind('connected', function() {
35
+ self.subscribeAll();
36
+ })
37
+ .bind('message', function(params) {
38
+ var internal = (params.event.indexOf('pusher_internal:') === 0);
39
+ if (params.channel) {
40
+ var channel;
41
+ if (channel = self.channel(params.channel)) {
42
+ channel.emit(params.event, params.data);
43
+ }
42
44
  }
43
- }
44
- // Emit globaly [deprecated]
45
- if (!internal) self.global_emitter.emit(params.event, params.data);
46
- })
47
- .bind('disconnected', function() {
48
- self.channels.disconnect();
49
- })
50
- .bind('error', function(err) {
51
- Pusher.warn('Error', err);
52
- });
45
+ // Emit globaly [deprecated]
46
+ if (!internal) self.global_emitter.emit(params.event, params.data);
47
+ })
48
+ .bind('disconnected', function() {
49
+ self.channels.disconnect();
50
+ })
51
+ .bind('error', function(err) {
52
+ Pusher.warn('Error', err);
53
+ });
53
54
 
54
- Pusher.instances.push(this);
55
+ Pusher.instances.push(this);
55
56
 
56
- if (Pusher.isReady) self.connect();
57
- };
58
- Pusher.instances = [];
59
- Pusher.prototype = {
60
- channel: function(name) {
61
- return this.channels.find(name);
62
- },
57
+ if (Pusher.isReady) self.connect();
58
+ };
59
+ Pusher.instances = [];
60
+ Pusher.prototype = {
61
+ channel: function(name) {
62
+ return this.channels.find(name);
63
+ },
63
64
 
64
- connect: function() {
65
- this.connection.connect();
66
- },
65
+ connect: function() {
66
+ this.connection.connect();
67
+ },
67
68
 
68
- disconnect: function() {
69
- this.connection.disconnect();
70
- },
69
+ disconnect: function() {
70
+ this.connection.disconnect();
71
+ },
71
72
 
72
- bind: function(event_name, callback) {
73
- this.global_emitter.bind(event_name, callback);
74
- return this;
75
- },
73
+ bind: function(event_name, callback) {
74
+ this.global_emitter.bind(event_name, callback);
75
+ return this;
76
+ },
76
77
 
77
- bind_all: function(callback) {
78
- this.global_emitter.bind_all(callback);
79
- return this;
80
- },
78
+ bind_all: function(callback) {
79
+ this.global_emitter.bind_all(callback);
80
+ return this;
81
+ },
81
82
 
82
- subscribeAll: function() {
83
- var channel;
84
- for (channel in this.channels.channels) {
85
- if (this.channels.channels.hasOwnProperty(channel)) {
86
- this.subscribe(channel);
83
+ subscribeAll: function() {
84
+ var channel;
85
+ for (channelName in this.channels.channels) {
86
+ if (this.channels.channels.hasOwnProperty(channelName)) {
87
+ this.subscribe(channelName);
88
+ }
87
89
  }
88
- }
89
- },
90
+ },
90
91
 
91
- subscribe: function(channel_name) {
92
- var self = this;
93
- var channel = this.channels.add(channel_name, this);
94
- if (this.connection.state === 'connected') {
95
- channel.authorize(this, function(err, data) {
96
- if (err) {
97
- channel.emit('pusher:subscription_error', data);
98
- } else {
99
- self.send_event('pusher:subscribe', {
100
- channel: channel_name,
101
- auth: data.auth,
102
- channel_data: data.channel_data
103
- });
104
- }
105
- });
106
- }
107
- return channel;
108
- },
92
+ subscribe: function(channel_name) {
93
+ var self = this;
94
+ var channel = this.channels.add(channel_name, this);
95
+
96
+ if (this.connection.state === 'connected') {
97
+ channel.authorize(this.connection.socket_id, this.options, function(err, data) {
98
+ if (err) {
99
+ channel.emit('pusher:subscription_error', data);
100
+ } else {
101
+ self.send_event('pusher:subscribe', {
102
+ channel: channel_name,
103
+ auth: data.auth,
104
+ channel_data: data.channel_data
105
+ });
106
+ }
107
+ });
108
+ }
109
+ return channel;
110
+ },
109
111
 
110
- unsubscribe: function(channel_name) {
111
- this.channels.remove(channel_name);
112
- if (this.connection.state === 'connected') {
113
- this.send_event('pusher:unsubscribe', {
114
- channel: channel_name
115
- });
116
- }
117
- },
112
+ unsubscribe: function(channel_name) {
113
+ this.channels.remove(channel_name);
114
+ if (this.connection.state === 'connected') {
115
+ this.send_event('pusher:unsubscribe', {
116
+ channel: channel_name
117
+ });
118
+ }
119
+ },
118
120
 
119
- send_event: function(event_name, data, channel) {
120
- return this.connection.send_event(event_name, data, channel);
121
- },
121
+ send_event: function(event_name, data, channel) {
122
+ return this.connection.send_event(event_name, data, channel);
123
+ },
122
124
 
123
- checkAppKey: function() {
124
- if(this.key === null || this.key === undefined) {
125
- Pusher.warn('Warning', 'You must pass your app key when you instantiate Pusher.');
126
- }
127
- }
128
- };
129
-
130
- Pusher.Util = {
131
- extend: function extend(target, extensions) {
132
- for (var property in extensions) {
133
- if (extensions[property] && extensions[property].constructor &&
134
- extensions[property].constructor === Object) {
135
- target[property] = extend(target[property] || {}, extensions[property]);
136
- } else {
137
- target[property] = extensions[property];
125
+ checkAppKey: function() {
126
+ if(this.key === null || this.key === undefined) {
127
+ Pusher.warn('Warning', 'You must pass your app key when you instantiate Pusher.');
138
128
  }
139
129
  }
140
- return target;
141
- },
142
-
143
- stringify: function stringify() {
144
- var m = ["Pusher"]
145
- for (var i = 0; i < arguments.length; i++){
146
- if (typeof arguments[i] === "string") {
147
- m.push(arguments[i])
148
- } else {
149
- if (window['JSON'] == undefined) {
150
- m.push(arguments[i].toString());
130
+ };
131
+
132
+ Pusher.Util = {
133
+ extend: function extend(target, extensions) {
134
+ for (var property in extensions) {
135
+ if (extensions[property] && extensions[property].constructor &&
136
+ extensions[property].constructor === Object) {
137
+ target[property] = extend(target[property] || {}, extensions[property]);
151
138
  } else {
152
- m.push(JSON.stringify(arguments[i]))
139
+ target[property] = extensions[property];
153
140
  }
154
141
  }
155
- };
156
- return m.join(" : ")
157
- },
158
-
159
- arrayIndexOf: function(array, item) { // MSIE doesn't have array.indexOf
160
- var nativeIndexOf = Array.prototype.indexOf;
161
- if (array == null) return -1;
162
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
163
- for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
164
- return -1;
165
- }
166
- };
167
-
168
- // To receive log output provide a Pusher.log function, for example
169
- // Pusher.log = function(m){console.log(m)}
170
- Pusher.debug = function() {
171
- if (!Pusher.log) return
172
- Pusher.log(Pusher.Util.stringify.apply(this, arguments))
173
- }
174
- Pusher.warn = function() {
175
- if (window.console && window.console.warn) {
176
- window.console.warn(Pusher.Util.stringify.apply(this, arguments));
177
- } else {
142
+ return target;
143
+ },
144
+
145
+ stringify: function stringify() {
146
+ var m = ["Pusher"]
147
+ for (var i = 0; i < arguments.length; i++){
148
+ if (typeof arguments[i] === "string") {
149
+ m.push(arguments[i])
150
+ } else {
151
+ if (window['JSON'] == undefined) {
152
+ m.push(arguments[i].toString());
153
+ } else {
154
+ m.push(JSON.stringify(arguments[i]))
155
+ }
156
+ }
157
+ };
158
+ return m.join(" : ")
159
+ },
160
+
161
+ arrayIndexOf: function(array, item) { // MSIE doesn't have array.indexOf
162
+ var nativeIndexOf = Array.prototype.indexOf;
163
+ if (array == null) return -1;
164
+ if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
165
+ for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
166
+ return -1;
167
+ }
168
+ };
169
+
170
+ // To receive log output provide a Pusher.log function, for example
171
+ // Pusher.log = function(m){console.log(m)}
172
+ Pusher.debug = function() {
178
173
  if (!Pusher.log) return
179
- Pusher.log(Pusher.Util.stringify.apply(this, arguments));
180
- }
181
- };
182
-
183
- // Pusher defaults
184
- Pusher.VERSION = '1.11.2';
185
-
186
- Pusher.host = 'ws.pusherapp.com';
187
- Pusher.ws_port = 80;
188
- Pusher.wss_port = 443;
189
- Pusher.channel_auth_endpoint = '/pusher/auth';
190
- Pusher.cdn_http = 'http://js.pusher.com/'
191
- Pusher.cdn_https = 'https://d3dy5gmtp8yhk7.cloudfront.net/'
192
- Pusher.dependency_suffix = '';
193
- Pusher.channel_auth_transport = 'ajax';
194
- Pusher.activity_timeout = 120000;
195
- Pusher.pong_timeout = 30000;
196
-
197
- Pusher.isReady = false;
198
- Pusher.ready = function() {
199
- Pusher.isReady = true;
200
- for (var i = 0, l = Pusher.instances.length; i < l; i++) {
201
- Pusher.instances[i].connect();
174
+ Pusher.log(Pusher.Util.stringify.apply(this, arguments))
202
175
  }
203
- };
176
+ Pusher.warn = function() {
177
+ if (window.console && window.console.warn) {
178
+ window.console.warn(Pusher.Util.stringify.apply(this, arguments));
179
+ } else {
180
+ if (!Pusher.log) return
181
+ Pusher.log(Pusher.Util.stringify.apply(this, arguments));
182
+ }
183
+ };
184
+
185
+ // Pusher defaults
186
+ Pusher.VERSION = '1.12.1';
187
+
188
+ Pusher.host = 'ws.pusherapp.com';
189
+ Pusher.ws_port = 80;
190
+ Pusher.wss_port = 443;
191
+ Pusher.channel_auth_endpoint = '/pusher/auth';
192
+ Pusher.cdn_http = 'http://js.pusher.com/'
193
+ Pusher.cdn_https = 'https://d3dy5gmtp8yhk7.cloudfront.net/'
194
+ Pusher.dependency_suffix = '';
195
+ Pusher.channel_auth_transport = 'ajax';
196
+ Pusher.activity_timeout = 120000;
197
+ Pusher.pong_timeout = 30000;
198
+
199
+ Pusher.isReady = false;
200
+ Pusher.ready = function() {
201
+ Pusher.isReady = true;
202
+ for (var i = 0, l = Pusher.instances.length; i < l; i++) {
203
+ Pusher.instances[i].connect();
204
+ }
205
+ };
206
+
207
+ this.Pusher = Pusher;
208
+ }).call(this);
204
209
 
205
210
  ;(function() {
206
211
  /* Abstract event binding
@@ -394,11 +399,11 @@ Example:
394
399
  'waiting': ['connecting', 'permanentlyClosed'],
395
400
  'connecting': ['open', 'permanentlyClosing', 'impermanentlyClosing', 'waiting'],
396
401
  'open': ['connected', 'permanentlyClosing', 'impermanentlyClosing', 'waiting'],
397
- 'connected': ['permanentlyClosing', 'impermanentlyClosing', 'waiting'],
402
+ 'connected': ['permanentlyClosing', 'waiting'],
398
403
  'impermanentlyClosing': ['waiting', 'permanentlyClosing'],
399
404
  'permanentlyClosing': ['permanentlyClosed'],
400
405
  'permanentlyClosed': ['waiting'],
401
- 'failed': ['permanentlyClosing']
406
+ 'failed': ['permanentlyClosed']
402
407
  };
403
408
 
404
409
 
@@ -502,8 +507,6 @@ Example:
502
507
  return;
503
508
  }
504
509
 
505
- // removed: if not closed, something is wrong that we should fix
506
- // if(self.socket !== undefined) self.socket.close();
507
510
  var url = formatURL(self.key, self.connectionSecure);
508
511
  Pusher.debug('Connecting', url);
509
512
  self.socket = new Pusher.Transport(url);
@@ -514,11 +517,12 @@ Example:
514
517
  self.socket.onerror = ws_onError;
515
518
 
516
519
  // allow time to get ws_onOpen, otherwise close socket and try again
517
- self._connectingTimer = setTimeout(TransitionToImpermanentClosing, self.openTimeout);
520
+ self._connectingTimer = setTimeout(TransitionToImpermanentlyClosing, self.openTimeout);
518
521
  },
519
522
 
520
523
  connectingExit: function() {
521
524
  clearTimeout(self._connectingTimer);
525
+ self.socket.onopen = undefined; // unbind to avoid open events that are no longer relevant
522
526
  },
523
527
 
524
528
  connectingToWaiting: function() {
@@ -539,11 +543,12 @@ Example:
539
543
  self.socket.onclose = transitionToWaiting;
540
544
 
541
545
  // allow time to get connected-to-Pusher message, otherwise close socket, try again
542
- self._openTimer = setTimeout(TransitionToImpermanentClosing, self.connectedTimeout);
546
+ self._openTimer = setTimeout(TransitionToImpermanentlyClosing, self.connectedTimeout);
543
547
  },
544
548
 
545
549
  openExit: function() {
546
550
  clearTimeout(self._openTimer);
551
+ self.socket.onmessage = undefined; // unbind to avoid messages that are no longer relevant
547
552
  },
548
553
 
549
554
  openToWaiting: function() {
@@ -551,11 +556,6 @@ Example:
551
556
  },
552
557
 
553
558
  openToImpermanentlyClosing: function() {
554
- // Possible to receive connection_established event after transition to impermanentlyClosing
555
- // but before socket close. Prevent this triggering a transition from impermanentlyClosing to connected
556
- // by unbinding onmessage callback.
557
- self.socket.onmessage = undefined;
558
-
559
559
  updateConnectionParameters();
560
560
  },
561
561
 
@@ -657,7 +657,7 @@ Example:
657
657
  }
658
658
 
659
659
  // callback for close and retry. Used on timeouts.
660
- function TransitionToImpermanentClosing() {
660
+ function TransitionToImpermanentlyClosing() {
661
661
  self._machine.transition('impermanentlyClosing');
662
662
  }
663
663
 
@@ -715,7 +715,7 @@ Example:
715
715
  self.connectionSecure = true;
716
716
  self.options.encrypted = true;
717
717
 
718
- self._machine.transition('impermanentlyClosing')
718
+ TransitionToImpermanentlyClosing();
719
719
  } else if (code < 4100) {
720
720
  // Permentently close connection
721
721
  self._machine.transition('permanentlyClosing')
@@ -725,7 +725,7 @@ Example:
725
725
  self._machine.transition('waiting')
726
726
  } else if (code < 4300) {
727
727
  // Reconnect immediately
728
- self._machine.transition('impermanentlyClosing')
728
+ TransitionToImpermanentlyClosing();
729
729
  } else {
730
730
  // Unknown error
731
731
  self._machine.transition('permanentlyClosing')
@@ -794,14 +794,9 @@ Example:
794
794
  self._machine.transition('waiting');
795
795
  }
796
796
 
797
- function ws_onError() {
798
- self.emit('error', {
799
- type: 'WebSocketError'
800
- });
801
-
802
- // note: required? is the socket auto closed in the case of error?
803
- self.socket.close();
804
- self._machine.transition('impermanentlyClosing');
797
+ function ws_onError(error) {
798
+ // just emit error to user - socket will already be closed by browser
799
+ self.emit('error', { type: 'WebSocketError', error: error });
805
800
  }
806
801
 
807
802
  // Updates the public state information exposed by connection
@@ -875,7 +870,7 @@ Example:
875
870
  Connection.prototype.disconnect = function() {
876
871
  if (this._machine.is('permanentlyClosed')) return;
877
872
 
878
- if (this._machine.is('waiting')) {
873
+ if (this._machine.is('waiting') || this._machine.is('failed')) {
879
874
  this._machine.transition('permanentlyClosed');
880
875
  } else {
881
876
  this._machine.transition('permanentlyClosing');
@@ -886,185 +881,151 @@ Example:
886
881
  this.Pusher.Connection = Connection;
887
882
  }).call(this);
888
883
 
889
- Pusher.Channels = function() {
890
- this.channels = {};
891
- };
884
+ ;(function() {
885
+ Pusher.Channels = function() {
886
+ this.channels = {};
887
+ };
892
888
 
893
- Pusher.Channels.prototype = {
894
- add: function(channel_name, pusher) {
895
- var existing_channel = this.find(channel_name);
896
- if (!existing_channel) {
897
- var channel = Pusher.Channel.factory(channel_name, pusher);
898
- this.channels[channel_name] = channel;
899
- return channel;
900
- } else {
901
- return existing_channel;
902
- }
903
- },
889
+ Pusher.Channels.prototype = {
890
+ add: function(channel_name, pusher) {
891
+ var existing_channel = this.find(channel_name);
892
+ if (!existing_channel) {
893
+ var channel = Pusher.Channel.factory(channel_name, pusher);
894
+ this.channels[channel_name] = channel;
895
+ return channel;
896
+ } else {
897
+ return existing_channel;
898
+ }
899
+ },
904
900
 
905
- find: function(channel_name) {
906
- return this.channels[channel_name];
907
- },
901
+ find: function(channel_name) {
902
+ return this.channels[channel_name];
903
+ },
908
904
 
909
- remove: function(channel_name) {
910
- delete this.channels[channel_name];
911
- },
905
+ remove: function(channel_name) {
906
+ delete this.channels[channel_name];
907
+ },
912
908
 
913
- disconnect: function () {
914
- for(var channel_name in this.channels){
915
- this.channels[channel_name].disconnect()
909
+ disconnect: function () {
910
+ for(var channel_name in this.channels){
911
+ this.channels[channel_name].disconnect()
912
+ }
916
913
  }
917
- }
918
- };
919
-
920
- Pusher.Channel = function(channel_name, pusher) {
921
- var self = this;
922
- Pusher.EventsDispatcher.call(this, function(event_name, event_data) {
923
- Pusher.debug('No callbacks on ' + channel_name + ' for ' + event_name);
924
- });
925
-
926
- this.pusher = pusher;
927
- this.name = channel_name;
928
- this.subscribed = false;
929
-
930
- this.bind('pusher_internal:subscription_succeeded', function(data) {
931
- self.onSubscriptionSucceeded(data);
932
- });
933
- };
934
-
935
- Pusher.Channel.prototype = {
936
- // inheritable constructor
937
- init: function() {},
938
- disconnect: function() {},
939
-
940
- onSubscriptionSucceeded: function(data) {
941
- this.subscribed = true;
942
- this.emit('pusher:subscription_succeeded');
943
- },
944
-
945
- authorize: function(pusher, callback){
946
- callback(false, {}); // normal channels don't require auth
947
- },
948
-
949
- trigger: function(event, data) {
950
- return this.pusher.send_event(event, data, this.name);
951
- }
952
- };
914
+ };
915
+
916
+ Pusher.Channel = function(channel_name, pusher) {
917
+ var self = this;
918
+ Pusher.EventsDispatcher.call(this, function(event_name, event_data) {
919
+ Pusher.debug('No callbacks on ' + channel_name + ' for ' + event_name);
920
+ });
953
921
 
954
- Pusher.Util.extend(Pusher.Channel.prototype, Pusher.EventsDispatcher.prototype);
922
+ this.pusher = pusher;
923
+ this.name = channel_name;
924
+ this.subscribed = false;
955
925
 
926
+ this.bind('pusher_internal:subscription_succeeded', function(data) {
927
+ self.onSubscriptionSucceeded(data);
928
+ });
929
+ };
956
930
 
931
+ Pusher.Channel.prototype = {
932
+ // inheritable constructor
933
+ init: function() {},
934
+ disconnect: function() {
935
+ this.subscribed = false;
936
+ this.emit("pusher_internal:disconnected");
937
+ },
957
938
 
958
- Pusher.auth_callbacks = {};
939
+ onSubscriptionSucceeded: function(data) {
940
+ this.subscribed = true;
941
+ this.emit('pusher:subscription_succeeded');
942
+ },
959
943
 
960
- Pusher.authorizers = {
961
- ajax: function(pusher, callback){
962
- var self = this, xhr;
944
+ authorize: function(socketId, options, callback){
945
+ return callback(false, {}); // normal channels don't require auth
946
+ },
963
947
 
964
- if (Pusher.XHR) {
965
- xhr = new Pusher.XHR();
966
- } else {
967
- xhr = (window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
948
+ trigger: function(event, data) {
949
+ return this.pusher.send_event(event, data, this.name);
968
950
  }
951
+ };
969
952
 
970
- xhr.open("POST", Pusher.channel_auth_endpoint, true);
971
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
972
- xhr.onreadystatechange = function() {
973
- if (xhr.readyState == 4) {
974
- if (xhr.status == 200) {
975
- var data, parsed = false;
953
+ Pusher.Util.extend(Pusher.Channel.prototype, Pusher.EventsDispatcher.prototype);
976
954
 
977
- try {
978
- data = JSON.parse(xhr.responseText);
979
- parsed = true;
980
- } catch (e) {
981
- callback(true, 'JSON returned from webapp was invalid, yet status code was 200. Data was: ' + xhr.responseText);
982
- }
983
-
984
- if (parsed) { // prevents double execution.
985
- callback(false, data);
986
- }
987
- } else {
988
- Pusher.warn("Couldn't get auth info from your webapp", status);
989
- callback(true, xhr.status);
955
+ Pusher.Channel.PrivateChannel = {
956
+ authorize: function(socketId, options, callback){
957
+ var self = this;
958
+ var authorizer = new Pusher.Channel.Authorizer(this, Pusher.channel_auth_transport, options);
959
+ return authorizer.authorize(socketId, function(err, authData) {
960
+ if(!err) {
961
+ self.emit('pusher_internal:authorized', authData);
990
962
  }
991
- }
992
- };
993
- xhr.send('socket_id=' + encodeURIComponent(pusher.connection.socket_id) + '&channel_name=' + encodeURIComponent(self.name));
994
- },
995
- jsonp: function(pusher, callback){
996
- var qstring = 'socket_id=' + encodeURIComponent(pusher.connection.socket_id) + '&channel_name=' + encodeURIComponent(this.name);
997
- var script = document.createElement("script");
998
- // Hacked wrapper.
999
- Pusher.auth_callbacks[this.name] = function(data) {
1000
- callback(false, data);
1001
- };
1002
- var callback_name = "Pusher.auth_callbacks['" + this.name + "']";
1003
- script.src = Pusher.channel_auth_endpoint+'?callback='+encodeURIComponent(callback_name)+'&'+qstring;
1004
- var head = document.getElementsByTagName("head")[0] || document.documentElement;
1005
- head.insertBefore( script, head.firstChild );
1006
- }
1007
- };
1008
963
 
1009
- Pusher.Channel.PrivateChannel = {
1010
- authorize: function(pusher, callback){
1011
- Pusher.authorizers[Pusher.channel_auth_transport].scopedTo(this)(pusher, callback);
1012
- }
1013
- };
1014
-
1015
- Pusher.Channel.PresenceChannel = {
1016
- init: function(){
1017
- this.bind('pusher_internal:member_added', function(data){
1018
- var member = this.members.add(data.user_id, data.user_info);
1019
- this.emit('pusher:member_added', member);
1020
- }.scopedTo(this))
1021
-
1022
- this.bind('pusher_internal:member_removed', function(data){
1023
- var member = this.members.remove(data.user_id);
1024
- if (member) {
1025
- this.emit('pusher:member_removed', member);
1026
- }
1027
- }.scopedTo(this))
1028
- },
964
+ callback(err, authData);
965
+ });
966
+ }
967
+ };
1029
968
 
1030
- disconnect: function(){
1031
- this.members.clear();
1032
- },
969
+ Pusher.Channel.PresenceChannel = {
970
+ init: function(){
971
+ this.members = new Members(this); // leeches off channel events
972
+ },
1033
973
 
1034
- onSubscriptionSucceeded: function(data) {
1035
- this.members._members_map = data.presence.hash;
1036
- this.members.count = data.presence.count;
1037
- this.subscribed = true;
974
+ onSubscriptionSucceeded: function(data) {
975
+ this.subscribed = true;
976
+ // We override this because we want the Members obj to be responsible for
977
+ // emitting the pusher:subscription_succeeded. It will do this after it has done its work.
978
+ }
979
+ };
1038
980
 
1039
- this.emit('pusher:subscription_succeeded', this.members);
1040
- },
981
+ var Members = function(channel) {
982
+ var self = this;
1041
983
 
1042
- members: {
1043
- _members_map: {},
1044
- count: 0,
984
+ var reset = function() {
985
+ this._members_map = {};
986
+ this.count = 0;
987
+ this.me = null;
988
+ };
989
+ reset.call(this);
990
+
991
+ channel.bind('pusher_internal:authorized', function(authorizedData) {
992
+ var channelData = JSON.parse(authorizedData.channel_data);
993
+ channel.bind("pusher_internal:subscription_succeeded", function(subscriptionData) {
994
+ self._members_map = subscriptionData.presence.hash;
995
+ self.count = subscriptionData.presence.count;
996
+ self.me = self.get(channelData.user_id);
997
+ channel.emit('pusher:subscription_succeeded', self);
998
+ });
999
+ });
1045
1000
 
1046
- each: function(callback) {
1047
- for(var i in this._members_map) {
1048
- callback({
1049
- id: i,
1050
- info: this._members_map[i]
1051
- });
1001
+ channel.bind('pusher_internal:member_added', function(data) {
1002
+ if(self.get(data.user_id) === null) { // only incr if user_id does not already exist
1003
+ self.count++;
1052
1004
  }
1053
- },
1054
1005
 
1055
- add: function(id, info) {
1056
- this._members_map[id] = info;
1057
- this.count++;
1058
- return this.get(id);
1059
- },
1006
+ self._members_map[data.user_id] = data.user_info;
1007
+ channel.emit('pusher:member_added', self.get(data.user_id));
1008
+ });
1060
1009
 
1061
- remove: function(user_id) {
1062
- var member = this.get(user_id);
1063
- if (member) {
1064
- delete this._members_map[user_id];
1065
- this.count--;
1010
+ channel.bind('pusher_internal:member_removed', function(data) {
1011
+ var member = self.get(data.user_id);
1012
+ if(member) {
1013
+ delete self._members_map[data.user_id];
1014
+ self.count--;
1015
+ channel.emit('pusher:member_removed', member);
1016
+ }
1017
+ });
1018
+
1019
+ channel.bind('pusher_internal:disconnected', function() {
1020
+ reset.call(self);
1021
+ });
1022
+ };
1023
+
1024
+ Members.prototype = {
1025
+ each: function(callback) {
1026
+ for(var i in this._members_map) {
1027
+ callback(this.get(i));
1066
1028
  }
1067
- return member;
1068
1029
  },
1069
1030
 
1070
1031
  get: function(user_id) {
@@ -1076,27 +1037,114 @@ Pusher.Channel.PresenceChannel = {
1076
1037
  } else { // have never heard of this user
1077
1038
  return null;
1078
1039
  }
1040
+ }
1041
+ };
1042
+
1043
+ Pusher.Channel.factory = function(channel_name, pusher){
1044
+ var channel = new Pusher.Channel(channel_name, pusher);
1045
+ if (channel_name.indexOf('private-') === 0) {
1046
+ Pusher.Util.extend(channel, Pusher.Channel.PrivateChannel);
1047
+ } else if (channel_name.indexOf('presence-') === 0) {
1048
+ Pusher.Util.extend(channel, Pusher.Channel.PrivateChannel);
1049
+ Pusher.Util.extend(channel, Pusher.Channel.PresenceChannel);
1050
+ };
1051
+ channel.init();
1052
+ return channel;
1053
+ };
1054
+ }).call(this);
1055
+ ;(function() {
1056
+ Pusher.Channel.Authorizer = function(channel, type, options) {
1057
+ this.channel = channel;
1058
+ this.type = type;
1059
+
1060
+ this.authOptions = (options || {}).auth || {};
1061
+ };
1062
+
1063
+ Pusher.Channel.Authorizer.prototype = {
1064
+ composeQuery: function(socketId) {
1065
+ var query = '&socket_id=' + encodeURIComponent(socketId)
1066
+ + '&channel_name=' + encodeURIComponent(this.channel.name);
1067
+
1068
+ for(var i in this.authOptions.params) {
1069
+ query += "&" + encodeURIComponent(i) + "=" + encodeURIComponent(this.authOptions.params[i]);
1070
+ }
1071
+
1072
+ return query;
1079
1073
  },
1080
1074
 
1081
- clear: function() {
1082
- this._members_map = {};
1083
- this.count = 0;
1075
+ authorize: function(socketId, callback) {
1076
+ return Pusher.authorizers[this.type].call(this, socketId, callback);
1084
1077
  }
1085
- }
1086
- };
1087
-
1088
- Pusher.Channel.factory = function(channel_name, pusher){
1089
- var channel = new Pusher.Channel(channel_name, pusher);
1090
- if (channel_name.indexOf('private-') === 0) {
1091
- Pusher.Util.extend(channel, Pusher.Channel.PrivateChannel);
1092
- } else if (channel_name.indexOf('presence-') === 0) {
1093
- Pusher.Util.extend(channel, Pusher.Channel.PrivateChannel);
1094
- Pusher.Util.extend(channel, Pusher.Channel.PresenceChannel);
1095
1078
  };
1096
- channel.init();
1097
- return channel;
1098
- };
1099
1079
 
1080
+
1081
+ Pusher.auth_callbacks = {};
1082
+ Pusher.authorizers = {
1083
+ ajax: function(socketId, callback){
1084
+ var self = this, xhr;
1085
+
1086
+ if (Pusher.XHR) {
1087
+ xhr = new Pusher.XHR();
1088
+ } else {
1089
+ xhr = (window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
1090
+ }
1091
+
1092
+ xhr.open("POST", Pusher.channel_auth_endpoint, true);
1093
+
1094
+ // add request headers
1095
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
1096
+ for(var headerName in this.authOptions.headers) {
1097
+ xhr.setRequestHeader(headerName, this.authOptions.headers[headerName]);
1098
+ }
1099
+
1100
+ xhr.onreadystatechange = function() {
1101
+ if (xhr.readyState == 4) {
1102
+ if (xhr.status == 200) {
1103
+ var data, parsed = false;
1104
+
1105
+ try {
1106
+ data = JSON.parse(xhr.responseText);
1107
+ parsed = true;
1108
+ } catch (e) {
1109
+ callback(true, 'JSON returned from webapp was invalid, yet status code was 200. Data was: ' + xhr.responseText);
1110
+ }
1111
+
1112
+ if (parsed) { // prevents double execution.
1113
+ callback(false, data);
1114
+ }
1115
+ } else {
1116
+ Pusher.warn("Couldn't get auth info from your webapp", xhr.status);
1117
+ callback(true, xhr.status);
1118
+ }
1119
+ }
1120
+ };
1121
+
1122
+ xhr.send(this.composeQuery(socketId));
1123
+ return xhr;
1124
+ },
1125
+
1126
+ jsonp: function(socketId, callback){
1127
+ if(this.authOptions.headers !== undefined) {
1128
+ Pusher.warn("Warn", "To send headers with the auth request, you must use AJAX, rather than JSONP.");
1129
+ }
1130
+
1131
+ var script = document.createElement("script");
1132
+ // Hacked wrapper.
1133
+ Pusher.auth_callbacks[this.channel.name] = function(data) {
1134
+ callback(false, data);
1135
+ };
1136
+
1137
+ var callback_name = "Pusher.auth_callbacks['" + this.channel.name + "']";
1138
+ script.src = Pusher.channel_auth_endpoint
1139
+ + '?callback='
1140
+ + encodeURIComponent(callback_name)
1141
+ + this.composeQuery(socketId);
1142
+
1143
+ var head = document.getElementsByTagName("head")[0] || document.documentElement;
1144
+ head.insertBefore( script, head.firstChild );
1145
+ }
1146
+ };
1147
+ }).call(this);
1100
1148
  var _require = (function () {
1101
1149
 
1102
1150
  var handleScriptLoaded;
data/lib/pusher-fake.rb CHANGED
@@ -14,7 +14,7 @@ require "pusher-fake/server/application"
14
14
 
15
15
  module PusherFake
16
16
  # The current version string.
17
- VERSION = "0.1.3"
17
+ VERSION = "0.1.4"
18
18
 
19
19
  # Call this method to modify the defaults.
20
20
  #
@@ -1,9 +1,13 @@
1
1
  module PusherFake
2
2
  module Channel
3
3
  class << self
4
+ # Name matcher for private channels.
4
5
  PRIVATE_CHANNEL_MATCHER = /^private-/.freeze
6
+
7
+ # Name matcher for presence channels.
5
8
  PRESENCE_CHANNEL_MATCHER = /^presence-/.freeze
6
9
 
10
+ # @return [Hash] Cache of existing channels.
7
11
  attr_accessor :channels
8
12
 
9
13
  # Create a channel, determining the type by the name.
@@ -39,6 +43,10 @@ module PusherFake
39
43
 
40
44
  private
41
45
 
46
+ # Determine the channel class to use based on the channel name.
47
+ #
48
+ # @param [String] name The name of the channel.
49
+ # @return [Class] The class to use for the channel.
42
50
  def class_for(name)
43
51
  if name =~ PRIVATE_CHANNEL_MATCHER
44
52
  Private
@@ -13,7 +13,7 @@ module PusherFake
13
13
  @members = {}
14
14
  end
15
15
 
16
- # Removes the +connection+ from the channel and notifies the channel.
16
+ # Remove the +connection+ from the channel and notify the channel.
17
17
  #
18
18
  # @param [Connection] connection The connection to remove.
19
19
  def remove(connection)
@@ -22,7 +22,7 @@ module PusherFake
22
22
  emit("pusher_internal:member_removed", members.delete(connection))
23
23
  end
24
24
 
25
- # Returns a hash containing presence information for the channel.
25
+ # Return a hash containing presence information for the channel.
26
26
  #
27
27
  # @return [Hash] Hash containing presence information.
28
28
  def subscription_data
@@ -37,6 +37,11 @@ module PusherFake
37
37
 
38
38
  private
39
39
 
40
+ # Store the member data for the connection and notify connections a
41
+ # member was added.
42
+ #
43
+ # @param [Connection] connection The connection a subscription succeeded for.
44
+ # @param [Hash] options The options for the channel.
40
45
  def subscription_succeeded(connection, options = {})
41
46
  members[connection] = Yajl::Parser.parse(options[:channel_data], symbolize_keys: true)
42
47
 
@@ -23,7 +23,7 @@ module PusherFake
23
23
  subscription_succeeded(connection, options)
24
24
  end
25
25
 
26
- # Emits an event to the channel.
26
+ # Emit an event to the channel.
27
27
  #
28
28
  # @param [String] event The event name.
29
29
  # @param [Hash] data The event data.
@@ -33,7 +33,7 @@ module PusherFake
33
33
  end
34
34
  end
35
35
 
36
- # Determines if the +connection+ is in the channel.
36
+ # Determine if the +connection+ is in the channel.
37
37
  #
38
38
  # @param [Connection] connection The connection.
39
39
  # @return [Boolean] +true+ if the connection is in the channel, +false+ otherwise.
@@ -41,19 +41,28 @@ module PusherFake
41
41
  connections.index(connection)
42
42
  end
43
43
 
44
- # Removes the +connection+ from the channel.
44
+ # Remove the +connection+ from the channel.
45
45
  #
46
46
  # @param [Connection] connection The connection to remove.
47
47
  def remove(connection)
48
48
  connections.delete(connection)
49
49
  end
50
50
 
51
+ # Return subscription data for the channel.
52
+ #
53
+ # @abstract
54
+ # @return [Hash] Subscription data for the channel.
51
55
  def subscription_data
52
56
  {}
53
57
  end
54
58
 
55
59
  private
56
60
 
61
+ # Notify the channel of the successful subscription and add the
62
+ # connection to the channel.
63
+ #
64
+ # @param [Connection] connection The connection a subscription succeeded for.
65
+ # @param [Hash] options The options for the channel.
57
66
  def subscription_succeeded(connection, options = {})
58
67
  connection.emit("pusher_internal:subscription_succeeded", subscription_data, name)
59
68
  connections.push(connection)
@@ -14,7 +14,7 @@ module PusherFake
14
14
  #
15
15
  # @param [String] event The event name.
16
16
  # @param [Hash] data The event data.
17
- # @param [String] The channel name.
17
+ # @param [String] channel The channel name.
18
18
  def emit(event, data = {}, channel = nil)
19
19
  message = { event: event, data: data }
20
20
  message[:channel] = channel if channel
@@ -23,12 +23,12 @@ module PusherFake
23
23
  socket.send(message)
24
24
  end
25
25
 
26
- # Notifies the Pusher client that a connection has been established.
26
+ # Notify the Pusher client that a connection has been established.
27
27
  def establish
28
28
  emit("pusher:connection_established", socket_id: socket.object_id)
29
29
  end
30
30
 
31
- # Processes an event.
31
+ # Process an event.
32
32
  #
33
33
  # @param [String] data The event data as JSON.
34
34
  def process(data)
@@ -36,10 +36,17 @@ module PusherFake
36
36
 
37
37
  private
38
38
 
39
+ # Convenience method for access the configuration object.
40
+ #
41
+ # @return [Configuration] The configuration object.
39
42
  def self.configuration
40
43
  PusherFake.configuration
41
44
  end
42
45
 
46
+ # Return a hash of options for the socket server based on
47
+ # the configuration.
48
+ #
49
+ # @return [Hash] The socket server configuration options.
43
50
  def self.socket_server_options
44
51
  { host: configuration.socket_host,
45
52
  port: configuration.socket_port }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pusher-fake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-09 00:00:00.000000000 Z
12
+ date: 2012-07-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: em-websocket
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 0.3.6
21
+ version: 0.3.8
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 0.3.6
29
+ version: 0.3.8
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: ruby-hmac
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -306,7 +306,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
306
306
  version: '0'
307
307
  segments:
308
308
  - 0
309
- hash: -981672882093841402
309
+ hash: 1370365380025237123
310
310
  required_rubygems_version: !ruby/object:Gem::Requirement
311
311
  none: false
312
312
  requirements:
@@ -315,7 +315,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
315
315
  version: '0'
316
316
  segments:
317
317
  - 0
318
- hash: -981672882093841402
318
+ hash: 1370365380025237123
319
319
  requirements: []
320
320
  rubyforge_project:
321
321
  rubygems_version: 1.8.23