Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
TdpClient,
TdpClientEvent,
} from 'shared/libs/tdp';
import { TdpError as RemoteTdpError } from 'shared/libs/tdp/client';

import { DesktopSession, DesktopSessionProps } from './DesktopSession';

Expand Down Expand Up @@ -86,7 +87,15 @@ export const FetchError = () => (
export const TdpError = () => {
const client = fakeClient();
client.connect = async () => {
client.emit(TdpClientEvent.ERROR, new Error('some tdp error'));
client.emit(
TdpClientEvent.ERROR,
new RemoteTdpError(
'RDP client exited with an error: Connection Timed Out.\n\n' +
'Teleport could not connect to the host within the timeout period. This may be due to a firewall blocking the connection, an overloaded system, or network congestion.\n\n' +
'To resolve this issue, ensure that the Teleport agent can reach the Windows host.\n\n' +
'You can use the command "nc -vz HOST 3389" to help diagnose connectivity problems.'
)
);
};

return <DesktopSession {...props} client={client} />;
Expand All @@ -96,10 +105,10 @@ export const Connected = () => {
return <DesktopSession {...props} />;
};

export const Disconnected = () => {
export const DisconnectedWithNoMessage = () => {
const client = fakeClient();
client.connect = async () => {
client.emit(TdpClientEvent.TRANSPORT_CLOSE, 'session disconnected');
client.emit(TdpClientEvent.TRANSPORT_CLOSE);
};

return <DesktopSession {...props} client={client} />;
Expand Down
31 changes: 21 additions & 10 deletions web/packages/shared/components/DesktopSession/DesktopSession.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
TdpClient,
useListener,
} from 'shared/libs/tdp';
import { TdpError } from 'shared/libs/tdp/client';

import { KeyboardHandler } from './KeyboardHandler';
import TopBar from './TopBar';
Expand Down Expand Up @@ -130,7 +131,8 @@ export function DesktopSession({
setClipboardSharingState(defaultClipboardSharingState);
setTdpConnectionStatus({
status: 'disconnected',
message: error.message || error.toString(),
fromTdpError: error instanceof TdpError,
message: error?.message || error?.toString(),
});
initialTdpConnectionSucceeded.current = false;
},
Expand Down Expand Up @@ -166,8 +168,11 @@ export function DesktopSession({
useListener(
client.onTransportClose,
useCallback(
statusText => {
setTdpConnectionStatus({ status: 'disconnected', message: statusText });
error => {
setTdpConnectionStatus({
status: 'disconnected',
message: error?.message || error?.toString(),
});
initialTdpConnectionSucceeded.current = false;
},
[setTdpConnectionStatus]
Expand Down Expand Up @@ -350,7 +355,7 @@ export function DesktopSession({
/>
)}
{screenState.state === 'custom' && screenState.component}
{screenState.state === 'error' && (
{screenState.state === 'disconnected' && (
<AlertDialog message={screenState.message} onRetry={onRetry} />
)}
{screenState.state === 'processing' && <Processing />}
Expand Down Expand Up @@ -447,7 +452,7 @@ function getScreenState(

if (aclAttempt.status === 'error') {
return {
state: 'error',
state: 'disconnected',
message: {
title: 'Could not fetch session details',
details: aclAttempt.statusText,
Expand All @@ -456,7 +461,7 @@ function getScreenState(
}
if (anotherDesktopActiveAttempt.status === 'error') {
return {
state: 'error',
state: 'disconnected',
message: {
title: 'Could not fetch session details',
details: anotherDesktopActiveAttempt.statusText,
Expand All @@ -465,8 +470,8 @@ function getScreenState(
}
if (tdpConnectionStatus.status === 'disconnected') {
return {
state: 'error',
message: { title: tdpConnectionStatus.message },
state: 'disconnected',
message: { title: tdpConnectionStatus.message || 'Session disconnected' },
};
}

Expand Down Expand Up @@ -499,6 +504,7 @@ type TdpConnectionStatus =
*/
| {
status: 'disconnected';
fromTdpError?: boolean;
message: string;
};

Expand All @@ -508,6 +514,11 @@ type ScreenState =
| { state: 'processing' }
| { state: 'canvas-visible' }
| {
state: 'error';
message: { title: string; details?: string };
state: 'disconnected';
message: DisconnectedMessage;
};

interface DisconnectedMessage {
title: string;
details?: string;
}
20 changes: 14 additions & 6 deletions web/packages/shared/libs/tdp/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export class TdpClient extends EventEmitter {
this.transportAbortController.signal
);
} catch (error) {
this.emit(TdpClientEvent.ERROR, error.message);
this.emit(TdpClientEvent.ERROR, error);
return;
}

Expand Down Expand Up @@ -183,11 +183,11 @@ export class TdpClient extends EventEmitter {

// 'Processing' errors are the most important.
if (processingError) {
this.emit(TdpClientEvent.ERROR, processingError.message);
this.emit(TdpClientEvent.ERROR, processingError);
} else if (connectionError) {
this.emit(TdpClientEvent.TRANSPORT_CLOSE, connectionError.message);
this.emit(TdpClientEvent.TRANSPORT_CLOSE, connectionError);
} else {
this.emit(TdpClientEvent.TRANSPORT_CLOSE, 'Session disconnected');
this.emit(TdpClientEvent.TRANSPORT_CLOSE);
}

this.logger.info('Transport is closed');
Expand Down Expand Up @@ -235,7 +235,7 @@ export class TdpClient extends EventEmitter {
return () => this.off(TdpClientEvent.TDP_WARNING, listener);
};

onTransportClose = (listener: (message: string) => void) => {
onTransportClose = (listener: (error?: Error) => void) => {
this.on(TdpClientEvent.TRANSPORT_CLOSE, listener);
return () => this.off(TdpClientEvent.TRANSPORT_CLOSE, listener);
};
Expand Down Expand Up @@ -391,7 +391,7 @@ export class TdpClient extends EventEmitter {
handleTdpNotification(buffer: ArrayBuffer) {
const notification = this.codec.decodeNotification(buffer);
if (notification.severity === Severity.Error) {
throw new Error(notification.message);
throw new TdpError(notification.message);
} else if (notification.severity === Severity.Warning) {
this.handleWarning(notification.message, TdpClientEvent.TDP_WARNING);
} else {
Expand Down Expand Up @@ -799,3 +799,11 @@ export function useListener<T extends any[]>(
};
}, [emitter, listener]);
}

/** Represents an alert emitted by the TDP service with "error" severity. */
export class TdpError extends Error {
constructor(message: string) {
super(message);
this.name = 'TdpError';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export async function adaptWebSocketToTdpTransport(
socket: WebSocket,
signal: AbortSignal
): Promise<TdpTransport> {
if (signal.aborted) {
throw new DOMException('Websocket was aborted.', 'AbortError');
}
// WebsocketCloseCode.NORMAL
signal.addEventListener('abort', () => socket.close(1000));
socket.binaryType = 'arraybuffer';
Expand Down
Loading