Adding a reconnect feature in case first Pusher request fails

Now, if the first pusher request fails, a waiting message will be displayed and the application will reconnect when the pusher comes back alive or the network connection is established again.
This commit is contained in:
David Négrier 2021-11-29 18:15:21 +01:00
parent 9eb4206fe0
commit fcf0888864
17 changed files with 981 additions and 32 deletions

View file

@ -54,6 +54,7 @@
"queue-typescript": "^1.0.1",
"quill": "1.3.6",
"quill-delta-to-html": "^0.12.0",
"retry-axios": "^2.6.0",
"rxjs": "^6.6.3",
"simple-peer": "^9.11.0",
"socket.io-client": "^2.3.0",

View file

@ -1,8 +1,8 @@
<script lang="ts">
import {errorStore} from "../../Stores/ErrorStore";
import {errorStore, hasClosableMessagesInErrorStore} from "../../Stores/ErrorStore";
function close(): boolean {
errorStore.clearMessages();
errorStore.clearClosableMessages();
return false;
}
@ -12,12 +12,14 @@ function close(): boolean {
<p class="nes-text is-error title">Error</p>
<div class="body">
{#each $errorStore as error}
<p>{error}</p>
<p>{error.message}</p>
{/each}
</div>
{#if $hasClosableMessagesInErrorStore}
<div class="button-bar">
<button class="nes-btn is-error" on:click={close}>Close</button>
</div>
{/if}
</div>
<style lang="scss">

View file

@ -0,0 +1,37 @@
import axios from "axios";
import * as rax from "retry-axios";
import {errorStore} from "../Stores/ErrorStore";
/**
* This instance of Axios will retry in case of an issue and display an error message as a HTML overlay.
*/
export const axiosWithRetry = axios.create();
axiosWithRetry.defaults.raxConfig = {
instance: axiosWithRetry,
retry: Infinity,
noResponseRetries: Infinity,
maxRetryAfter: 60_000,
// You can detect when a retry is happening, and figure out how many
// retry attempts have been made
onRetryAttempt: err => {
const cfg = rax.getConfig(err);
console.log(err)
console.log(cfg)
console.log(`Retry attempt #${cfg?.currentRetryAttempt}`);
errorStore.addErrorMessage('Unable to connect to WorkAdventure. Are you connected to internet?', {
closable: false,
id: "axios_retry"
});
},
};
axiosWithRetry.interceptors.response.use(res => {
if (res.status < 400) {
errorStore.clearMessageById("axios_retry");
}
return res;
});
const interceptorId = rax.attach(axiosWithRetry);

View file

@ -1,7 +1,10 @@
import * as rax from 'retry-axios';
import Axios from "axios";
import { CONTACT_URL, PUSHER_URL, DISABLE_ANONYMOUS, OPID_LOGIN_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
import type { CharacterTexture } from "./LocalUser";
import { localUserStore } from "./LocalUserStore";
import axios from "axios";
import {axiosWithRetry} from "./AxiosUtils";
export class MapDetail {
constructor(public readonly mapUrl: string, public readonly textures: CharacterTexture[] | undefined) {}
@ -90,7 +93,7 @@ export class Room {
private async getMapDetail(): Promise<MapDetail | RoomRedirect> {
try {
const result = await Axios.get(`${PUSHER_URL}/map`, {
const result = await axiosWithRetry.get(`${PUSHER_URL}/map`, {
params: {
playUri: this.roomUrl.toString(),
authToken: localUserStore.getAuthToken(),

View file

@ -1,15 +1,24 @@
import { writable } from "svelte/store";
import {derived, writable} from "svelte/store";
interface ErrorMessage {
id: string|undefined;
closable: boolean; // Whether it can be closed by a user action or not
message: string | number | boolean | undefined;
}
/**
* A store that contains a list of error messages to be displayed.
*/
function createErrorStore() {
const { subscribe, set, update } = writable<string[]>([]);
const { subscribe, set, update } = writable<ErrorMessage[]>([]);
return {
subscribe,
addErrorMessage: (e: string | Error): void => {
update((messages: string[]) => {
addErrorMessage: (e: string | Error, options?: {
closable?: boolean,
id?: string
}): void => {
update((messages: ErrorMessage[]) => {
let message: string;
if (e instanceof Error) {
message = e.message;
@ -17,17 +26,36 @@ function createErrorStore() {
message = e;
}
if (!messages.includes(message)) {
messages.push(message);
if (!messages.find(errorMessage => errorMessage.message === message)) {
messages.push({
message,
closable: options?.closable ?? true,
id: options?.id
});
}
return messages;
});
},
clearMessages: (): void => {
set([]);
clearMessageById: (id: string): void => {
update((messages: ErrorMessage[]) => {
messages = messages.filter(message => message.id !== id);
return messages;
});
},
clearClosableMessages: (): void => {
update((messages: ErrorMessage[]) => {
messages = messages.filter(message => message.closable);
return messages;
});
},
};
}
export const errorStore = createErrorStore();
export const hasClosableMessagesInErrorStore = derived(errorStore, ($errorStore) => {
const closableMessage = $errorStore.find(errorMessage => errorMessage.closable);
return !!closableMessage;
});

View file

@ -4862,6 +4862,11 @@ ret@~0.1.10:
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
retry-axios@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/retry-axios/-/retry-axios-2.6.0.tgz#d4dc5c8a8e73982e26a705e46a33df99a28723e0"
integrity sha512-pOLi+Gdll3JekwuFjXO3fTq+L9lzMQGcSq7M5gIjExcl3Gu1hd4XXuf5o3+LuSBsaULQH7DiNbsqPd1chVpQGQ==
retry@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"