Added exponential backoff to reconnection

Also made the number of reconnect attempts settable
Doesn't attempt a reconnection if we intentionally disconnect
Make sure the fire-and-forget for TURN activity doesn't result in unhandled promise rejection.
This commit is contained in:
Marc Brooks 2025-09-30 17:40:37 -05:00
parent 0984ca7e40
commit 69f429d0a5
No known key found for this signature in database
GPG Key ID: 583A6AF2D6AE1DC6
1 changed files with 20 additions and 9 deletions

View File

@ -146,6 +146,7 @@ export default function KvmIdRoute() {
const { otaState, setOtaState, setModalView } = useUpdateStore();
const [loadingMessage, setLoadingMessage] = useState("Connecting to device...");
const cleanupAndStopReconnecting = useCallback(
function cleanupAndStopReconnecting() {
console.log("Closing peer connection");
@ -182,11 +183,11 @@ export default function KvmIdRoute() {
pc: RTCPeerConnection,
remoteDescription: RTCSessionDescriptionInit,
) {
setLoadingMessage("Setting remote description");
setLoadingMessage("Setting remote description type:" + remoteDescription.type);
try {
await pc.setRemoteDescription(new RTCSessionDescription(remoteDescription));
console.log("[setRemoteSessionDescription] Remote description set successfully");
console.log("[setRemoteSessionDescription] Remote description set successfully to: " + remoteDescription.sdp);
setLoadingMessage("Establishing secure connection...");
} catch (error) {
console.error(
@ -231,9 +232,15 @@ export default function KvmIdRoute() {
const ignoreOffer = useRef(false);
const isSettingRemoteAnswerPending = useRef(false);
const makingOffer = useRef(false);
const reconnectAttemptsRef = useRef(20);
const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:";
const reconnectInterval = (attempt: number) => {
// Exponential backoff with a max of 10 seconds between attempts
return Math.min(500 * 2 ** attempt, 10000);
}
const { sendMessage, getWebSocket } = useWebSocket(
isOnDevice
? `${wsProtocol}//${window.location.host}/webrtc/signaling/client`
@ -241,17 +248,16 @@ export default function KvmIdRoute() {
{
heartbeat: true,
retryOnError: true,
reconnectAttempts: 15,
reconnectInterval: 1000,
onReconnectStop: () => {
console.debug("Reconnect stopped");
reconnectAttempts: reconnectAttemptsRef.current,
reconnectInterval: reconnectInterval,
onReconnectStop: (attempt: number) => {
console.debug("Reconnect stopped after ", attempt, "attempts");
cleanupAndStopReconnecting();
},
shouldReconnect(event) {
console.debug("[Websocket] shouldReconnect", event);
// TODO: Why true?
return true;
return !connectionFailed; // we always want to try to reconnect unless we're explicitly stopped
},
onClose(event) {
@ -284,6 +290,7 @@ export default function KvmIdRoute() {
*/
const parsedMessage = JSON.parse(message.data);
if (parsedMessage.type === "device-metadata") {
const { deviceVersion } = parsedMessage.data;
console.debug("[Websocket] Received device-metadata message");
@ -300,10 +307,12 @@ export default function KvmIdRoute() {
console.log("[Websocket] Device is using new signaling");
isLegacySignalingEnabled.current = false;
}
setupPeerConnection();
}
if (!peerConnection) return;
if (parsedMessage.type === "answer") {
console.debug("[Websocket] Received answer");
const readyForOffer =
@ -594,6 +603,8 @@ export default function KvmIdRoute() {
api.POST(`${CLOUD_API}/webrtc/turn_activity`, {
bytesReceived: bytesReceivedDelta,
bytesSent: bytesSentDelta,
}).catch(()=>{
// we don't care about errors here, but we don't want unhandled promise rejections
});
}, 10000);