/
canop-websocket.js
72 lines (65 loc) · 2.49 KB
/
canop-websocket.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
(function(exports, undefined) {
var canop = exports.canop;
var INITIAL_RECONNECTION_INTERVAL = 256; // ms. Increases exponentially to 10min
// client: a canop.Client instance.
// options:
// - url: string URL for the socket endpoint.
// - reconnect: if true (default), automatically reconnect when disconnected.
// - open: function run when the socket opens.
// - close: function run when the socket closes.
// (You can also rely on .canopClient.on('unsyncable', …)
// - error: function run when the socket experiences an error.
var CanopWebsocket = function(client, options) {
options = options || {};
options.url = options.url ||
// Trick: use the end of either http: or https:.
'ws' + window.location.protocol.slice(4) + '//' +
window.location.host + '/websocket';
var self = this;
this.canopClient = client;
this.canopClient.send = function(msg) {
if (self.socket === undefined ||
self.socket.readyState !== WebSocket.OPEN) {
throw new Error("WebSocket is not open for business");
}
self.socket.send(msg);
};
this.url = "" + options.url;
this.socket = null;
this.reconnect = (options.reconnect === undefined)? true: !!options.reconnect;
this.reconnectionInterval = INITIAL_RECONNECTION_INTERVAL;
this.receive = this.receive.bind(this);
this.connect(options);
};
CanopWebsocket.prototype = {
connect: function canopWebsocketConnect(options) {
var self = this;
this.socket = new WebSocket(this.url);
this.socket.addEventListener('message', this.receive);
this.socket.addEventListener('close', function(e) {
self.canopClient.emit('unsyncable');
if (self.reconnect) {
setTimeout(function() { self.connect(options); },
self.reconnectionInterval);
if (self.reconnectionInterval <= 1000 * 60 * 10) {
self.reconnectionInterval *= 2;
}
}
});
this.socket.addEventListener('open', function() {
self.reconnectionInterval = INITIAL_RECONNECTION_INTERVAL;
self.canopClient.emit('syncing');
});
if (options.error) { this.socket.addEventListener('error', options.error); }
if (options.open) { this.socket.addEventListener('open', options.open); }
if (options.close) { this.socket.addEventListener('close', options.close); }
},
receive: function canopWebsocketReceive(event) {
this.canopClient.receive('' + event.data);
},
};
canop.wire = canop.wire || {};
canop.wire.websocket = function(client, options) {
return new CanopWebsocket(client, options);
};
}(this));