|
53 | 53 | function $WebSocketProvider($rootScope, $q, $timeout, $websocketBackend) {
|
54 | 54 |
|
55 | 55 | function $WebSocket(url, protocols, options) {
|
56 |
| - // var bits = url.split('/'); |
57 |
| - |
58 | 56 | if (!options && isObject(protocols) && !isArray(protocols)) {
|
59 | 57 | options = protocols;
|
60 | 58 | protocols = undefined;
|
|
73 | 71 | // TODO: refactor options to use isDefined
|
74 | 72 | this.scope = options && options.scope || $rootScope;
|
75 | 73 | this.rootScopeFailover = options && options.rootScopeFailover && true;
|
76 |
| - // this.useApplyAsync = options && options.useApplyAsync || false; |
| 74 | + this.useApplyAsync = options && options.useApplyAsync || false; |
77 | 75 | this._reconnectAttempts = options && options.reconnectAttempts || 0;
|
78 | 76 | this.initialTimeout = options && options.initialTimeout || 500; // 500ms
|
79 | 77 | this.maxTimeout = options && options.maxTimeout || 5 * 60 * 1000; // 5 minutes
|
|
113 | 111 | };
|
114 | 112 |
|
115 | 113 | $WebSocket.prototype.bindToScope = function bindToScope(scope) {
|
| 114 | + var self = this; |
116 | 115 | if (scope) {
|
117 | 116 | this.scope = scope;
|
118 | 117 | if (this.rootScopeFailover) {
|
119 | 118 | this.scope.$on('$destroy', function() {
|
120 |
| - this.scope = $rootScope; |
| 119 | + self.scope = $rootScope; |
121 | 120 | });
|
122 | 121 | }
|
123 | 122 | }
|
124 |
| - return this; |
| 123 | + return self; |
125 | 124 | };
|
126 | 125 |
|
127 | 126 | $WebSocket.prototype._connect = function _connect(force) {
|
128 | 127 | if (force || !this.socket || this.socket.readyState !== this._readyStateConstants.OPEN) {
|
129 | 128 | this.socket = $websocketBackend.create(this.url, this.protocols);
|
130 |
| - this.socket.onopen = this._onOpenHandler.bind(this); |
131 | 129 | this.socket.onmessage = this._onMessageHandler.bind(this);
|
| 130 | + this.socket.onopen = this._onOpenHandler.bind(this); |
132 | 131 | this.socket.onerror = this._onErrorHandler.bind(this);
|
133 | 132 | this.socket.onclose = this._onCloseHandler.bind(this);
|
134 | 133 | }
|
|
145 | 144 | }
|
146 | 145 | };
|
147 | 146 |
|
148 |
| - $WebSocket.prototype.notifyOpenCallbacks = function notifyOpenCallbacks() { |
| 147 | + $WebSocket.prototype.notifyOpenCallbacks = function notifyOpenCallbacks(event) { |
149 | 148 | for (var i = 0; i < this.onOpenCallbacks.length; i++) {
|
150 |
| - this.onOpenCallbacks[i].call(this); |
| 149 | + this.onOpenCallbacks[i].call(this, event); |
151 | 150 | }
|
152 | 151 | };
|
153 | 152 |
|
|
196 | 195 | return this;
|
197 | 196 | };
|
198 | 197 |
|
199 |
| - $WebSocket.prototype._onOpenHandler = function _onOpenHandler() { |
| 198 | + $WebSocket.prototype._onOpenHandler = function _onOpenHandler(event) { |
200 | 199 | this._reconnectAttempts = 0;
|
201 |
| - this.notifyOpenCallbacks(); |
| 200 | + this.notifyOpenCallbacks(event); |
202 | 201 | this.fireQueue();
|
203 | 202 | };
|
204 | 203 |
|
|
215 | 214 |
|
216 | 215 | $WebSocket.prototype._onMessageHandler = function _onMessageHandler(message) {
|
217 | 216 | var pattern;
|
218 |
| - var socketInstance = this; |
| 217 | + var self = this; |
219 | 218 | var currentCallback;
|
220 |
| - for (var i = 0; i < socketInstance.onMessageCallbacks.length; i++) { |
221 |
| - currentCallback = socketInstance.onMessageCallbacks[i]; |
| 219 | + for (var i = 0; i < self.onMessageCallbacks.length; i++) { |
| 220 | + currentCallback = self.onMessageCallbacks[i]; |
222 | 221 | pattern = currentCallback.pattern;
|
223 | 222 | if (pattern) {
|
224 | 223 | if (isString(pattern) && message.data === pattern) {
|
225 |
| - currentCallback.fn.call(socketInstance, message); |
226 |
| - socketInstance.safeDigest(currentCallback.autoApply); |
| 224 | + applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message); |
227 | 225 | }
|
228 | 226 | else if (pattern instanceof RegExp && pattern.exec(message.data)) {
|
229 |
| - currentCallback.fn.call(socketInstance, message); |
230 |
| - socketInstance.safeDigest(currentCallback.autoApply); |
| 227 | + applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message); |
231 | 228 | }
|
232 | 229 | }
|
233 | 230 | else {
|
234 |
| - currentCallback.fn.call(socketInstance, message); |
235 |
| - socketInstance.safeDigest(currentCallback.autoApply); |
| 231 | + applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message); |
| 232 | + } |
| 233 | + } |
| 234 | + |
| 235 | + function applyAsyncOrDigest(callback, autoApply, args) { |
| 236 | + args = arraySlice.call(arguments, 2); |
| 237 | + if (self.useApplyAsync) { |
| 238 | + self.scope.$applyAsync(function() { |
| 239 | + callback.apply(self, args); |
| 240 | + }); |
| 241 | + } else { |
| 242 | + callback.apply(self, args); |
| 243 | + self.safeDigest(autoApply); |
236 | 244 | }
|
237 | 245 | }
|
| 246 | + |
238 | 247 | };
|
239 | 248 |
|
240 | 249 | $WebSocket.prototype.close = function close(force) {
|
|
246 | 255 |
|
247 | 256 | $WebSocket.prototype.send = function send(data) {
|
248 | 257 | var deferred = $q.defer();
|
249 |
| - var socketInstance = this; |
| 258 | + var self = this; |
250 | 259 | var promise = cancelableify(deferred.promise);
|
251 | 260 |
|
252 |
| - if (socketInstance.readyState === socketInstance._readyStateConstants.RECONNECT_ABORTED) { |
| 261 | + if (self.readyState === self._readyStateConstants.RECONNECT_ABORTED) { |
253 | 262 | deferred.reject('Socket connection has been closed');
|
254 | 263 | }
|
255 | 264 | else {
|
256 |
| - socketInstance.sendQueue.push({ |
| 265 | + self.sendQueue.push({ |
257 | 266 | message: data,
|
258 | 267 | deferred: deferred
|
259 | 268 | });
|
260 |
| - socketInstance.fireQueue(); |
| 269 | + self.fireQueue(); |
261 | 270 | }
|
262 | 271 |
|
263 | 272 | // Credit goes to @btford
|
|
272 | 281 | }
|
273 | 282 |
|
274 | 283 | function cancel(reason) {
|
275 |
| - socketInstance.sendQueue.splice(socketInstance.sendQueue.indexOf(data), 1); |
| 284 | + self.sendQueue.splice(self.sendQueue.indexOf(data), 1); |
276 | 285 | deferred.reject(reason);
|
277 |
| - return socketInstance; |
| 286 | + return self; |
278 | 287 | }
|
279 | 288 |
|
280 | 289 | return promise;
|
281 | 290 | };
|
282 | 291 |
|
283 | 292 | $WebSocket.prototype.reconnect = function reconnect() {
|
284 |
| - var socketInstance = this; |
285 |
| - socketInstance.close(); |
| 293 | + this.close(); |
286 | 294 |
|
287 |
| - $timeout(socketInstance._connect, socketInstance._getBackoffDelay(++socketInstance._reconnectAttempts)); |
| 295 | + $timeout(this._connect.bind(this), this._getBackoffDelay(++this._reconnectAttempts)); |
288 | 296 |
|
289 |
| - return socketInstance; |
| 297 | + return this; |
290 | 298 | };
|
291 | 299 | // Exponential Backoff Formula by Prof. Douglas Thain
|
292 | 300 | // http://dthain.blogspot.co.uk/2009/02/exponential-backoff-in-distributed.html
|
|
334 | 342 | };
|
335 | 343 | }
|
336 | 344 |
|
337 |
| - // $WebSocketBackendProvider.$inject = ['$window']; |
| 345 | + // $WebSocketBackendProvider.$inject = ['$window', '$log']; |
338 | 346 | function $WebSocketBackendProvider($window, $log) {
|
339 | 347 | this.create = function create(url, protocols) {
|
340 | 348 | var match = /wss?:\/\//.exec(url);
|
|
0 commit comments