mirror of https://github.com/jetkvm/kvm.git
Improve error handling when `RTCPeerConnection` throws (#289)
* fix(WebRTC): improve error handling during peer connection creation and add connection error overlay * refactor: update peer connection state handling and improve type definitions across components
This commit is contained in:
parent
3b711db781
commit
a3580b5465
|
@ -36,7 +36,7 @@ export default function DashboardNavbar({
|
|||
picture,
|
||||
kvmName,
|
||||
}: NavbarProps) {
|
||||
const peerConnectionState = useRTCStore(state => state.peerConnection?.connectionState);
|
||||
const peerConnectionState = useRTCStore(state => state.peerConnectionState);
|
||||
const setUser = useUserStore(state => state.setUser);
|
||||
const navigate = useNavigate();
|
||||
const onLogout = useCallback(async () => {
|
||||
|
|
|
@ -9,19 +9,22 @@ const PeerConnectionStatusMap = {
|
|||
failed: "Connection failed",
|
||||
closed: "Closed",
|
||||
new: "Connecting",
|
||||
};
|
||||
} as Record<RTCPeerConnectionState | "error" | "closing", string>;
|
||||
|
||||
export type PeerConnections = keyof typeof PeerConnectionStatusMap;
|
||||
|
||||
type StatusProps = Record<PeerConnections, {
|
||||
type StatusProps = Record<
|
||||
PeerConnections,
|
||||
{
|
||||
statusIndicatorClassName: string;
|
||||
}>;
|
||||
}
|
||||
>;
|
||||
|
||||
export default function PeerConnectionStatusCard({
|
||||
state,
|
||||
title,
|
||||
}: {
|
||||
state?: PeerConnections;
|
||||
state?: RTCPeerConnectionState | null;
|
||||
title?: string;
|
||||
}) {
|
||||
if (!state) return null;
|
||||
|
|
|
@ -8,11 +8,14 @@ import { HidState } from "@/hooks/stores";
|
|||
|
||||
type USBStates = HidState["usbState"];
|
||||
|
||||
type StatusProps = Record<USBStates, {
|
||||
type StatusProps = Record<
|
||||
USBStates,
|
||||
{
|
||||
icon: React.FC<{ className: string | undefined }>;
|
||||
iconClassName: string;
|
||||
statusIndicatorClassName: string;
|
||||
}>;
|
||||
}
|
||||
>;
|
||||
|
||||
const USBStateMap: Record<USBStates, string> = {
|
||||
configured: "Connected",
|
||||
|
@ -27,9 +30,8 @@ export default function USBStateStatus({
|
|||
peerConnectionState,
|
||||
}: {
|
||||
state: USBStates;
|
||||
peerConnectionState?: RTCPeerConnectionState;
|
||||
peerConnectionState: RTCPeerConnectionState | null;
|
||||
}) {
|
||||
|
||||
const StatusCardProps: StatusProps = {
|
||||
configured: {
|
||||
icon: ({ className }) => (
|
||||
|
|
|
@ -126,7 +126,7 @@ export default function KvmIdRoute() {
|
|||
|
||||
const setIsTurnServerInUse = useRTCStore(state => state.setTurnServerInUse);
|
||||
const peerConnection = useRTCStore(state => state.peerConnection);
|
||||
|
||||
const peerConnectionState = useRTCStore(state => state.peerConnectionState);
|
||||
const setPeerConnectionState = useRTCStore(state => state.setPeerConnectionState);
|
||||
const setMediaMediaStream = useRTCStore(state => state.setMediaStream);
|
||||
const setPeerConnection = useRTCStore(state => state.setPeerConnection);
|
||||
|
@ -153,6 +153,7 @@ export default function KvmIdRoute() {
|
|||
// However, the onconnectionstatechange event doesn't fire when close() is called manually
|
||||
// So we need to explicitly update our state to maintain consistency
|
||||
// I don't know why this is happening, but this is the best way I can think of to handle it
|
||||
// ALSO, this will render the connection error overlay linking to docs
|
||||
setPeerConnectionState("closed");
|
||||
},
|
||||
[peerConnection, setPeerConnectionState],
|
||||
|
@ -255,12 +256,19 @@ export default function KvmIdRoute() {
|
|||
setStartedConnectingAt(new Date());
|
||||
setConnectedAt(null);
|
||||
|
||||
const pc = new RTCPeerConnection({
|
||||
// We only use STUN or TURN servers if we're in the cloud
|
||||
...(isInCloud && iceConfig?.iceServers
|
||||
? { iceServers: [iceConfig?.iceServers] }
|
||||
: {}),
|
||||
});
|
||||
let pc: RTCPeerConnection;
|
||||
try {
|
||||
pc = new RTCPeerConnection({
|
||||
// We only use STUN or TURN servers if we're in the cloud
|
||||
...(isInCloud && iceConfig?.iceServers
|
||||
? { iceServers: [iceConfig?.iceServers] }
|
||||
: {}),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Error creating peer connection: ${e}`);
|
||||
closePeerConnection();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up event listeners and data channels
|
||||
pc.onconnectionstatechange = () => {
|
||||
|
@ -296,8 +304,10 @@ export default function KvmIdRoute() {
|
|||
setPeerConnection(pc);
|
||||
} catch (e) {
|
||||
console.error(`Error creating offer: ${e}`);
|
||||
closePeerConnection();
|
||||
}
|
||||
}, [
|
||||
closePeerConnection,
|
||||
iceConfig?.iceServers,
|
||||
sdp,
|
||||
setDiskChannel,
|
||||
|
@ -315,9 +325,8 @@ export default function KvmIdRoute() {
|
|||
if (location.pathname.includes("other-session")) return;
|
||||
|
||||
// If we're already connected or connecting, we don't need to connect
|
||||
if (
|
||||
["connected", "connecting", "new"].includes(peerConnection?.connectionState ?? "")
|
||||
) {
|
||||
// We have to use the state from the store, because the peerConnection.connectionState doesnt trigger a value change, if called manually from .close()
|
||||
if (["connected", "connecting", "new"].includes(peerConnectionState ?? "")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -331,12 +340,7 @@ export default function KvmIdRoute() {
|
|||
connectWebRTC();
|
||||
}, 3000);
|
||||
return () => clearInterval(interval);
|
||||
}, [
|
||||
connectWebRTC,
|
||||
connectionFailed,
|
||||
location.pathname,
|
||||
peerConnection?.connectionState,
|
||||
]);
|
||||
}, [connectWebRTC, connectionFailed, location.pathname, peerConnectionState]);
|
||||
|
||||
// On boot, if the connection state is undefined, we connect to the WebRTC
|
||||
useEffect(() => {
|
||||
|
|
Loading…
Reference in New Issue