Skip to content

Commit

Permalink
automatically reconnect to server
Browse files Browse the repository at this point in the history
  • Loading branch information
rmorshea committed Mar 27, 2021
1 parent 2a43df7 commit 3477e2b
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 17 deletions.
89 changes: 72 additions & 17 deletions src/idom/client/app/src/index.js
@@ -1,4 +1,8 @@
import { mountLayout } from "idom-client-react";
import { unmountComponentAtNode } from "react-dom";

const maxReconnectTimeout = 45;
const initialReconnectTimeoutRange = 5;

const userPackages = import("./user-packages.js").then((module) => {
for (const pkgName in module.default) {
Expand All @@ -8,23 +12,6 @@ const userPackages = import("./user-packages.js").then((module) => {
}
});

export function mountLayoutWithWebSocket(element, endpoint, importSourceURL) {
const ws = new WebSocket(endpoint || defaultWebSocketEndpoint());

function saveUpdateHook(update) {
ws.onmessage = (event) => {
const [pathPrefix, patch] = JSON.parse(event.data);
update(pathPrefix, patch);
};
}

function sendCallback(event) {
ws.send(JSON.stringify(event));
}

mountLayout(element, saveUpdateHook, sendCallback, importSourceURL || "./");
}

function defaultWebSocketEndpoint() {
const uri = document.location.hostname + ":" + document.location.port;
const url = (uri + document.location.pathname).split("/").slice(0, -1);
Expand All @@ -40,3 +27,71 @@ function defaultWebSocketEndpoint() {

return protocol + "//" + url.join("/") + window.location.search;
}

export function mountLayoutWithWebSocket(
element,
endpoint = defaultWebSocketEndpoint(),
importSourceURL = "./",
mountState = {
everMounted: false,
reconnectAttempts: 0,
reconnectTimeoutRange: initialReconnectTimeoutRange,
}
) {
const socket = new WebSocket(endpoint);

let resolveUpdateHook = null;
let rejectUpdateHook = null;
const updateHookPromise = new Promise((resolve, reject) => {
resolveUpdateHook = resolve;
rejectUpdateHook = reject;
});

socket.onopen = (event) => {
console.log(`Connected to ${endpoint}`);
if (mountState.everMounted) {
unmountComponentAtNode(element);
}
mountLayout(
element,
(updateHook) => resolveUpdateHook(updateHook),
(event) => socket.send(JSON.stringify(event)),
importSourceURL
);
_setOpenMountState(mountState);
};

socket.onmessage = (event) => {
updateHookPromise.then((update) => {
const [pathPrefix, patch] = JSON.parse(event.data);
update(pathPrefix, patch);
});
};

socket.onclose = (event) => {
const reconnectTimeout = _nextReconnectTimeout(mountState);
console.log(`Connection lost, reconnecting in ${reconnectTimeout} seconds`);
setTimeout(function () {
mountState.reconnectAttempts++;
mountLayoutWithWebSocket(element, endpoint, importSourceURL, mountState);
}, reconnectTimeout * 1000);
};
}

function _setOpenMountState(mountState) {
mountState.everMounted = true;
mountState.reconnectAttempts = 0;
mountState.reconnectTimeoutRange = initialReconnectTimeoutRange;
}

function _nextReconnectTimeout(mountState) {
const timeout = Math.floor(Math.random() * mountState.reconnectTimeoutRange);
mountState.reconnectTimeoutRange =
(mountState.reconnectTimeoutRange + 5) % maxReconnectTimeout;
if (mountState.reconnectAttempts == 3) {
window.alert(
"Server connection was lost. Attempts to reconnect are being made in the background."
);
}
return timeout;
}
2 changes: 2 additions & 0 deletions tests/test_client/test_app.py
@@ -0,0 +1,2 @@
def test_automatic_reconnect():
assert False

0 comments on commit 3477e2b

Please sign in to comment.