From 5f83bfb535a63d98b046ab3c8e2c19cf517ae76d Mon Sep 17 00:00:00 2001 From: ostatni5 <26521377+ostatni5@users.noreply.github.com> Date: Tue, 30 May 2023 22:17:08 +0200 Subject: [PATCH 1/2] Add configurable backend URL --- src/config/Config.ts | 7 +++ src/services/AuthService.tsx | 118 +++++++++++++++++++++-------------- 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/src/config/Config.ts b/src/config/Config.ts index e633e1a33..1d93f0c41 100644 --- a/src/config/Config.ts +++ b/src/config/Config.ts @@ -1,3 +1,10 @@ +declare global { + interface Window { + BACKEND_URL?: string; + } +} + export const BACKEND_URL = process.env.REACT_APP_BACKEND_URL ?? 'http://localhost:5000'; +window.BACKEND_URL = BACKEND_URL; export const DEMO_MODE = process.env.REACT_APP_TARGET === 'demo'; export const ALT_AUTH = process.env.REACT_APP_ALT_AUTH === 'plg'; diff --git a/src/services/AuthService.tsx b/src/services/AuthService.tsx index 9dbbba473..9d5536356 100644 --- a/src/services/AuthService.tsx +++ b/src/services/AuthService.tsx @@ -60,57 +60,82 @@ const Auth = ({ children }: AuthProps) => { const [isServerReachable, setIsServerReachable] = useState(null); const { enqueueSnackbar } = useSnackbar(); + const [backendUrl, setBackendUrl] = useState(BACKEND_URL); + useEffect(() => { setReachInterval(isServerReachable ? 180000 : 30000); }, [isServerReachable]); - const kyRef = useRef( - ky.create({ - credentials: 'include', - prefixUrl: BACKEND_URL, - //overwrite default json parser to convert snake_case to camelCase - parseJson: (text: string) => snakeToCamelCase(JSON.parse(text), true), - hooks: { - afterResponse: [ - async (_request, _options, response) => { - switch (response?.status) { - case 401: - enqueueSnackbar('Please log in.', { variant: 'warning' }); - setUser(null); - break; - case 403: - enqueueSnackbar('Please log in again.', { variant: 'warning' }); - setUser(null); - break; - } - if (response?.status > 300) { - const message = await response.json().then(r => r.message); - if (message !== 'No token provided') - enqueueSnackbar(await response.json().then(r => r.message), { - variant: 'error' - }); - console.error( - response.status, - await response.json().then(r => r.message) - ); + const kyRef = useMemo( + () => + ky.create({ + credentials: 'include', + prefixUrl: backendUrl, + //overwrite default json parser to convert snake_case to camelCase + parseJson: (text: string) => snakeToCamelCase(JSON.parse(text), true), + hooks: { + afterResponse: [ + async (_request, _options, response) => { + switch (response?.status) { + case 401: + enqueueSnackbar('Please log in.', { variant: 'warning' }); + setUser(null); + break; + case 403: + enqueueSnackbar('Please log in again.', { variant: 'warning' }); + setUser(null); + break; + } + if (response?.status > 300) { + const message = await response.json().then(r => r.message); + if (message !== 'No token provided') + enqueueSnackbar(await response.json().then(r => r.message), { + variant: 'error' + }); + console.error( + response.status, + await response.json().then(r => r.message) + ); + } } - } - ] - } - }) + ] + } + }), + [backendUrl, enqueueSnackbar] ); - const kyIntervalRef = useRef( - kyRef.current.extend({ - retry: 0 - }) + + const kyIntervalRef = useMemo( + () => + kyRef.extend({ + retry: 0 + }), + [kyRef] + ); + + const setBackendUrlCallback = useCallback( + (url: string) => { + setBackendUrl(url); + }, + [setBackendUrl] ); + useEffect(() => { + Object.defineProperty(window, 'BACKEND_URL', { + set: function (url: string) { + setBackendUrlCallback(url); + }, + get: function () { + return backendUrl; + } + }); + }, [backendUrl, setBackendUrlCallback]); + useEffect(() => { if (DEMO_MODE) enqueueSnackbar('Demo mode enabled.', { variant: 'info' }); }, [enqueueSnackbar]); const reachServer = useCallback(() => { - return kyIntervalRef.current + return kyIntervalRef .get(``) .json() .then(r => !!r.message) @@ -124,7 +149,7 @@ const Auth = ({ children }: AuthProps) => { }) ) .catch(() => setIsServerReachable(false)); - }, [enqueueSnackbar]); + }, [enqueueSnackbar, kyIntervalRef]); useIntervalAsync(reachServer, reachInterval); useEffect(() => { @@ -133,12 +158,12 @@ const Auth = ({ children }: AuthProps) => { const refresh = useCallback(() => { if (DEMO_MODE || !isServerReachable) return Promise.resolve(setRefreshInterval(undefined)); - return kyIntervalRef.current + return kyIntervalRef .get(`auth/refresh`) .json() .then(({ accessExp }) => setRefreshInterval(getRefreshDelay(accessExp))) .catch((_: HTTPError) => {}); - }, [isServerReachable]); + }, [isServerReachable, kyIntervalRef]); useEffect(() => { if (user !== null && refreshInterval === undefined && isServerReachable) @@ -148,7 +173,7 @@ const Auth = ({ children }: AuthProps) => { const login = useCallback( (...[username, password]: RequestAuthLogin) => { - kyRef.current + kyRef .post(`auth/login`, { json: { username, password } }) @@ -160,17 +185,18 @@ const Auth = ({ children }: AuthProps) => { }) .catch((_: HTTPError) => {}); }, - [enqueueSnackbar] + [enqueueSnackbar, kyRef] ); const logout = useCallback(() => { - kyRef.current + kyRef .delete(`auth/logout`) .json() .then(_response => setUser(null)) .catch((_: HTTPError) => {}); - }, []); - const authKy = useMemo(() => kyRef.current, []); + }, [kyRef]); + + const authKy = useMemo(() => kyRef, [kyRef]); const isAuthorized = useMemo(() => user !== null || DEMO_MODE, [user]); useEffect(() => { From 801d2f019a63001cb1ac6e4bec4a922823cd6d35 Mon Sep 17 00:00:00 2001 From: ostatni5 <26521377+ostatni5@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:05:42 +0200 Subject: [PATCH 2/2] Add env variable --- src/config/Config.ts | 9 ++------- src/services/AuthService.tsx | 35 +++++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/config/Config.ts b/src/config/Config.ts index 1d93f0c41..8409221f6 100644 --- a/src/config/Config.ts +++ b/src/config/Config.ts @@ -1,10 +1,5 @@ -declare global { - interface Window { - BACKEND_URL?: string; - } -} - export const BACKEND_URL = process.env.REACT_APP_BACKEND_URL ?? 'http://localhost:5000'; -window.BACKEND_URL = BACKEND_URL; export const DEMO_MODE = process.env.REACT_APP_TARGET === 'demo'; export const ALT_AUTH = process.env.REACT_APP_ALT_AUTH === 'plg'; +type ConfigDeployment = 'dev' | 'prod' | undefined; +export const DEPLOYMENT: ConfigDeployment = process.env.REACT_APP_DEPLOYMENT as ConfigDeployment; diff --git a/src/services/AuthService.tsx b/src/services/AuthService.tsx index 9d5536356..f0f7daa96 100644 --- a/src/services/AuthService.tsx +++ b/src/services/AuthService.tsx @@ -1,8 +1,8 @@ -import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; import { createGenericContext } from './GenericContext'; import ky, { HTTPError } from 'ky'; import { KyInstance } from 'ky/distribution/types/ky'; -import { BACKEND_URL, DEMO_MODE } from '../config/Config'; +import { BACKEND_URL, DEMO_MODE, DEPLOYMENT } from '../config/Config'; import { snakeToCamelCase } from '../types/TypeTransformUtil'; import { RequestAuthLogin, RequestAuthLogout, RequestAuthRefresh } from '../types/RequestTypes'; import useIntervalAsync from '../util/hooks/useIntervalAsync'; @@ -14,6 +14,12 @@ import { YaptideResponse } from '../types/ResponseTypes'; +declare global { + interface Window { + BACKEND_URL?: string; + } +} + export interface AuthProps { children: ReactNode; } @@ -119,16 +125,21 @@ const Auth = ({ children }: AuthProps) => { [setBackendUrl] ); - useEffect(() => { - Object.defineProperty(window, 'BACKEND_URL', { - set: function (url: string) { - setBackendUrlCallback(url); - }, - get: function () { - return backendUrl; - } - }); - }, [backendUrl, setBackendUrlCallback]); + // Enable backend url change in dev mode + if (DEPLOYMENT === 'dev') { + // eslint-disable-next-line react-hooks/rules-of-hooks + useEffect(() => { + Object.defineProperty(window, 'BACKEND_URL', { + set: function (url: string) { + setBackendUrlCallback(url); + }, + get: function () { + return backendUrl; + }, + configurable: true + }); + }, [backendUrl, setBackendUrlCallback]); + } useEffect(() => { if (DEMO_MODE) enqueueSnackbar('Demo mode enabled.', { variant: 'info' });