-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathservice.hub.js
292 lines (229 loc) · 6.75 KB
/
service.hub.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
(function ($, angular, document) {
'use strict';
HubFactory.$inject = ['$rootScope', '$q', 'HubConnectionEvents'];
function HubFactory($rootScope, $q, ConnectionEvents) {
/**
* Class Hub
* This is a re-usable Class
* @example
*
* var myHub = new Hub('myHub');
*
* myHub.send('sendMessage', 'Hello from Client');
*
* myHub.on('receiveMessage', function(msg){ console.log('Server:', msg); });
*
* @param {String} hubName
* @param [{Object}] options
*/
function Hub(hubName, options) {
// Ensure a hub name was passed
if (!hubName) {
throw new Error('Hub name was not specified, be sure to pass it in when invoking the Hub class');
}
// Hub Settings
var settings = angular.extend({
// Enable hub logging events
loggingEnabled: false,
// Connection path to use
connectionPath: '.'
}, options);
// Create and set the connection property
this.connection = $.hubConnection(settings.connectionPath);
// Set Logging
this.connection.logging = settings.loggingEnabled;
// Create and set the Hub Proxy
this.proxy = this.connection.createHubProxy(hubName);
// Bind to connection events , this is only done once.
bindConnectionEvents(this);
}
/**
* Add the following methods to the Hub.prototype chain
*/
Hub.prototype = {
/**
* Starts the hub connection
* @return {Promise}
*/
start: function start() {
return this.connection.start();
},
/**
* Hub.on
* @param {String} evt
* @param {Function} fn
*/
on: function on(evt, fn) {
this.proxy.on(evt, function () {
var args = arguments;
// Have angular run a digest
$rootScope.$evalAsync(function () {
fn.apply(fn, args);
});
});
return this; // Return for chaining
},
/**
* Hub.off
* Stops listening to passed in event
*
* @example
* Hub.off('getDataFromHub', getDataFromHubCallback);
*/
off: function () {
this.proxy.off.apply(this.proxy, arguments);
},
/**
* Hub.invoke
* Method will ensure that a connection has been established before
* calling to the hub
*
* @example
* Hub.invoke('sendMessage', 'Message to Send');
*/
invoke: function invoke() {
// Store the passed in arguments
var args = arguments,
// Send will always return a promise.
// Promises are resolved by the hub invoke method
deferred = $q.defer(),
// Internal context
self = this
;
// Resolve the invoke call and it's promise
function resolve() {
// Our promise is either resolved or rejected by the hubs response.
self.proxy.invoke.apply(self.proxy, args).then(deferred.resolve, deferred.reject);
}
// Resolve the method immediately if the connection is established
if (this.connection.state === $.signalR.connectionState.connected) {
resolve();
}
// In the event that we're disconnected
if (this.connection.state === $.signalR.connectionState.disconnected) {
// Start the connection, then resolve once we're connected
this.start().done(function () {
resolve();
});
}
// Return the promise
return deferred.promise;
},
/**
* Alias for invoke
*/
send: function () {
return this.invoke.apply(this, arguments);
},
/**
* Exposes the Hubs connection status
*/
connectionStatus: {
// Disconnected flag
disconnected: false,
// Reconnecting flag
reconnecting: false,
/**
* Determine if the hub is connected
* @return boolean
*/
isConnected: function () {
return !this.disconnected && !this.reconnecting;
},
/**
* Is connection disconnected
*/
isDisconnected: function () {
return this.disconnected;
},
/**
* Is Reconnecting
*/
isReconnecting: function () {
return this.reconnecting;
},
/**
* Determine if the hub connection is down
*
* @return boolean
*/
isDown: function () {
return this.disconnected || this.reconnecting;
},
/**
* Update the connection status
* @param {Boolean} reconnectVal
* @param {Boolean} disconnectVal
*/
setConnection: function (reconnectVal, disconnectVal) {
var self = this;
// Ask angular to udpate the digest
$rootScope.$evalAsync(function () {
self.reconnecting = reconnectVal;
self.disconnected = disconnectVal;
});
}
}
};
/**
* Bind to the connection events.
* This is a private method, we use it to bind the hubs connection events when constructed.
*
* @param {Hub} hubInstance
*/
function bindConnectionEvents(hubInstance) {
/**
* Uses rootScope to broadcast the desired connection event
*/
function broadcastConnectionEvent() {
$rootScope.$broadcast.apply($rootScope, arguments);
}
/**
* Update the connection status on the hub, when the state changes
*/
function updateConnectionState(evt, state) {
var reconnecting = state.newState === $.signalR.connectionState.reconnecting,
disconnected = state.newState === $.signalR.connectionState.disconnected
;
hubInstance.connectionStatus.setConnection(reconnecting, disconnected);
}
// Hook into the change event
$rootScope.$on(ConnectionEvents.change, updateConnectionState);
// Bind to the connection reconnecting event
hubInstance.connection.reconnecting(function () {
broadcastConnectionEvent(ConnectionEvents.reconnecting);
});
// Bind to the connection reconnected event
hubInstance.connection.reconnected(function () {
broadcastConnectionEvent(ConnectionEvents.reconnected);
});
// Bind to the connection disconnected event
hubInstance.connection.disconnected(function () {
broadcastConnectionEvent(ConnectionEvents.disconnected);
});
// Bind to the connection error event
hubInstance.connection.error(function (error, data) {
broadcastConnectionEvent(ConnectionEvents.error, error, data);
});
// Bind to the connection change event
hubInstance.connection.stateChanged(function (state) {
broadcastConnectionEvent(ConnectionEvents.change, state);
});
}
// Return our Class
return Hub;
}
angular.module('services.hub', [])
// Hub Conncetion event object
// This can be used throughout the application to hook into the $scope or $rootScope for connection events
//
.value('HubConnectionEvents', {
change: 'hub:connection:change',
error: 'hub:connection:error',
disconnected: 'hub:connection:disconnected',
reconnected: 'hub:connection:reconnected',
reconnecting: 'hub:connection:reconnecting'
})
// Register the Hub Proxy Service
.factory('HubProxy', HubFactory);
})(window.jQuery, window.angular, document);