Skip to content

Commit

Permalink
Add external coordinator (#1297)
Browse files Browse the repository at this point in the history
* Add external coordinator

* CR
  • Loading branch information
KoalaSat authored Jun 25, 2024
1 parent 10f88e3 commit 8168108
Show file tree
Hide file tree
Showing 32 changed files with 1,519 additions and 1,256 deletions.
36 changes: 19 additions & 17 deletions frontend/src/basic/OrderPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,26 @@ const OrderPage = (): JSX.Element => {
useEffect(() => {
const shortAlias = params.shortAlias;
const coordinator = federation.getCoordinator(shortAlias ?? '');
const { url, basePath } = coordinator.getEndpoint(
settings.network,
origin,
settings.selfhostedClient,
hostUrl,
);
if (coordinator) {
const { url, basePath } = coordinator?.getEndpoint(
settings.network,
origin,
settings.selfhostedClient,
hostUrl,
);

setBaseUrl(`${url}${basePath}`);
setBaseUrl(`${url}${basePath}`);

const orderId = Number(params.orderId);
if (
orderId &&
currentOrderId.id !== orderId &&
currentOrderId.shortAlias !== shortAlias &&
shortAlias
)
setCurrentOrderId({ id: orderId, shortAlias });
if (!acknowledgedWarning) setOpen({ ...closeAll, warning: true });
const orderId = Number(params.orderId);
if (
orderId &&
currentOrderId.id !== orderId &&
currentOrderId.shortAlias !== shortAlias &&
shortAlias
)
setCurrentOrderId({ id: orderId, shortAlias });
if (!acknowledgedWarning) setOpen({ ...closeAll, warning: true });
}
}, [params, currentOrderId]);

const onClickCoordinator = function (): void {
Expand Down Expand Up @@ -98,7 +100,7 @@ const OrderPage = (): JSX.Element => {
setOpen(closeAll);
setAcknowledgedWarning(true);
}}
longAlias={federation.getCoordinator(params.shortAlias ?? '').longAlias}
longAlias={federation.getCoordinator(params.shortAlias ?? '')?.longAlias}
/>
{currentOrder === null && badOrder === undefined && <CircularProgress />}
{badOrder !== undefined ? (
Expand Down
62 changes: 60 additions & 2 deletions frontend/src/basic/SettingsPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
import React, { useContext } from 'react';
import { Grid, Paper } from '@mui/material';
import React, { useContext, useState } from 'react';
import { Button, Grid, List, ListItem, Paper, TextField, Typography } from '@mui/material';
import SettingsForm from '../../components/SettingsForm';
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
import FederationTable from '../../components/FederationTable';
import { t } from 'i18next';
import { FederationContext, UseFederationStoreType } from '../../contexts/FederationContext';

const SettingsPage = (): JSX.Element => {
const { windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);
const { federation, addNewCoordinator } = useContext<UseFederationStoreType>(FederationContext);
const maxHeight = (windowSize.height - navbarHeight) * 0.85 - 3;
const [newAlias, setNewAlias] = useState<string>('');
const [newUrl, setNewUrl] = useState<string>('');
const [error, setError] = useState<string>();
// Regular expression to match a valid .onion URL
const onionUrlPattern = /^(http:\/\/|https:\/\/)?[a-zA-Z2-7]{16,56}\.onion$/;

const addCoordinator = () => {
if (federation.coordinators[newAlias]) {
setError(t('Alias already exists'));
} else {
if (onionUrlPattern.test(newUrl)) {
addNewCoordinator(newAlias, newUrl);
setNewAlias('');
setNewUrl('');
} else {
setError(t('Invalid URL'));
}
}
};

return (
<Paper
Expand All @@ -26,6 +48,42 @@ const SettingsPage = (): JSX.Element => {
<Grid item>
<FederationTable maxHeight={18} />
</Grid>
<Grid item>
<Typography align='center' component='h2' variant='subtitle2' color='secondary'>
{error}
</Typography>
</Grid>
<List>
<ListItem>
<TextField
id='outlined-basic'
label={t('Alias')}
variant='outlined'
size='small'
value={newAlias}
onChange={(e) => setNewAlias(e.target.value)}
/>
<TextField
id='outlined-basic'
label={t('URL')}
variant='outlined'
size='small'
value={newUrl}
onChange={(e) => setNewUrl(e.target.value)}
/>
<Button
sx={{ maxHeight: 38 }}
disabled={false}
onClick={addCoordinator}
variant='contained'
color='primary'
size='small'
type='submit'
>
{t('Add')}
</Button>
</ListItem>
</List>
</Grid>
</Paper>
);
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/BookTable/BookControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,8 @@ const BookControl = ({
>
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
<RobotAvatar
shortAlias={coordinator.shortAlias}
shortAlias={coordinator.federated ? coordinator.shortAlias : undefined}
hashId={coordinator.federated ? undefined : coordinator.mainnet.onion}
style={{ width: '1.55em', height: '1.55em' }}
smooth={true}
small={true}
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/BookTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ const BookTable = ({
headerName: t('Host'),
width: width * fontSize,
renderCell: (params: any) => {
const coordinator = federation.coordinators[params.row.coordinatorShortAlias];
return (
<ListItemButton
style={{ cursor: 'pointer' }}
Expand All @@ -262,7 +263,8 @@ const BookTable = ({
>
<ListItemAvatar sx={{ position: 'relative', left: '-1.54em', bottom: '0.4em' }}>
<RobotAvatar
shortAlias={params.row.coordinatorShortAlias}
shortAlias={coordinator.federated ? params.row.coordinatorShortAlias : undefined}
hashId={coordinator.federated ? undefined : coordinator.mainnet.onion}
style={{ width: '3.215em', height: '3.215em' }}
smooth={true}
small={true}
Expand Down Expand Up @@ -900,7 +902,6 @@ const BookTable = ({
((federation.exchange.enabledCoordinators - federation.exchange.loadingCoordinators) /
federation.exchange.enabledCoordinators) *
100;

if (!fullscreen) {
return (
<Paper
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Dialogs/Coordinator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ const ContactButtons = ({
</Grid>
)}

{pgp !== undefined && (
{pgp && fingerprint && (
<Grid item>
<Tooltip
enterTouchDelay={0}
Expand Down Expand Up @@ -368,7 +368,8 @@ const CoordinatorDialog = ({ open = false, onClose, network, shortAlias }: Props
<Grid container direction='column' alignItems='center' padding={0}>
<Grid item>
<RobotAvatar
shortAlias={coordinator?.shortAlias}
shortAlias={coordinator?.federated ? coordinator?.shortAlias : undefined}
hashId={coordinator?.federated ? undefined : coordinator?.shortAlias}
style={{ width: '7.5em', height: '7.5em' }}
smooth={true}
/>
Expand Down
23 changes: 14 additions & 9 deletions frontend/src/components/FederationTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState, useContext } from 'react';
import React, { useCallback, useEffect, useState, useContext, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, useTheme, Checkbox, CircularProgress, Typography, Grid } from '@mui/material';
import { DataGrid, type GridColDef, type GridValidRowModel } from '@mui/x-data-grid';
Expand All @@ -21,9 +21,9 @@ const FederationTable = ({
fillContainer = false,
}: FederationTableProps): JSX.Element => {
const { t } = useTranslation();
const { federation, sortedCoordinators, coordinatorUpdatedAt } =
const { federation, sortedCoordinators, coordinatorUpdatedAt, federationUpdatedAt } =
useContext<UseFederationStoreType>(FederationContext);
const { setOpen } = useContext<UseAppStoreType>(AppContext);
const { setOpen, settings } = useContext<UseAppStoreType>(AppContext);
const theme = useTheme();
const [pageSize, setPageSize] = useState<number>(0);

Expand All @@ -43,7 +43,7 @@ const FederationTable = ({
if (useDefaultPageSize) {
setPageSize(defaultPageSize);
}
}, [coordinatorUpdatedAt]);
}, [coordinatorUpdatedAt, federationUpdatedAt]);

const localeText = {
MuiTablePagination: { labelRowsPerPage: t('Coordinators per page:') },
Expand All @@ -62,6 +62,7 @@ const FederationTable = ({
headerName: t('Coordinator'),
width: width * fontSize,
renderCell: (params: any) => {
const coordinator = federation.coordinators[params.row.shortAlias];
return (
<Grid
container
Expand All @@ -76,7 +77,8 @@ const FederationTable = ({
>
<Grid item>
<RobotAvatar
shortAlias={params.row.shortAlias}
shortAlias={coordinator.federated ? params.row.shortAlias : undefined}
hashId={coordinator.federated ? undefined : coordinator.mainnet.onion}
style={{ width: '3.215em', height: '3.215em' }}
smooth={true}
small={true}
Expand Down Expand Up @@ -212,10 +214,13 @@ const FederationTable = ({
}
};

const reorderedCoordinators = sortedCoordinators.reduce((coordinators, key) => {
coordinators[key] = federation.coordinators[key];
return coordinators;
}, {});
const reorderedCoordinators = useMemo(() => {
return sortedCoordinators.reduce((coordinators, key) => {
coordinators[key] = federation.coordinators[key];

return coordinators;
}, {});
}, [settings.network, federationUpdatedAt]);

return (
<Box
Expand Down
11 changes: 4 additions & 7 deletions frontend/src/components/MakerForm/SelectCoordinator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ const SelectCoordinator: React.FC<SelectCoordinatorProps> = ({
setCoordinator,
}) => {
const { setOpen } = useContext<UseAppStoreType>(AppContext);
const { federation, sortedCoordinators, coordinatorUpdatedAt } =
useContext<UseFederationStoreType>(FederationContext);
const { federation, sortedCoordinators } = useContext<UseFederationStoreType>(FederationContext);
const theme = useTheme();
const { t } = useTranslation();

Expand All @@ -41,10 +40,7 @@ const SelectCoordinator: React.FC<SelectCoordinatorProps> = ({
setCoordinator(e.target.value);
};

const coordinator = useMemo(
() => federation.getCoordinator(coordinatorAlias),
[coordinatorUpdatedAt],
);
const coordinator = federation.getCoordinator(coordinatorAlias);

return (
<Grid item>
Expand Down Expand Up @@ -83,7 +79,8 @@ const SelectCoordinator: React.FC<SelectCoordinatorProps> = ({
>
<Grid item>
<RobotAvatar
shortAlias={coordinatorAlias}
shortAlias={coordinator?.federated ? coordinator.shortAlias : undefined}
hashId={coordinator?.federated ? undefined : coordinator.mainnet.onion}
style={{ width: '3em', height: '3em' }}
smooth={true}
flipHorizontally={false}
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/components/OrderDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,12 @@ const OrderDetails = ({
{' '}
<Grid container direction='row' justifyContent='center' alignItems='center'>
<Grid item xs={2}>
<RobotAvatar shortAlias={coordinator.shortAlias} small={true} smooth={true} />
<RobotAvatar
shortAlias={coordinator.federated ? coordinator.shortAlias : undefined}
hashId={coordinator.federated ? undefined : coordinator.mainnet.onion}
small={true}
smooth={true}
/>
</Grid>
<Grid item xs={4}>
<ListItemText primary={coordinator.longAlias} secondary={t('Order host')} />
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/RobotAvatar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ const RobotAvatar: React.FC<Props> = ({
}, [hashId]);

useEffect(() => {
if (shortAlias !== undefined) {
if (window.NativeRobosats === undefined) {
if (shortAlias && shortAlias !== '') {
if (!window.NativeRobosats) {
setAvatarSrc(
`${hostUrl}/static/federation/avatars/${shortAlias}${small ? '.small' : ''}.webp`,
);
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/SettingsForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
AccountBalance,
AttachMoney,
QrCode,
ControlPoint,
} from '@mui/icons-material';
import { systemClient } from '../../services/System';
import { TorIcon } from '../Icons';
Expand Down
31 changes: 29 additions & 2 deletions frontend/src/contexts/FederationContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, {
type ReactNode,
} from 'react';

import { type Order, Federation, Settings } from '../models';
import { type Order, Federation, Settings, Coordinator } from '../models';

import { federationLottery } from '../utils';

Expand Down Expand Up @@ -59,6 +59,7 @@ export interface UseFederationStoreType {
currentOrder: Order | null;
coordinatorUpdatedAt: string;
federationUpdatedAt: string;
addNewCoordinator: (alias: string, url: string) => void;
}

export const initialFederationContext: UseFederationStoreType = {
Expand All @@ -70,6 +71,7 @@ export const initialFederationContext: UseFederationStoreType = {
currentOrder: null,
coordinatorUpdatedAt: '',
federationUpdatedAt: '',
addNewCoordinator: () => {},
};

export const FederationContext = createContext<UseFederationStoreType>(initialFederationContext);
Expand All @@ -81,7 +83,7 @@ export const FederationContextProvider = ({
useContext<UseAppStoreType>(AppContext);
const { setMaker, garage, setBadOrder } = useContext<UseGarageStoreType>(GarageContext);
const [federation] = useState(new Federation(origin, settings, hostUrl));
const sortedCoordinators = useMemo(() => federationLottery(federation), []);
const [sortedCoordinators, setSortedCoordinators] = useState(federationLottery(federation));
const [coordinatorUpdatedAt, setCoordinatorUpdatedAt] = useState<string>(
new Date().toISOString(),
);
Expand Down Expand Up @@ -164,6 +166,30 @@ export const FederationContextProvider = ({
}
};

const addNewCoordinator: (alias: string, url: string) => void = (alias, url) => {
if (!federation.coordinators[alias]) {
const attributes: Record<any, any> = {
longAlias: alias,
shortAlias: alias,
federated: false,
enabled: true,
};
if (settings.network === 'mainnet') {
attributes.mainnet = url;
} else {
attributes.testnet = url;
}
federation.addCoordinator(origin, settings, hostUrl, attributes);
const newCoordinator = federation.coordinators[alias];
newCoordinator.update(() => {
setCoordinatorUpdatedAt(new Date().toISOString());
});
garage.syncCoordinator(newCoordinator);
setSortedCoordinators(federationLottery(federation));
setFederationUpdatedAt(new Date().toISOString());
}
};

useEffect(() => {
if (currentOrderId.id && currentOrderId.shortAlias) {
setCurrentOrder(null);
Expand Down Expand Up @@ -200,6 +226,7 @@ export const FederationContextProvider = ({
setDelay,
coordinatorUpdatedAt,
federationUpdatedAt,
addNewCoordinator,
}}
>
{children}
Expand Down
Loading

0 comments on commit 8168108

Please sign in to comment.