From 15312ac659f5720d5ff53b51ba8030aea2bcf2bd Mon Sep 17 00:00:00 2001
From: Christoph Guttandin <chrisguttandin@media-codings.com>
Date: Mon, 13 Nov 2023 22:20:47 +0100
Subject: [PATCH] fix: cancel endlessly gathering connections

---
 src/functions/create-backoff.ts          |  8 ++++++++
 src/operators/negotiate-data-channels.ts | 20 ++++++++++++++++++++
 2 files changed, 28 insertions(+)
 create mode 100644 src/functions/create-backoff.ts

diff --git a/src/functions/create-backoff.ts b/src/functions/create-backoff.ts
new file mode 100644
index 00000000..cd7fd478
--- /dev/null
+++ b/src/functions/create-backoff.ts
@@ -0,0 +1,8 @@
+export const createBackoff = (base: number) =>
+    <const>[
+        () => base ** 2,
+        () => {
+            // tslint:disable-next-line:no-parameter-reassignment
+            base += 1;
+        }
+    ];
diff --git a/src/operators/negotiate-data-channels.ts b/src/operators/negotiate-data-channels.ts
index dc516517..89984c77 100644
--- a/src/operators/negotiate-data-channels.ts
+++ b/src/operators/negotiate-data-channels.ts
@@ -9,19 +9,23 @@ import {
     finalize,
     from,
     ignoreElements,
+    iif,
     interval,
     merge,
     mergeMap,
     of,
     retry,
+    switchMap,
     take,
     takeUntil,
     tap,
     throwError,
+    timer,
     zip
 } from 'rxjs';
 import { inexorably } from 'rxjs-etc/operators';
 import { on } from 'subscribable-things';
+import { createBackoff } from '../functions/create-backoff';
 import { IErrorEvent, IPingEvent, IPongEvent, IUpdateEvent } from '../interfaces';
 import { TDataChannelTuple, TIncomingNegotiationEvent, TOutgoingSignalingEvent, TSendPeerToPeerMessageFunction } from '../types';
 import { echo } from './echo';
@@ -138,8 +142,24 @@ export const negotiateDataChannels =
 
                             return () => unsubscribeFunctions.forEach((unsubscribeFunction) => unsubscribeFunction());
                         };
+                        const [getBackoff, incrementBackoff] = createBackoff(1);
                         const subscribeToPeerConnection = () => {
+                            const subscription = merge(on(peerConnection, 'icecandidate'), on(peerConnection, 'icegatheringstatechange'))
+                                .pipe(
+                                    switchMap(() =>
+                                        iif(
+                                            () => peerConnection.iceGatheringState === 'gathering',
+                                            defer(() => timer(10_000 * getBackoff())),
+                                            EMPTY
+                                        )
+                                    )
+                                )
+                                .subscribe(() => {
+                                    incrementBackoff();
+                                    errorSubject.next(new Error('RTCPeerConnection seems to be stuck at iceGatheringState "gathering".'));
+                                });
                             const unsubscribeFunctions = [
+                                () => subscription.unsubscribe(),
                                 on(
                                     peerConnection,
                                     'connectionstatechange'