pusher-fake 0.1.3 → 0.1.4

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.
@@ -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