Retry websocket connect if error returned is 502
* Retry websocket connect if error returned is 502 * Introduce connect button on 'Disconnected' left-pane dialog * NetworkStatus: If user clicks connect, show connecting for 5s
This commit is contained in:
parent
c44176f7f3
commit
6bd5587d50
5 changed files with 89 additions and 15 deletions
|
@ -571,6 +571,10 @@
|
||||||
"message": "Connecting",
|
"message": "Connecting",
|
||||||
"description": "Displayed when the desktop client is currently connecting to the server."
|
"description": "Displayed when the desktop client is currently connecting to the server."
|
||||||
},
|
},
|
||||||
|
"connect": {
|
||||||
|
"message": "Connect",
|
||||||
|
"description": "Shown to allow the user to manually attempt a reconnect."
|
||||||
|
},
|
||||||
"connectingHangOn": {
|
"connectingHangOn": {
|
||||||
"message": "Shouldn't be long...",
|
"message": "Shouldn't be long...",
|
||||||
"description": "Subtext description for when the client is connecting to the server."
|
"description": "Subtext description for when the client is connecting to the server."
|
||||||
|
|
|
@ -1446,6 +1446,7 @@
|
||||||
new textsecure.SyncRequest(textsecure.messaging, messageReceiver);
|
new textsecure.SyncRequest(textsecure.messaging, messageReceiver);
|
||||||
|
|
||||||
let disconnectTimer = null;
|
let disconnectTimer = null;
|
||||||
|
let reconnectTimer = null;
|
||||||
function onOffline() {
|
function onOffline() {
|
||||||
window.log.info('offline');
|
window.log.info('offline');
|
||||||
|
|
||||||
|
@ -1499,7 +1500,12 @@
|
||||||
|
|
||||||
let connectCount = 0;
|
let connectCount = 0;
|
||||||
async function connect(firstRun) {
|
async function connect(firstRun) {
|
||||||
window.log.info('connect', firstRun);
|
window.log.info('connect', { firstRun, connectCount });
|
||||||
|
|
||||||
|
if (reconnectTimer) {
|
||||||
|
clearTimeout(reconnectTimer);
|
||||||
|
reconnectTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Bootstrap our online/offline detection, only the first time we connect
|
// Bootstrap our online/offline detection, only the first time we connect
|
||||||
if (connectCount === 0 && navigator.onLine) {
|
if (connectCount === 0 && navigator.onLine) {
|
||||||
|
@ -1799,6 +1805,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Whisper.events.on('manualConnect', manualConnect);
|
||||||
|
function manualConnect() {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
function onConfiguration(ev) {
|
function onConfiguration(ev) {
|
||||||
ev.confirm();
|
ev.confirm();
|
||||||
|
|
||||||
|
@ -2435,11 +2446,15 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error && error.name === 'HTTPError' && error.code === -1) {
|
if (
|
||||||
|
error &&
|
||||||
|
error.name === 'HTTPError' &&
|
||||||
|
(error.code === -1 || error.code === 502)
|
||||||
|
) {
|
||||||
// Failed to connect to server
|
// Failed to connect to server
|
||||||
if (navigator.onLine) {
|
if (navigator.onLine) {
|
||||||
window.log.info('retrying in 1 minute');
|
window.log.info('retrying in 1 minute');
|
||||||
setTimeout(connect, 60000);
|
reconnectTimer = setTimeout(connect, 60000);
|
||||||
|
|
||||||
Whisper.events.trigger('reconnectTimer');
|
Whisper.events.trigger('reconnectTimer');
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ const defaultProps = {
|
||||||
isRegistrationDone: true,
|
isRegistrationDone: true,
|
||||||
socketStatus: 0,
|
socketStatus: 0,
|
||||||
relinkDevice: action('relink-device'),
|
relinkDevice: action('relink-device'),
|
||||||
|
manualReconnect: action('manual-reconnect'),
|
||||||
withinConnectingGracePeriod: false,
|
withinConnectingGracePeriod: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,12 +42,6 @@ const permutations = [
|
||||||
socketStatus: 3,
|
socketStatus: 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'Offline',
|
|
||||||
props: {
|
|
||||||
isOnline: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Unlinked (online)',
|
title: 'Unlinked (online)',
|
||||||
props: {
|
props: {
|
||||||
|
@ -60,6 +55,12 @@ const permutations = [
|
||||||
isRegistrationDone: false,
|
isRegistrationDone: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Offline',
|
||||||
|
props: {
|
||||||
|
isOnline: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
storiesOf('Components/NetworkStatus', module)
|
storiesOf('Components/NetworkStatus', module)
|
||||||
|
|
|
@ -3,11 +3,14 @@ import React from 'react';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import { NetworkStateType } from '../state/ducks/network';
|
import { NetworkStateType } from '../state/ducks/network';
|
||||||
|
|
||||||
|
const FIVE_SECONDS = 5 * 1000;
|
||||||
|
|
||||||
export interface PropsType extends NetworkStateType {
|
export interface PropsType extends NetworkStateType {
|
||||||
hasNetworkDialog: boolean;
|
hasNetworkDialog: boolean;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
isRegistrationDone: boolean;
|
isRegistrationDone: boolean;
|
||||||
relinkDevice: () => void;
|
relinkDevice: () => void;
|
||||||
|
manualReconnect: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type RenderDialogTypes = {
|
type RenderDialogTypes = {
|
||||||
|
@ -39,17 +42,41 @@ export const NetworkStatus = ({
|
||||||
isRegistrationDone,
|
isRegistrationDone,
|
||||||
socketStatus,
|
socketStatus,
|
||||||
relinkDevice,
|
relinkDevice,
|
||||||
|
manualReconnect,
|
||||||
}: PropsType): JSX.Element | null => {
|
}: PropsType): JSX.Element | null => {
|
||||||
if (!hasNetworkDialog) {
|
if (!hasNetworkDialog) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOnline) {
|
const [isConnecting, setIsConnecting] = React.useState<boolean>(false);
|
||||||
return renderDialog({
|
React.useEffect(() => {
|
||||||
subtext: i18n('checkNetworkConnection'),
|
let timeout: NodeJS.Timeout;
|
||||||
title: i18n('offline'),
|
|
||||||
});
|
if (isConnecting) {
|
||||||
} else if (!isRegistrationDone) {
|
timeout = setTimeout(() => {
|
||||||
|
setIsConnecting(false);
|
||||||
|
}, FIVE_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [isConnecting, setIsConnecting]);
|
||||||
|
|
||||||
|
const reconnect = () => {
|
||||||
|
setIsConnecting(true);
|
||||||
|
manualReconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
const manualReconnectButton = (): JSX.Element => (
|
||||||
|
<div className="module-left-pane-dialog__actions">
|
||||||
|
<button onClick={reconnect}>{i18n('connect')}</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isRegistrationDone) {
|
||||||
return renderDialog({
|
return renderDialog({
|
||||||
renderActionableButton: (): JSX.Element => (
|
renderActionableButton: (): JSX.Element => (
|
||||||
<div className="module-left-pane-dialog__actions">
|
<div className="module-left-pane-dialog__actions">
|
||||||
|
@ -59,10 +86,22 @@ export const NetworkStatus = ({
|
||||||
subtext: i18n('unlinkedWarning'),
|
subtext: i18n('unlinkedWarning'),
|
||||||
title: i18n('unlinked'),
|
title: i18n('unlinked'),
|
||||||
});
|
});
|
||||||
|
} else if (isConnecting) {
|
||||||
|
return renderDialog({
|
||||||
|
subtext: i18n('connectingHangOn'),
|
||||||
|
title: i18n('connecting'),
|
||||||
|
});
|
||||||
|
} else if (!isOnline) {
|
||||||
|
return renderDialog({
|
||||||
|
renderActionableButton: manualReconnectButton,
|
||||||
|
subtext: i18n('checkNetworkConnection'),
|
||||||
|
title: i18n('offline'),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let subtext = '';
|
let subtext = '';
|
||||||
let title = '';
|
let title = '';
|
||||||
|
let renderActionableButton;
|
||||||
|
|
||||||
switch (socketStatus) {
|
switch (socketStatus) {
|
||||||
case WebSocket.CONNECTING:
|
case WebSocket.CONNECTING:
|
||||||
|
@ -72,11 +111,13 @@ export const NetworkStatus = ({
|
||||||
case WebSocket.CLOSED:
|
case WebSocket.CLOSED:
|
||||||
case WebSocket.CLOSING:
|
case WebSocket.CLOSING:
|
||||||
default:
|
default:
|
||||||
|
renderActionableButton = manualReconnectButton;
|
||||||
title = i18n('disconnected');
|
title = i18n('disconnected');
|
||||||
subtext = i18n('checkNetworkConnection');
|
subtext = i18n('checkNetworkConnection');
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderDialog({
|
return renderDialog({
|
||||||
|
renderActionableButton,
|
||||||
subtext,
|
subtext,
|
||||||
title,
|
title,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { trigger } from '../../shims/events';
|
||||||
|
|
||||||
|
import { NoopActionType } from './noop';
|
||||||
import { LocalizerType } from '../../types/Util';
|
import { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
@ -34,6 +37,7 @@ export type UserActionType = UserChangedActionType;
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
userChanged,
|
userChanged,
|
||||||
|
manualReconnect,
|
||||||
};
|
};
|
||||||
|
|
||||||
function userChanged(attributes: {
|
function userChanged(attributes: {
|
||||||
|
@ -49,6 +53,15 @@ function userChanged(attributes: {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function manualReconnect(): NoopActionType {
|
||||||
|
trigger('manualConnect');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'NOOP',
|
||||||
|
payload: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Reducer
|
// Reducer
|
||||||
|
|
||||||
function getEmptyState(): UserStateType {
|
function getEmptyState(): UserStateType {
|
||||||
|
|
Loading…
Reference in a new issue