|
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