Refactor info endpoint calls

This commit is contained in:
koalasat
2024-10-17 11:14:52 +02:00
parent 560def2966
commit 7bf77a538e
13 changed files with 74 additions and 95 deletions

View File

@ -1,4 +1,4 @@
import React, { useContext, useMemo, useState } from 'react'; import React, { useContext, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Grid, Paper, Collapse, Typography } from '@mui/material'; import { Grid, Paper, Collapse, Typography } from '@mui/material';
@ -13,7 +13,7 @@ import { FederationContext, type UseFederationStoreType } from '../../contexts/F
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext'; import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
const MakerPage = (): JSX.Element => { const MakerPage = (): JSX.Element => {
const { fav, windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext); const { fav, windowSize, navbarHeight, page } = useContext<UseAppStoreType>(AppContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext); const { federation } = useContext<UseFederationStoreType>(FederationContext);
const { garage, maker } = useContext<UseGarageStoreType>(GarageContext); const { garage, maker } = useContext<UseGarageStoreType>(GarageContext);
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -22,6 +22,7 @@ import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
import { genBase62Token } from '../../utils'; import { genBase62Token } from '../../utils';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext'; import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
import { FederationContext, UseFederationStoreType } from '../../contexts/FederationContext';
interface RobotProfileProps { interface RobotProfileProps {
robot: Robot; robot: Robot;
@ -45,6 +46,7 @@ const RobotProfile = ({
}: RobotProfileProps): JSX.Element => { }: RobotProfileProps): JSX.Element => {
const { windowSize, client } = useContext<UseAppStoreType>(AppContext); const { windowSize, client } = useContext<UseAppStoreType>(AppContext);
const { garage, slotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext); const { garage, slotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext);
const { t } = useTranslation(); const { t } = useTranslation();
const theme = useTheme(); const theme = useTheme();
@ -75,10 +77,6 @@ const RobotProfile = ({
const slot = garage.getSlot(); const slot = garage.getSlot();
const robot = slot?.getRobot(); const robot = slot?.getRobot();
const loadingCoordinators = Object.values(slot?.robots ?? {}).filter(
(robot) => robot.loading,
).length;
return ( return (
<Grid container direction='column' alignItems='center' spacing={1} padding={1} paddingTop={2}> <Grid container direction='column' alignItems='center' spacing={1} padding={1} paddingTop={2}>
<Grid <Grid
@ -154,7 +152,7 @@ const RobotProfile = ({
)} )}
</Grid> </Grid>
{loadingCoordinators > 0 && !slot?.activeOrder?.id ? ( {federation.loading && !slot?.activeOrder?.id ? (
<Grid> <Grid>
<b>{t('Looking for orders!')}</b> <b>{t('Looking for orders!')}</b>
<LinearProgress /> <LinearProgress />
@ -208,7 +206,7 @@ const RobotProfile = ({
</Grid> </Grid>
) : null} ) : null}
{!slot?.activeOrder && !slot?.lastOrder && loadingCoordinators === 0 ? ( {!slot?.activeOrder && !slot?.lastOrder && !federation.loading ? (
<Grid item>{t('No existing orders found')}</Grid> <Grid item>{t('No existing orders found')}</Grid>
) : null} ) : null}

View File

@ -1,4 +1,4 @@
import React, { useContext, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { Box, Button, Grid, List, ListItem, Paper, TextField, Typography } from '@mui/material'; import { Box, Button, Grid, List, ListItem, Paper, TextField, Typography } from '@mui/material';
import SettingsForm from '../../components/SettingsForm'; import SettingsForm from '../../components/SettingsForm';
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
@ -8,7 +8,7 @@ import { FederationContext, type UseFederationStoreType } from '../../contexts/F
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext'; import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
const SettingsPage = (): JSX.Element => { const SettingsPage = (): JSX.Element => {
const { windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext); const { windowSize, navbarHeight, page } = useContext<UseAppStoreType>(AppContext);
const { federation, addNewCoordinator } = useContext<UseFederationStoreType>(FederationContext); const { federation, addNewCoordinator } = useContext<UseFederationStoreType>(FederationContext);
const { garage } = useContext<UseGarageStoreType>(GarageContext); const { garage } = useContext<UseGarageStoreType>(GarageContext);
const maxHeight = (windowSize.height - navbarHeight) * 0.85 - 3; const maxHeight = (windowSize.height - navbarHeight) * 0.85 - 3;
@ -37,6 +37,10 @@ const SettingsPage = (): JSX.Element => {
} }
}; };
useEffect(() => {
if (page === 'settings') void federation.loadInfo();
}, [page]);
return ( return (
<Paper <Paper
elevation={12} elevation={12}

View File

@ -827,7 +827,7 @@ const BookTable = ({
<Grid item xs={6}> <Grid item xs={6}>
<IconButton <IconButton
onClick={() => { onClick={() => {
void federation.updateBook(); void federation.loadBook();
}} }}
> >
<Refresh /> <Refresh />
@ -902,10 +902,6 @@ const BookTable = ({
: orders; : orders;
}, [showControls, orders, fav, paymentMethods]); }, [showControls, orders, fav, paymentMethods]);
const loadingPercentage =
((federation.exchange.enabledCoordinators - federation.exchange.loadingCoordinators) /
federation.exchange.enabledCoordinators) *
100;
if (!fullscreen) { if (!fullscreen) {
return ( return (
<Paper <Paper
@ -938,11 +934,8 @@ const BookTable = ({
setPaymentMethods, setPaymentMethods,
}, },
loadingOverlay: { loadingOverlay: {
variant: variant: 'indeterminate',
federation.exchange.loadingCache || loadingPercentage === 0 value: federation.loading ? 0 : 100,
? 'indeterminate'
: 'determinate',
value: federation.exchange.loadingCache ? 1 : loadingPercentage,
}, },
}} }}
paginationModel={paginationModel} paginationModel={paginationModel}

View File

@ -1,4 +1,4 @@
import React, { useContext, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
@ -68,8 +68,9 @@ import {
} from '../Icons'; } from '../Icons';
import { AppContext } from '../../contexts/AppContext'; import { AppContext } from '../../contexts/AppContext';
import { systemClient } from '../../services/System'; import { systemClient } from '../../services/System';
import { type Badges } from '../../models/Coordinator.model'; import Coordinator, { type Badges } from '../../models/Coordinator.model';
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext'; import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
import { width } from '@mui/system';
interface Props { interface Props {
open: boolean; open: boolean;
@ -348,18 +349,28 @@ const CoordinatorDialog = ({ open = false, onClose, shortAlias }: Props): JSX.El
const { t } = useTranslation(); const { t } = useTranslation();
const { clientVersion, page, settings, origin } = useContext(AppContext); const { clientVersion, page, settings, origin } = useContext(AppContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext); const { federation } = useContext<UseFederationStoreType>(FederationContext);
const coordinator = federation.getCoordinator(shortAlias ?? '');
const [expanded, setExpanded] = useState<'summary' | 'stats' | 'policies' | undefined>(undefined); const [expanded, setExpanded] = useState<'summary' | 'stats' | 'policies' | undefined>(undefined);
const [coordinator, setCoordinator] = useState<Coordinator>(
federation.getCoordinator(shortAlias ?? ''),
);
const listItemProps = { sx: { maxHeight: '3em', width: '100%' } }; const listItemProps = { sx: { maxHeight: '3em', width: '100%' } };
const coordinatorVersion = `v${coordinator?.info?.version?.major ?? '?'}.${ const coordinatorVersion = `v${coordinator?.info?.version?.major ?? '?'}.${
coordinator?.info?.version?.minor ?? '?' coordinator?.info?.version?.minor ?? '?'
}.${coordinator?.info?.version?.patch ?? '?'}`; }.${coordinator?.info?.version?.patch ?? '?'}`;
useEffect(() => {
setCoordinator(federation.getCoordinator(shortAlias ?? ''));
}, [shortAlias]);
useEffect(() => {
if (open) federation.getCoordinator(shortAlias ?? '')?.loadInfo();
}, [open]);
return ( return (
<Dialog open={open} onClose={onClose}> <Dialog open={open} onClose={onClose}>
<DialogContent> <DialogContent style={{ width: 600 }}>
<Typography align='center' component='h5' variant='h5'> <Typography align='center' component='h5' variant='h5'>
{String(coordinator?.longAlias)} {String(coordinator?.longAlias)}
</Typography> </Typography>
@ -483,7 +494,7 @@ const CoordinatorDialog = ({ open = false, onClose, shortAlias }: Props): JSX.El
</ListItemButton> </ListItemButton>
</List> </List>
{coordinator?.loadingInfo ? ( {!coordinator || coordinator?.loadingInfo ? (
<Box style={{ display: 'flex', justifyContent: 'center' }}> <Box style={{ display: 'flex', justifyContent: 'center' }}>
<CircularProgress /> <CircularProgress />
</Box> </Box>

View File

@ -35,18 +35,11 @@ interface Props {
const ExchangeDialog = ({ open = false, onClose }: Props): JSX.Element => { const ExchangeDialog = ({ open = false, onClose }: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
const { federation, federationUpdatedAt } = useContext(FederationContext); const { federation, federationUpdatedAt } = useContext(FederationContext);
const [loadingProgress, setLoadingProgress] = useState<number>(0);
useEffect(() => {
const loadedCoordinators =
federation.exchange.enabledCoordinators - federation.exchange.loadingCoordinators;
setLoadingProgress((loadedCoordinators / federation.exchange.enabledCoordinators) * 100);
}, [open, federationUpdatedAt]);
return ( return (
<Dialog open={open} onClose={onClose}> <Dialog open={open} onClose={onClose}>
<div style={loadingProgress < 100 ? {} : { display: 'none' }}> <div style={federation.loading ? {} : { display: 'none' }}>
<LinearProgress variant='determinate' value={loadingProgress} /> <LinearProgress variant='indeterminate' />
</div> </div>
<DialogContent> <DialogContent>
<Typography component='h5' variant='h5'> <Typography component='h5' variant='h5'>

View File

@ -33,15 +33,13 @@ const ProfileDialog = ({ open = false, onClose }: Props): JSX.Element => {
const slot = garage.getSlot(); const slot = garage.getSlot();
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [loadingCoordinators, setLoadingCoordinators] = useState<number>( const [loadingRobots, setLoadingRobots] = useState<number>(
Object.values(slot?.robots ?? {}).length, Object.values(slot?.robots ?? {}).length,
); );
useEffect(() => { useEffect(() => {
setLoading(!garage.getSlot()?.hashId); setLoading(!garage.getSlot()?.hashId);
setLoadingCoordinators( setLoadingRobots(Object.values(slot?.robots ?? {}).filter((robot) => robot.loading).length);
Object.values(slot?.robots ?? {}).filter((robot) => robot.loading).length,
);
}, [slotUpdatedAt]); }, [slotUpdatedAt]);
return ( return (
@ -85,7 +83,7 @@ const ProfileDialog = ({ open = false, onClose }: Props): JSX.Element => {
)} )}
</Typography> </Typography>
{loadingCoordinators > 0 ? ( {loadingRobots > 0 ? (
<> <>
<b>{t('Looking for your robot!')}</b> <b>{t('Looking for your robot!')}</b>
<LinearProgress /> <LinearProgress />

View File

@ -502,7 +502,6 @@ const MakerForm = ({
(!makerHasAmountRange && maker.amount <= 0) || (!makerHasAmountRange && maker.amount <= 0) ||
(maker.isExplicit && (maker.badSatoshisText !== '' || maker.satoshis === '')) || (maker.isExplicit && (maker.badSatoshisText !== '' || maker.satoshis === '')) ||
(!maker.isExplicit && maker.badPremiumText !== '') || (!maker.isExplicit && maker.badPremiumText !== '') ||
federation.getCoordinator(maker.coordinator)?.info === undefined ||
federation.getCoordinator(maker.coordinator)?.limits === undefined federation.getCoordinator(maker.coordinator)?.limits === undefined
); );
}, [maker, amountLimits, federationUpdatedAt, fav.type, makerHasAmountRange]); }, [maker, amountLimits, federationUpdatedAt, fav.type, makerHasAmountRange]);

View File

@ -86,7 +86,7 @@ const SelectCoordinator: React.FC<SelectCoordinatorProps> = ({
flipHorizontally={false} flipHorizontally={false}
small={true} small={true}
/> />
{(coordinator?.info === undefined || {(coordinator?.limits === undefined ||
Object.keys(coordinator?.limits).length === 0) && ( Object.keys(coordinator?.limits).length === 0) && (
<CircularProgress <CircularProgress
size={49} size={49}

View File

@ -68,12 +68,12 @@ export const FederationContextProvider = ({
useEffect(() => { useEffect(() => {
if (client !== 'mobile' || torStatus === 'ON' || !settings.useProxy) { if (client !== 'mobile' || torStatus === 'ON' || !settings.useProxy) {
void federation.updateUrl(origin, settings, hostUrl); void federation.updateUrl(origin, settings, hostUrl);
void federation.updateMeta(); void federation.loadLimits();
} }
}, [settings.network, settings.useProxy, torStatus]); }, [settings.network, settings.useProxy, torStatus]);
useEffect(() => { useEffect(() => {
federation.setConnection(settings.connection); federation.setConnection(settings);
}, [settings.connection]); }, [settings.connection]);
const addNewCoordinator: (alias: string, url: string) => void = (alias, url) => { const addNewCoordinator: (alias: string, url: string) => void = (alias, url) => {
@ -96,7 +96,7 @@ export const FederationContextProvider = ({
} }
federation.addCoordinator(origin, settings, hostUrl, attributes); federation.addCoordinator(origin, settings, hostUrl, attributes);
const newCoordinator: Coordinator = federation.coordinators[alias]; const newCoordinator: Coordinator = federation.coordinators[alias];
newCoordinator.updateMeta(() => { newCoordinator.loadLimits(() => {
setCoordinatorUpdatedAt(new Date().toISOString()); setCoordinatorUpdatedAt(new Date().toISOString());
}); });
garage.syncCoordinator(federation, alias); garage.syncCoordinator(federation, alias);
@ -106,7 +106,7 @@ export const FederationContextProvider = ({
}; };
useEffect(() => { useEffect(() => {
if (page === 'offers') void federation.updateBook(); if (page === 'offers') void federation.loadBook();
}, [page]); }, [page]);
// use effects to fetchRobots on Profile open // use effects to fetchRobots on Profile open

View File

@ -182,21 +182,6 @@ export class Coordinator {
} }
}; };
updateMeta = async (onUpdate: (shortAlias: string) => void = () => {}): Promise<void> => {
const onDataLoad = (): void => {
if (this.isUpdated()) onUpdate(this.shortAlias);
};
this.loadLimits(onDataLoad);
this.loadInfo(onDataLoad);
};
updateBook = async (onUpdate: (shortAlias: string) => void = () => {}): Promise<void> => {
this.loadBook(() => {
onUpdate(this.shortAlias);
});
};
generateAllMakerAvatars = async (): Promise<void> => { generateAllMakerAvatars = async (): Promise<void> => {
for (const order of Object.values(this.book)) { for (const order of Object.values(this.book)) {
void roboidentitiesClient.generateRobohash(order.maker_hash_id, 'small'); void roboidentitiesClient.generateRobohash(order.maker_hash_id, 'small');
@ -287,7 +272,7 @@ export class Coordinator {
enable = (onEnabled: () => void = () => {}): void => { enable = (onEnabled: () => void = () => {}): void => {
this.enabled = true; this.enabled = true;
void this.updateMeta(() => { void this.loadLimits(() => {
onEnabled(); onEnabled();
}); });
}; };
@ -299,10 +284,6 @@ export class Coordinator {
this.book = {}; this.book = {};
}; };
isUpdated = (): boolean => {
return !((this.loadingBook === this.loadingInfo) === this.loadingLimits);
};
getBaseUrl = (): string => { getBaseUrl = (): string => {
return this.url + this.basePath; return this.url + this.basePath;
}; };

View File

@ -36,9 +36,7 @@ export const updateExchangeInfo = (federation: Federation): ExchangeInfo => {
'lifetime_volume', 'lifetime_volume',
]; ];
Object.values(federation.coordinators) Object.values(federation.coordinators).forEach((coordinator, index) => {
.filter((coor) => coor.isUpdated())
.forEach((coordinator, index) => {
if (coordinator.info !== undefined) { if (coordinator.info !== undefined) {
premiums[index] = coordinator.info.last_day_nonkyc_btc_premium; premiums[index] = coordinator.info.last_day_nonkyc_btc_premium;
volumes[index] = coordinator.info.last_day_volume; volumes[index] = coordinator.info.last_day_volume;

View File

@ -78,18 +78,18 @@ export class Federation {
public relayPool: SimplePool = new SimplePool(); public relayPool: SimplePool = new SimplePool();
public relaySubscriptions: SubCloser[] = []; public relaySubscriptions: SubCloser[] = [];
setConnection = (connection: 'api' | 'nostr'): void => { setConnection = (settings: Settings): void => {
this.connection = connection; this.connection = settings.connection;
if (this.connection === 'nostr') { if (this.connection === 'nostr') {
this.connectNostr(); this.connectNostr(settings);
} else { } else {
this.relayPool.close(Array.from(this.relayPool.trustedRelayURLs)); this.relayPool.close(Array.from(this.relayPool.trustedRelayURLs));
this.updateBook(); this.loadBook();
} }
}; };
connectNostr = (): void => { connectNostr = (settings: Settings): void => {
this.loading = true; this.loading = true;
this.book = {}; this.book = {};
@ -105,7 +105,7 @@ export class Federation {
{ {
authors, authors,
kinds: [38383], kinds: [38383],
'#n': ['mainnet'], '#n': [settings.network],
}, },
], ],
{ {
@ -123,12 +123,6 @@ export class Federation {
this.updateExchange(); this.updateExchange();
this.triggerHook('onFederationUpdate'); this.triggerHook('onFederationUpdate');
}, },
onclose: () => {
this.exchange.loadingCache = this.exchange.loadingCache - 1;
this.loading = this.exchange.loadingCache > 0 && this.exchange.loadingCoordinators > 0;
this.updateExchange();
this.triggerHook('onFederationUpdate');
},
}, },
); );
this.relaySubscriptions.push(sub); this.relaySubscriptions.push(sub);
@ -186,8 +180,7 @@ export class Federation {
systemClient.setCookie('federation', JSON.stringify(federationUrls)); systemClient.setCookie('federation', JSON.stringify(federationUrls));
}; };
updateMeta = async (): Promise<void> => { loadInfo = async (): Promise<void> => {
this.loading = true;
this.exchange.info = { this.exchange.info = {
num_public_buy_orders: 0, num_public_buy_orders: 0,
num_public_sell_orders: 0, num_public_sell_orders: 0,
@ -198,19 +191,30 @@ export class Federation {
lifetime_volume: 0, lifetime_volume: 0,
version: { major: 0, minor: 0, patch: 0 }, version: { major: 0, minor: 0, patch: 0 },
}; };
this.updateEnabledCoordinators();
for (const coor of Object.values(this.coordinators)) {
void coor.loadInfo(() => {
this.onCoordinatorSaved();
});
}
};
loadLimits = async (): Promise<void> => {
this.loading = true;
this.exchange.onlineCoordinators = 0; this.exchange.onlineCoordinators = 0;
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length; this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
this.updateEnabledCoordinators(); this.updateEnabledCoordinators();
for (const coor of Object.values(this.coordinators)) { for (const coor of Object.values(this.coordinators)) {
void coor.updateMeta(() => { void coor.loadLimits(() => {
this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1; this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1;
this.onCoordinatorSaved(); this.onCoordinatorSaved();
}); });
} }
}; };
updateBook = async (): Promise<void> => { loadBook = async (): Promise<void> => {
if (this.connection !== 'api') return; if (this.connection !== 'api') return;
this.loading = true; this.loading = true;
@ -218,7 +222,7 @@ export class Federation {
this.triggerHook('onFederationUpdate'); this.triggerHook('onFederationUpdate');
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length; this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
for (const coor of Object.values(this.coordinators)) { for (const coor of Object.values(this.coordinators)) {
void coor.updateBook(() => { void coor.loadBook(() => {
this.onCoordinatorSaved(); this.onCoordinatorSaved();
this.triggerHook('onFederationUpdate'); this.triggerHook('onFederationUpdate');
}); });