Skip to content

Add external coordinator #1297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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