diff --git a/app/actions/websocket/index.ts b/app/actions/websocket/index.ts index 5f094dbd37..f2b12615b3 100644 --- a/app/actions/websocket/index.ts +++ b/app/actions/websocket/index.ts @@ -86,7 +86,7 @@ export async function handleFirstConnect(serverUrl: string) { // ESR: 5.37 if (lastDisconnect && config?.EnableReliableWebSockets !== 'true' && alreadyConnected.has(serverUrl)) { - handleReconnect(serverUrl); + await handleReconnect(serverUrl); return; } @@ -100,8 +100,8 @@ export async function handleFirstConnect(serverUrl: string) { } } -export function handleReconnect(serverUrl: string) { - doReconnect(serverUrl); +export async function handleReconnect(serverUrl: string) { + await doReconnect(serverUrl); } export async function handleClose(serverUrl: string, lastDisconnect: number) { diff --git a/app/components/connection_banner/connection_banner.tsx b/app/components/connection_banner/connection_banner.tsx index ea1340a720..44604ff32d 100644 --- a/app/components/connection_banner/connection_banner.tsx +++ b/app/components/connection_banner/connection_banner.tsx @@ -20,7 +20,7 @@ import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; type Props = { - isConnected: boolean; + websocketState: WebsocketConnectedState; } const getStyle = makeStyleSheetFromTheme((theme: Theme) => { @@ -74,7 +74,7 @@ const TIME_TO_OPEN = toMilliseconds({seconds: 3}); const TIME_TO_CLOSE = toMilliseconds({seconds: 1}); const ConnectionBanner = ({ - isConnected, + websocketState, }: Props) => { const intl = useIntl(); const closeTimeout = useRef(); @@ -86,6 +86,8 @@ const ConnectionBanner = ({ const appState = useAppState(); const netInfo = useNetInfo(); + const isConnected = websocketState === 'connected'; + const openCallback = useCallback(() => { setVisible(true); clearTimeoutRef(openTimeout); @@ -97,7 +99,9 @@ const ConnectionBanner = ({ }, []); useEffect(() => { - if (!isConnected) { + if (websocketState === 'connecting') { + openCallback(); + } else if (!isConnected) { openTimeout.current = setTimeout(openCallback, TIME_TO_OPEN); } return () => { @@ -158,6 +162,8 @@ const ConnectionBanner = ({ let text; if (isConnected) { text = intl.formatMessage({id: 'connection_banner.connected', defaultMessage: 'Connection restored'}); + } else if (websocketState === 'connecting') { + text = intl.formatMessage({id: 'connection_banner.connecting', defaultMessage: 'Connecting...'}); } else if (netInfo.isInternetReachable) { text = intl.formatMessage({id: 'connection_banner.not_reachable', defaultMessage: 'The server is not reachable'}); } else { diff --git a/app/components/connection_banner/index.ts b/app/components/connection_banner/index.ts index 0b5547837b..5de70a4285 100644 --- a/app/components/connection_banner/index.ts +++ b/app/components/connection_banner/index.ts @@ -9,7 +9,7 @@ import websocket_manager from '@managers/websocket_manager'; import ConnectionBanner from './connection_banner'; const enhanced = withObservables(['serverUrl'], ({serverUrl}: {serverUrl: string}) => ({ - isConnected: websocket_manager.observeConnected(serverUrl), + websocketState: websocket_manager.observeWebsocketState(serverUrl), })); export default withServerUrl(enhanced(ConnectionBanner)); diff --git a/app/managers/websocket_manager.ts b/app/managers/websocket_manager.ts index 809ad34444..1e44a3da2c 100644 --- a/app/managers/websocket_manager.ts +++ b/app/managers/websocket_manager.ts @@ -21,10 +21,10 @@ import {isMainActivity} from '@utils/helpers'; import {logError} from '@utils/log'; const WAIT_TO_CLOSE = toMilliseconds({seconds: 15}); -const WAIT_UNTIL_NEXT = toMilliseconds({seconds: 20}); +const WAIT_UNTIL_NEXT = toMilliseconds({seconds: 5}); class WebsocketManager { - private connectedSubjects: {[serverUrl: string]: BehaviorSubject} = {}; + private connectedSubjects: {[serverUrl: string]: BehaviorSubject} = {}; private clients: Record = {}; private connectionTimerIDs: Record void>> = {}; @@ -69,7 +69,7 @@ class WebsocketManager { } delete this.clients[serverUrl]; - this.getConnectedSubject(serverUrl).next(false); + this.getConnectedSubject(serverUrl).next('not_connected'); delete this.connectedSubjects[serverUrl]; }; @@ -96,7 +96,7 @@ class WebsocketManager { const client = this.clients[url]; if (client.isConnected()) { client.close(true); - this.getConnectedSubject(url).next(false); + this.getConnectedSubject(url).next('not_connected'); } } }; @@ -107,6 +107,7 @@ class WebsocketManager { if (clientUrl === activeServerUrl) { this.initializeClient(clientUrl); } else { + this.getConnectedSubject(clientUrl).next('connecting'); const bounce = debounce(this.initializeClient.bind(this, clientUrl), WAIT_UNTIL_NEXT); this.connectionTimerIDs[clientUrl] = bounce; bounce(); @@ -118,7 +119,7 @@ class WebsocketManager { return this.clients[serverUrl]?.isConnected(); }; - public observeConnected = (serverUrl: string) => { + public observeWebsocketState = (serverUrl: string) => { return this.getConnectedSubject(serverUrl).asObservable().pipe( distinctUntilChanged(), ); @@ -126,7 +127,7 @@ class WebsocketManager { private getConnectedSubject = (serverUrl: string) => { if (!this.connectedSubjects[serverUrl]) { - this.connectedSubjects[serverUrl] = new BehaviorSubject(this.isConnected(serverUrl)); + this.connectedSubjects[serverUrl] = new BehaviorSubject(this.isConnected(serverUrl) ? 'connected' : 'not_connected'); } return this.connectedSubjects[serverUrl]; @@ -153,13 +154,13 @@ class WebsocketManager { private onFirstConnect = (serverUrl: string) => { this.startPeriodicStatusUpdates(serverUrl); handleFirstConnect(serverUrl); - this.getConnectedSubject(serverUrl).next(true); + this.getConnectedSubject(serverUrl).next('connected'); }; - private onReconnect = (serverUrl: string) => { + private onReconnect = async (serverUrl: string) => { this.startPeriodicStatusUpdates(serverUrl); - handleReconnect(serverUrl); - this.getConnectedSubject(serverUrl).next(true); + await handleReconnect(serverUrl); + this.getConnectedSubject(serverUrl).next('connected'); }; private onWebsocketClose = async (serverUrl: string, connectFailCount: number, lastDisconnect: number) => { @@ -168,7 +169,7 @@ class WebsocketManager { await handleClose(serverUrl, lastDisconnect); this.stopPeriodicStatusUpdates(serverUrl); - this.getConnectedSubject(serverUrl).next(false); + this.getConnectedSubject(serverUrl).next('not_connected'); } }; diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/websocket/index.ts b/app/screens/home/channel_list/servers/servers_list/server_item/websocket/index.ts index de3f977534..b3379ffe77 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/websocket/index.ts +++ b/app/screens/home/channel_list/servers/servers_list/server_item/websocket/index.ts @@ -8,7 +8,7 @@ import WebsocketManager from '@managers/websocket_manager'; import WebSocket from './websocket'; const enhanced = withObservables(['serverUrl'], ({serverUrl}: {serverUrl: string}) => ({ - isConnected: WebsocketManager.observeConnected(serverUrl), + websocketState: WebsocketManager.observeWebsocketState(serverUrl), })); export default enhanced(WebSocket); diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/websocket/websocket.tsx b/app/screens/home/channel_list/servers/servers_list/server_item/websocket/websocket.tsx index 19cac50798..f4c162a23e 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/websocket/websocket.tsx +++ b/app/screens/home/channel_list/servers/servers_list/server_item/websocket/websocket.tsx @@ -11,7 +11,7 @@ import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; type Props = { - isConnected: boolean; + websocketState: WebsocketConnectedState; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -28,10 +28,10 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ }, })); -const WebSocket = ({isConnected}: Props) => { +const WebSocket = ({websocketState}: Props) => { const theme = useTheme(); - if (isConnected) { + if (websocketState === 'connected' || websocketState === 'connecting') { return null; } diff --git a/types/global/websocket.d.ts b/types/global/websocket.d.ts new file mode 100644 index 0000000000..9ee8f65e5e --- /dev/null +++ b/types/global/websocket.d.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +type WebsocketConnectedState = 'not_connected' | 'connected' | 'connecting';