Refactor events listeners and fix a race condition when closing RDP stream#52714
Refactor events listeners and fix a race condition when closing RDP stream#52714
Conversation
…bsocket close messages
It's the responsibility of callers who created the listeners to clean them up. Otherwise, `onWsClose` callback won't be called when we call `shutdown()`.
d9b0a53 to
fcd3f0f
Compare
| // It's safe to call this multiple times, calls subsequent to the first call | ||
| // will simply do nothing. | ||
| shutdown(closeCode = WebsocketCloseCode.NORMAL) { | ||
| this.removeAllListeners(); |
There was a problem hiding this comment.
I think this shouldn't have been here in the first place.
This class doesn't create event listeners for its own purposes—its callers do. Because of that, it shouldn't be responsible for clearing them; that should be left to the callers. This became a problem for onWsClose callback I added. It was removed before we closed the socket so the listeners were not notified about it.
Previously, it worked purely by accident. useTdpClientCanvas.clientOnWsClient wasn't wrapped in useCallback, so when the user clicked the Disconnect button in the UI, a re-render occurred, causing the callback to be re-created and reattached as a listener.
| ...prevState, | ||
| { | ||
| content: info, | ||
| severity: 'info', |
There was a problem hiding this comment.
TDP_INFO is no longer used to signal disconnection, so now I show info warnings when we receive it.
But I'm not sure if it makes any sense, we don't have any code that sends info level alerts?
There was a problem hiding this comment.
The original intent was that the TDP "notification" message can be used for both fatal errors or non-fatal messages.
SeverityErrormeans there was a fatal error and the proxy is about to close the connection.SeverityInfoandSeverityWarningare for non-fatal messages that show up in the top right corner.
In reality, Isaiah used SeverityInfo to show connection close "errors" in a state that's not error, which is why there's nothing else that's using INFO level.
Maybe the correct solution would have been to treat these as two separate concepts:
- a severity, which indicates to the UI how to render the message
- whether or not this message is preceding a disconnect
That said, what we have here is good enough for me.
|
Changes look good to me. I'll try to test it a bit later before approving. |
|
I'm pretty sure this fixes #38373. |
|
I think so, I will close the linked issue. |
…tream (#52714) * Add `useListener` hook that makes subscribing to events easier * Expose simpler APIs for subscribing to events * Replace verbose `useEffect` listeners with `useListener` calls * Fix a race condition that caused TDP errors to be overwritten with websocket close messages * Move `clientOnTdpWarning` to `DesktopCanvas.tsx` * Move `clientOnTdpInfo` to `DesktopCanvas.tsx` * Move `clientOnTdpError` to `DesktopCanvas.tsx` * Move functions that change WS connection status to `DesktopCanvas.tsx` * Change order of functions * Do not remove listeners when shutting down the WebSocket It's the responsibility of callers who created the listeners to clean them up. Otherwise, `onWsClose` callback won't be called when we call `shutdown()`. * Fix types (cherry picked from commit 0a7d941)
…tream (#52714) * Add `useListener` hook that makes subscribing to events easier * Expose simpler APIs for subscribing to events * Replace verbose `useEffect` listeners with `useListener` calls * Fix a race condition that caused TDP errors to be overwritten with websocket close messages * Move `clientOnTdpWarning` to `DesktopCanvas.tsx` * Move `clientOnTdpInfo` to `DesktopCanvas.tsx` * Move `clientOnTdpError` to `DesktopCanvas.tsx` * Move functions that change WS connection status to `DesktopCanvas.tsx` * Change order of functions * Do not remove listeners when shutting down the WebSocket It's the responsibility of callers who created the listeners to clean them up. Otherwise, `onWsClose` callback won't be called when we call `shutdown()`. * Fix types (cherry picked from commit 0a7d941)
…tream (#52714) * Add `useListener` hook that makes subscribing to events easier * Expose simpler APIs for subscribing to events * Replace verbose `useEffect` listeners with `useListener` calls * Fix a race condition that caused TDP errors to be overwritten with websocket close messages * Move `clientOnTdpWarning` to `DesktopCanvas.tsx` * Move `clientOnTdpInfo` to `DesktopCanvas.tsx` * Move `clientOnTdpError` to `DesktopCanvas.tsx` * Move functions that change WS connection status to `DesktopCanvas.tsx` * Change order of functions * Do not remove listeners when shutting down the WebSocket It's the responsibility of callers who created the listeners to clean them up. Otherwise, `onWsClose` callback won't be called when we call `shutdown()`. * Fix types (cherry picked from commit 0a7d941)
…P stream (#52869) * Refactor client canvas (#52431) * Remove non-canvas related listeners from `TdpClientCanvas` * Simplify event handlers setup by using React handlers * Listen to canvas resize events instead of window ones * Expose imperative API to set pointer * Expose imperative API to render frames * Expose imperative API to change canvas resolution Also, we no longer need to set the canvas size manually; it is now handled by `objectFit: scale-down`. * Remove duplicate player shutdown * Expose imperative API to clear canvas * Remove unnecessary display size syncing We get the canvas resolution from the server, there doesn't seem to be a need to calculate it from the browser window size. * Fix focusing canvas It didn't work because it happened too early, before we even showed the MFA dialog which stole focus. This is a temporary fix, I will do it more elegantly in the future. * Minor code changes Remove component memoization, it didn't work anyway and doesn't seem needed. We don't have anything particularly expensive to render here from React's perspective. * Add a TODO for improving rendering functions (cherry picked from commit 671475f) * Refactor events listeners and fix a race condition when closing RDP stream (#52714) * Add `useListener` hook that makes subscribing to events easier * Expose simpler APIs for subscribing to events * Replace verbose `useEffect` listeners with `useListener` calls * Fix a race condition that caused TDP errors to be overwritten with websocket close messages * Move `clientOnTdpWarning` to `DesktopCanvas.tsx` * Move `clientOnTdpInfo` to `DesktopCanvas.tsx` * Move `clientOnTdpError` to `DesktopCanvas.tsx` * Move functions that change WS connection status to `DesktopCanvas.tsx` * Change order of functions * Do not remove listeners when shutting down the WebSocket It's the responsibility of callers who created the listeners to clean them up. Otherwise, `onWsClose` callback won't be called when we call `shutdown()`. * Fix types (cherry picked from commit 0a7d941) * Rename warnings to alerts * Remove desktop session snapshot tests
…P stream (#52866) * Refactor client canvas (#52431) * Remove non-canvas related listeners from `TdpClientCanvas` * Simplify event handlers setup by using React handlers * Listen to canvas resize events instead of window ones * Expose imperative API to set pointer * Expose imperative API to render frames * Expose imperative API to change canvas resolution Also, we no longer need to set the canvas size manually; it is now handled by `objectFit: scale-down`. * Remove duplicate player shutdown * Expose imperative API to clear canvas * Remove unnecessary display size syncing We get the canvas resolution from the server, there doesn't seem to be a need to calculate it from the browser window size. * Fix focusing canvas It didn't work because it happened too early, before we even showed the MFA dialog which stole focus. This is a temporary fix, I will do it more elegantly in the future. * Minor code changes Remove component memoization, it didn't work anyway and doesn't seem needed. We don't have anything particularly expensive to render here from React's perspective. * Add a TODO for improving rendering functions (cherry picked from commit 671475f) * Refactor events listeners and fix a race condition when closing RDP stream (#52714) * Add `useListener` hook that makes subscribing to events easier * Expose simpler APIs for subscribing to events * Replace verbose `useEffect` listeners with `useListener` calls * Fix a race condition that caused TDP errors to be overwritten with websocket close messages * Move `clientOnTdpWarning` to `DesktopCanvas.tsx` * Move `clientOnTdpInfo` to `DesktopCanvas.tsx` * Move `clientOnTdpError` to `DesktopCanvas.tsx` * Move functions that change WS connection status to `DesktopCanvas.tsx` * Change order of functions * Do not remove listeners when shutting down the WebSocket It's the responsibility of callers who created the listeners to clean them up. Otherwise, `onWsClose` callback won't be called when we call `shutdown()`. * Fix types (cherry picked from commit 0a7d941)
…P stream (gravitational#52868) * Refactor client canvas (gravitational#52431) * Remove non-canvas related listeners from `TdpClientCanvas` * Simplify event handlers setup by using React handlers * Listen to canvas resize events instead of window ones * Expose imperative API to set pointer * Expose imperative API to render frames * Expose imperative API to change canvas resolution Also, we no longer need to set the canvas size manually; it is now handled by `objectFit: scale-down`. * Remove duplicate player shutdown * Expose imperative API to clear canvas * Remove unnecessary display size syncing We get the canvas resolution from the server, there doesn't seem to be a need to calculate it from the browser window size. * Fix focusing canvas It didn't work because it happened too early, before we even showed the MFA dialog which stole focus. This is a temporary fix, I will do it more elegantly in the future. * Minor code changes Remove component memoization, it didn't work anyway and doesn't seem needed. We don't have anything particularly expensive to render here from React's perspective. * Add a TODO for improving rendering functions (cherry picked from commit 671475f) * Refactor events listeners and fix a race condition when closing RDP stream (gravitational#52714) * Add `useListener` hook that makes subscribing to events easier * Expose simpler APIs for subscribing to events * Replace verbose `useEffect` listeners with `useListener` calls * Fix a race condition that caused TDP errors to be overwritten with websocket close messages * Move `clientOnTdpWarning` to `DesktopCanvas.tsx` * Move `clientOnTdpInfo` to `DesktopCanvas.tsx` * Move `clientOnTdpError` to `DesktopCanvas.tsx` * Move functions that change WS connection status to `DesktopCanvas.tsx` * Change order of functions * Do not remove listeners when shutting down the WebSocket It's the responsibility of callers who created the listeners to clean them up. Otherwise, `onWsClose` callback won't be called when we call `shutdown()`. * Fix types (cherry picked from commit 0a7d941) * Rename warning to alerts * Prettier * Remove desktop session snapshot tests
Closes #38373
I included a few changes in this PR:
Replaced listening to events from a verbose
useEffectto a shorteruseListener. The only point of this change is to limit repeating the same code, there's no functional changes.Fixed a race condition that caused TDP errors to be overwritten with websocket close messages. This consists of two parts:
socket.onclose()handler is removed before closing the socket when an error occurs first. Thanks to it, we don't overwrite the original error which is more important.I moved some functions from
useTdpClientCanvasto the main component. The hook will be removed in a future PR, it only adds more layers of code which make navigating through it more difficult. There's no functional changes.changelog: Resolved an issue that could cause WebSocket errors to appear after the graceful shutdown of a desktop session
Best to review commit by commit.