Split out common drivers from chat example.
This commit is contained in:
parent
b3e2d17966
commit
a9d3e4eca4
6
Makefile
6
Makefile
|
@ -1,6 +1,10 @@
|
|||
APP_NAME=MarketplaceChat.app
|
||||
LIB_SOURCES=\
|
||||
marketplace.js
|
||||
marketplace.js \
|
||||
spy.js \
|
||||
jquery-driver.js \
|
||||
wake-detector.js \
|
||||
websocket-driver.js
|
||||
APP_SOURCES=\
|
||||
examples/chat/index.html \
|
||||
examples/chat/index.js \
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
<script src="../../third-party/jquery-2.0.3.min.js"></script>
|
||||
|
||||
<script src="../../marketplace.js"></script>
|
||||
<script src="../../spy.js"></script>
|
||||
<script src="../../jquery-driver.js"></script>
|
||||
<script src="../../wake-detector.js"></script>
|
||||
<script src="../../websocket-driver.js"></script>
|
||||
<script src="index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -29,285 +29,6 @@ function decodeAction(j) {
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Generic Spy
|
||||
|
||||
function Spy() {
|
||||
}
|
||||
|
||||
Spy.prototype.boot = function () {
|
||||
World.updateRoutes([sub(__, 0, Infinity), pub(__, 0, Infinity)]);
|
||||
};
|
||||
|
||||
Spy.prototype.handleEvent = function (e) {
|
||||
switch (e.type) {
|
||||
case "routes": console.log("SPY", "routes", e.routes); break;
|
||||
case "message": console.log("SPY", "message", e.message, e.metaLevel, e.isFeedback); break;
|
||||
default: console.log("SPY", "unknown", e); break;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// JQuery event driver
|
||||
|
||||
function spawnJQueryDriver() {
|
||||
var d = new DemandMatcher(["jQuery", __, __, __]);
|
||||
d.onDemandIncrease = function (r) {
|
||||
var selector = r.pattern[1];
|
||||
var eventName = r.pattern[2];
|
||||
World.spawn(new JQueryEventRouter(selector, eventName),
|
||||
[pub(["jQuery", selector, eventName, __]),
|
||||
pub(["jQuery", selector, eventName, __], 0, 1)]);
|
||||
};
|
||||
World.spawn(d);
|
||||
}
|
||||
|
||||
function JQueryEventRouter(selector, eventName) {
|
||||
var self = this;
|
||||
this.selector = selector;
|
||||
this.eventName = eventName;
|
||||
this.handler =
|
||||
World.wrap(function (e) {
|
||||
World.send(["jQuery", self.selector, self.eventName, e]);
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
$(this.selector).on(this.eventName, this.handler);
|
||||
}
|
||||
|
||||
JQueryEventRouter.prototype.handleEvent = function (e) {
|
||||
if (e.type === "routes" && e.routes.length === 0) {
|
||||
$(this.selector).off(this.eventName, this.handler);
|
||||
World.exit();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Wake detector - notices when something (such as
|
||||
// suspension/sleeping!) has caused periodic activities to be
|
||||
// interrupted, and warns others about it
|
||||
// Inspired by http://blog.alexmaccaw.com/javascript-wake-event
|
||||
|
||||
function WakeDetector(period) {
|
||||
this.message = "wake";
|
||||
this.period = period || 10000;
|
||||
this.mostRecentTrigger = +(new Date());
|
||||
this.timerId = null;
|
||||
}
|
||||
|
||||
WakeDetector.prototype.boot = function () {
|
||||
var self = this;
|
||||
World.updateRoutes([pub(this.message)]);
|
||||
this.timerId = setInterval(World.wrap(function () { self.trigger(); }), this.period);
|
||||
};
|
||||
|
||||
WakeDetector.prototype.handleEvent = function (e) {};
|
||||
|
||||
WakeDetector.prototype.trigger = function () {
|
||||
var now = +(new Date());
|
||||
if (now - this.mostRecentTrigger > this.period * 1.5) {
|
||||
World.send(this.message);
|
||||
}
|
||||
this.mostRecentTrigger = now;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// WebSocket client driver
|
||||
|
||||
var DEFAULT_RECONNECT_DELAY = 100;
|
||||
var MAX_RECONNECT_DELAY = 30000;
|
||||
var DEFAULT_IDLE_TIMEOUT = 300000; // 5 minutes
|
||||
var DEFAULT_PING_INTERVAL = DEFAULT_IDLE_TIMEOUT - 10000;
|
||||
|
||||
function WebSocketConnection(label, wsurl, shouldReconnect) {
|
||||
this.label = label;
|
||||
this.wsurl = wsurl;
|
||||
this.shouldReconnect = shouldReconnect ? true : false;
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
this.localRoutes = [];
|
||||
this.peerRoutes = [];
|
||||
this.prevPeerRoutesMessage = null;
|
||||
this.sock = null;
|
||||
this.deduplicator = new Deduplicator();
|
||||
|
||||
this.activityTimestamp = 0;
|
||||
this.idleTimeout = DEFAULT_IDLE_TIMEOUT;
|
||||
this.pingInterval = DEFAULT_PING_INTERVAL;
|
||||
this.idleTimer = null;
|
||||
this.pingTimer = null;
|
||||
}
|
||||
|
||||
WebSocketConnection.prototype.clearHeartbeatTimers = function () {
|
||||
if (this.idleTimer) { clearTimeout(this.idleTimer); this.idleTimer = null; }
|
||||
if (this.pingTimer) { clearTimeout(this.pingTimer); this.pingTimer = null; }
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.recordActivity = function () {
|
||||
var self = this;
|
||||
this.activityTimestamp = +(new Date());
|
||||
this.clearHeartbeatTimers();
|
||||
this.idleTimer = setTimeout(function () { self.forceclose(); },
|
||||
this.idleTimeout);
|
||||
this.pingTimer = setTimeout(function () { self.safeSend(JSON.stringify("ping")) },
|
||||
this.pingInterval);
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.statusRoute = function (status) {
|
||||
return pub([this.label + "_state", status]);
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.relayRoutes = function () {
|
||||
// fresh copy each time, suitable for in-place extension/mutation
|
||||
return [this.statusRoute(this.isConnected() ? "connected" : "disconnected"),
|
||||
pub([this.label, __, __], 0, 1000),
|
||||
sub([this.label, __, __], 0, 1000)];
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.aggregateRoutes = function () {
|
||||
var rs = this.relayRoutes();
|
||||
for (var i = 0; i < this.peerRoutes.length; i++) {
|
||||
var r = this.peerRoutes[i];
|
||||
rs.push(new Route(r.isSubscription,
|
||||
[this.label, __, r.pattern],
|
||||
r.metaLevel,
|
||||
r.level));
|
||||
}
|
||||
// console.log("WebSocketConnection.aggregateRoutes", this.label, rs);
|
||||
return rs;
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.boot = function () {
|
||||
this.reconnect();
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.trapexit = function () {
|
||||
this.forceclose();
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.isConnected = function () {
|
||||
return this.sock && this.sock.readyState === this.sock.OPEN;
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.safeSend = function (m) {
|
||||
try {
|
||||
if (this.isConnected()) { this.sock.send(m); }
|
||||
} catch (e) {
|
||||
console.warn("Trapped exn while sending", e);
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.sendLocalRoutes = function () {
|
||||
this.safeSend(JSON.stringify(encodeEvent(updateRoutes(this.localRoutes))));
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.handleEvent = function (e) {
|
||||
// console.log("WebSocketConnection.handleEvent", e);
|
||||
switch (e.type) {
|
||||
case "routes":
|
||||
this.localRoutes = [];
|
||||
for (var i = 0; i < e.routes.length; i++) {
|
||||
var r = e.routes[i];
|
||||
if (r.pattern.length && r.pattern.length === 3
|
||||
&& r.pattern[0] === this.label
|
||||
&& typeof(r.pattern[1]) === "number")
|
||||
{
|
||||
this.localRoutes.push(new Route(r.isSubscription,
|
||||
r.pattern[2],
|
||||
r.pattern[1],
|
||||
r.level));
|
||||
}
|
||||
}
|
||||
this.sendLocalRoutes();
|
||||
break;
|
||||
case "message":
|
||||
var m = e.message;
|
||||
if (m.length && m.length === 3
|
||||
&& m[0] === this.label
|
||||
&& typeof(m[1]) === "number")
|
||||
{
|
||||
var encoded = JSON.stringify(encodeEvent(sendMessage(m[2], m[1], e.isFeedback)));
|
||||
if (this.deduplicator.accept(encoded)) {
|
||||
this.safeSend(encoded);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.forceclose = function (keepReconnectDelay) {
|
||||
if (!keepReconnectDelay) {
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
}
|
||||
this.clearHeartbeatTimers();
|
||||
if (this.sock) {
|
||||
console.log("WebSocketConnection.forceclose called");
|
||||
this.sock.close();
|
||||
this.sock = null;
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.reconnect = function () {
|
||||
var self = this;
|
||||
this.forceclose(true);
|
||||
this.sock = new WebSocket(this.wsurl);
|
||||
this.sock.onopen = World.wrap(function (e) { return self.onopen(e); });
|
||||
this.sock.onmessage = World.wrap(function (e) { return self.onmessage(e); });
|
||||
this.sock.onclose = World.wrap(function (e) { return self.onclose(e); });
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.onopen = function (e) {
|
||||
console.log("connected to " + this.sock.url);
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
this.sendLocalRoutes();
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.onmessage = function (wse) {
|
||||
// console.log("onmessage", wse);
|
||||
this.recordActivity();
|
||||
|
||||
var j = JSON.parse(wse.data);
|
||||
if (j === "ping") {
|
||||
this.safeSend(JSON.stringify("pong"));
|
||||
return;
|
||||
} else if (j === "pong") {
|
||||
return; // recordActivity already took care of our timers
|
||||
}
|
||||
|
||||
var e = decodeAction(j);
|
||||
switch (e.type) {
|
||||
case "routes":
|
||||
if (this.prevPeerRoutesMessage !== wse.data) {
|
||||
this.prevPeerRoutesMessage = wse.data;
|
||||
this.peerRoutes = e.routes;
|
||||
World.updateRoutes(this.aggregateRoutes());
|
||||
}
|
||||
break;
|
||||
case "message":
|
||||
if (this.deduplicator.accept(wse.data)) {
|
||||
World.send([this.label, e.metaLevel, e.message], 0, e.isFeedback);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.onclose = function (e) {
|
||||
var self = this;
|
||||
console.log("onclose", e);
|
||||
|
||||
// Update routes to give clients some indication of the discontinuity
|
||||
World.updateRoutes(this.aggregateRoutes());
|
||||
|
||||
if (this.shouldReconnect) {
|
||||
console.log("reconnecting to " + this.wsurl + " in " + this.reconnectDelay + "ms");
|
||||
setTimeout(World.wrap(function () { self.reconnect(); }), this.reconnectDelay);
|
||||
this.reconnectDelay = this.reconnectDelay * 1.618 + (Math.random() * 1000);
|
||||
this.reconnectDelay =
|
||||
this.reconnectDelay > MAX_RECONNECT_DELAY
|
||||
? MAX_RECONNECT_DELAY + (Math.random() * 1000)
|
||||
: this.reconnectDelay;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Main
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// JQuery event driver
|
||||
|
||||
function spawnJQueryDriver() {
|
||||
var d = new DemandMatcher(["jQuery", __, __, __]);
|
||||
d.onDemandIncrease = function (r) {
|
||||
var selector = r.pattern[1];
|
||||
var eventName = r.pattern[2];
|
||||
World.spawn(new JQueryEventRouter(selector, eventName),
|
||||
[pub(["jQuery", selector, eventName, __]),
|
||||
pub(["jQuery", selector, eventName, __], 0, 1)]);
|
||||
};
|
||||
World.spawn(d);
|
||||
}
|
||||
|
||||
function JQueryEventRouter(selector, eventName) {
|
||||
var self = this;
|
||||
this.selector = selector;
|
||||
this.eventName = eventName;
|
||||
this.handler =
|
||||
World.wrap(function (e) {
|
||||
World.send(["jQuery", self.selector, self.eventName, e]);
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
$(this.selector).on(this.eventName, this.handler);
|
||||
}
|
||||
|
||||
JQueryEventRouter.prototype.handleEvent = function (e) {
|
||||
if (e.type === "routes" && e.routes.length === 0) {
|
||||
$(this.selector).off(this.eventName, this.handler);
|
||||
World.exit();
|
||||
}
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
// Generic Spy
|
||||
|
||||
function Spy() {
|
||||
}
|
||||
|
||||
Spy.prototype.boot = function () {
|
||||
World.updateRoutes([sub(__, 0, Infinity), pub(__, 0, Infinity)]);
|
||||
};
|
||||
|
||||
Spy.prototype.handleEvent = function (e) {
|
||||
switch (e.type) {
|
||||
case "routes": console.log("SPY", "routes", e.routes); break;
|
||||
case "message": console.log("SPY", "message", e.message, e.metaLevel, e.isFeedback); break;
|
||||
default: console.log("SPY", "unknown", e); break;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
// Wake detector - notices when something (such as
|
||||
// suspension/sleeping!) has caused periodic activities to be
|
||||
// interrupted, and warns others about it
|
||||
// Inspired by http://blog.alexmaccaw.com/javascript-wake-event
|
||||
|
||||
function WakeDetector(period) {
|
||||
this.message = "wake";
|
||||
this.period = period || 10000;
|
||||
this.mostRecentTrigger = +(new Date());
|
||||
this.timerId = null;
|
||||
}
|
||||
|
||||
WakeDetector.prototype.boot = function () {
|
||||
var self = this;
|
||||
World.updateRoutes([pub(this.message)]);
|
||||
this.timerId = setInterval(World.wrap(function () { self.trigger(); }), this.period);
|
||||
};
|
||||
|
||||
WakeDetector.prototype.handleEvent = function (e) {};
|
||||
|
||||
WakeDetector.prototype.trigger = function () {
|
||||
var now = +(new Date());
|
||||
if (now - this.mostRecentTrigger > this.period * 1.5) {
|
||||
World.send(this.message);
|
||||
}
|
||||
this.mostRecentTrigger = now;
|
||||
};
|
|
@ -0,0 +1,195 @@
|
|||
// WebSocket client driver
|
||||
|
||||
var DEFAULT_RECONNECT_DELAY = 100;
|
||||
var MAX_RECONNECT_DELAY = 30000;
|
||||
var DEFAULT_IDLE_TIMEOUT = 300000; // 5 minutes
|
||||
var DEFAULT_PING_INTERVAL = DEFAULT_IDLE_TIMEOUT - 10000;
|
||||
|
||||
function WebSocketConnection(label, wsurl, shouldReconnect) {
|
||||
this.label = label;
|
||||
this.wsurl = wsurl;
|
||||
this.shouldReconnect = shouldReconnect ? true : false;
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
this.localRoutes = [];
|
||||
this.peerRoutes = [];
|
||||
this.prevPeerRoutesMessage = null;
|
||||
this.sock = null;
|
||||
this.deduplicator = new Deduplicator();
|
||||
|
||||
this.activityTimestamp = 0;
|
||||
this.idleTimeout = DEFAULT_IDLE_TIMEOUT;
|
||||
this.pingInterval = DEFAULT_PING_INTERVAL;
|
||||
this.idleTimer = null;
|
||||
this.pingTimer = null;
|
||||
}
|
||||
|
||||
WebSocketConnection.prototype.clearHeartbeatTimers = function () {
|
||||
if (this.idleTimer) { clearTimeout(this.idleTimer); this.idleTimer = null; }
|
||||
if (this.pingTimer) { clearTimeout(this.pingTimer); this.pingTimer = null; }
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.recordActivity = function () {
|
||||
var self = this;
|
||||
this.activityTimestamp = +(new Date());
|
||||
this.clearHeartbeatTimers();
|
||||
this.idleTimer = setTimeout(function () { self.forceclose(); },
|
||||
this.idleTimeout);
|
||||
this.pingTimer = setTimeout(function () { self.safeSend(JSON.stringify("ping")) },
|
||||
this.pingInterval);
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.statusRoute = function (status) {
|
||||
return pub([this.label + "_state", status]);
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.relayRoutes = function () {
|
||||
// fresh copy each time, suitable for in-place extension/mutation
|
||||
return [this.statusRoute(this.isConnected() ? "connected" : "disconnected"),
|
||||
pub([this.label, __, __], 0, 1000),
|
||||
sub([this.label, __, __], 0, 1000)];
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.aggregateRoutes = function () {
|
||||
var rs = this.relayRoutes();
|
||||
for (var i = 0; i < this.peerRoutes.length; i++) {
|
||||
var r = this.peerRoutes[i];
|
||||
rs.push(new Route(r.isSubscription,
|
||||
[this.label, __, r.pattern],
|
||||
r.metaLevel,
|
||||
r.level));
|
||||
}
|
||||
// console.log("WebSocketConnection.aggregateRoutes", this.label, rs);
|
||||
return rs;
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.boot = function () {
|
||||
this.reconnect();
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.trapexit = function () {
|
||||
this.forceclose();
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.isConnected = function () {
|
||||
return this.sock && this.sock.readyState === this.sock.OPEN;
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.safeSend = function (m) {
|
||||
try {
|
||||
if (this.isConnected()) { this.sock.send(m); }
|
||||
} catch (e) {
|
||||
console.warn("Trapped exn while sending", e);
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.sendLocalRoutes = function () {
|
||||
this.safeSend(JSON.stringify(encodeEvent(updateRoutes(this.localRoutes))));
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.handleEvent = function (e) {
|
||||
// console.log("WebSocketConnection.handleEvent", e);
|
||||
switch (e.type) {
|
||||
case "routes":
|
||||
this.localRoutes = [];
|
||||
for (var i = 0; i < e.routes.length; i++) {
|
||||
var r = e.routes[i];
|
||||
if (r.pattern.length && r.pattern.length === 3
|
||||
&& r.pattern[0] === this.label
|
||||
&& typeof(r.pattern[1]) === "number")
|
||||
{
|
||||
this.localRoutes.push(new Route(r.isSubscription,
|
||||
r.pattern[2],
|
||||
r.pattern[1],
|
||||
r.level));
|
||||
}
|
||||
}
|
||||
this.sendLocalRoutes();
|
||||
break;
|
||||
case "message":
|
||||
var m = e.message;
|
||||
if (m.length && m.length === 3
|
||||
&& m[0] === this.label
|
||||
&& typeof(m[1]) === "number")
|
||||
{
|
||||
var encoded = JSON.stringify(encodeEvent(sendMessage(m[2], m[1], e.isFeedback)));
|
||||
if (this.deduplicator.accept(encoded)) {
|
||||
this.safeSend(encoded);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.forceclose = function (keepReconnectDelay) {
|
||||
if (!keepReconnectDelay) {
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
}
|
||||
this.clearHeartbeatTimers();
|
||||
if (this.sock) {
|
||||
console.log("WebSocketConnection.forceclose called");
|
||||
this.sock.close();
|
||||
this.sock = null;
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.reconnect = function () {
|
||||
var self = this;
|
||||
this.forceclose(true);
|
||||
this.sock = new WebSocket(this.wsurl);
|
||||
this.sock.onopen = World.wrap(function (e) { return self.onopen(e); });
|
||||
this.sock.onmessage = World.wrap(function (e) { return self.onmessage(e); });
|
||||
this.sock.onclose = World.wrap(function (e) { return self.onclose(e); });
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.onopen = function (e) {
|
||||
console.log("connected to " + this.sock.url);
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
this.sendLocalRoutes();
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.onmessage = function (wse) {
|
||||
// console.log("onmessage", wse);
|
||||
this.recordActivity();
|
||||
|
||||
var j = JSON.parse(wse.data);
|
||||
if (j === "ping") {
|
||||
this.safeSend(JSON.stringify("pong"));
|
||||
return;
|
||||
} else if (j === "pong") {
|
||||
return; // recordActivity already took care of our timers
|
||||
}
|
||||
|
||||
var e = decodeAction(j);
|
||||
switch (e.type) {
|
||||
case "routes":
|
||||
if (this.prevPeerRoutesMessage !== wse.data) {
|
||||
this.prevPeerRoutesMessage = wse.data;
|
||||
this.peerRoutes = e.routes;
|
||||
World.updateRoutes(this.aggregateRoutes());
|
||||
}
|
||||
break;
|
||||
case "message":
|
||||
if (this.deduplicator.accept(wse.data)) {
|
||||
World.send([this.label, e.metaLevel, e.message], 0, e.isFeedback);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketConnection.prototype.onclose = function (e) {
|
||||
var self = this;
|
||||
console.log("onclose", e);
|
||||
|
||||
// Update routes to give clients some indication of the discontinuity
|
||||
World.updateRoutes(this.aggregateRoutes());
|
||||
|
||||
if (this.shouldReconnect) {
|
||||
console.log("reconnecting to " + this.wsurl + " in " + this.reconnectDelay + "ms");
|
||||
setTimeout(World.wrap(function () { self.reconnect(); }), this.reconnectDelay);
|
||||
this.reconnectDelay = this.reconnectDelay * 1.618 + (Math.random() * 1000);
|
||||
this.reconnectDelay =
|
||||
this.reconnectDelay > MAX_RECONNECT_DELAY
|
||||
? MAX_RECONNECT_DELAY + (Math.random() * 1000)
|
||||
: this.reconnectDelay;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue