mirror of
https://github.com/RoboSats/robosats.git
synced 2025-09-13 00:56:22 +00:00
Add external coordinator
This commit is contained in:
@ -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 {
|
||||
@ -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 ? (
|
||||
|
||||
@ -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
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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.shortAlias}
|
||||
style={{ width: '1.55em', height: '1.55em' }}
|
||||
smooth={true}
|
||||
small={true}
|
||||
|
||||
@ -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' }}
|
||||
@ -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}
|
||||
@ -900,7 +902,6 @@ const BookTable = ({
|
||||
((federation.exchange.enabledCoordinators - federation.exchange.loadingCoordinators) /
|
||||
federation.exchange.enabledCoordinators) *
|
||||
100;
|
||||
|
||||
if (!fullscreen) {
|
||||
return (
|
||||
<Paper
|
||||
|
||||
@ -127,7 +127,7 @@ const ContactButtons = ({
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{pgp !== undefined && (
|
||||
{pgp && fingerprint && (
|
||||
<Grid item>
|
||||
<Tooltip
|
||||
enterTouchDelay={0}
|
||||
@ -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}
|
||||
/>
|
||||
|
||||
@ -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';
|
||||
@ -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);
|
||||
|
||||
@ -43,7 +43,7 @@ const FederationTable = ({
|
||||
if (useDefaultPageSize) {
|
||||
setPageSize(defaultPageSize);
|
||||
}
|
||||
}, [coordinatorUpdatedAt]);
|
||||
}, [coordinatorUpdatedAt, federationUpdatedAt]);
|
||||
|
||||
const localeText = {
|
||||
MuiTablePagination: { labelRowsPerPage: t('Coordinators per page:') },
|
||||
@ -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
|
||||
@ -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}
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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>
|
||||
@ -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.shortAlias}
|
||||
style={{ width: '3em', height: '3em' }}
|
||||
smooth={true}
|
||||
flipHorizontally={false}
|
||||
|
||||
@ -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.shortAlias}
|
||||
small={true}
|
||||
smooth={true}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<ListItemText primary={coordinator.longAlias} secondary={t('Order host')} />
|
||||
|
||||
@ -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`,
|
||||
);
|
||||
|
||||
@ -26,6 +26,7 @@ import {
|
||||
AccountBalance,
|
||||
AttachMoney,
|
||||
QrCode,
|
||||
ControlPoint,
|
||||
} from '@mui/icons-material';
|
||||
import { systemClient } from '../../services/System';
|
||||
import { TorIcon } from '../Icons';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -59,6 +59,7 @@ export interface UseFederationStoreType {
|
||||
currentOrder: Order | null;
|
||||
coordinatorUpdatedAt: string;
|
||||
federationUpdatedAt: string;
|
||||
addNewCoordinator: (alias: string, url: string) => void;
|
||||
}
|
||||
|
||||
export const initialFederationContext: UseFederationStoreType = {
|
||||
@ -70,6 +71,7 @@ export const initialFederationContext: UseFederationStoreType = {
|
||||
currentOrder: null,
|
||||
coordinatorUpdatedAt: '',
|
||||
federationUpdatedAt: '',
|
||||
addNewCoordinator: () => {},
|
||||
};
|
||||
|
||||
export const FederationContext = createContext<UseFederationStoreType>(initialFederationContext);
|
||||
@ -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(),
|
||||
);
|
||||
@ -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);
|
||||
@ -200,6 +226,7 @@ export const FederationContextProvider = ({
|
||||
setDelay,
|
||||
coordinatorUpdatedAt,
|
||||
federationUpdatedAt,
|
||||
addNewCoordinator,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@ -72,6 +72,39 @@ export interface Info {
|
||||
|
||||
export type Origin = 'onion' | 'i2p' | 'clearnet';
|
||||
|
||||
export const coordinatorDefaultValues = {
|
||||
longAlias: '',
|
||||
shortAlias: '',
|
||||
description: '',
|
||||
motto: '',
|
||||
color: '#000',
|
||||
size_limit: 21 * 100000000,
|
||||
established: new Date(),
|
||||
policies: {},
|
||||
contact: {
|
||||
email: '',
|
||||
telegram: '',
|
||||
simplex: '',
|
||||
matrix: '',
|
||||
website: '',
|
||||
nostr: '',
|
||||
pgp: '',
|
||||
fingerprint: '',
|
||||
},
|
||||
badges: {
|
||||
isFounder: false,
|
||||
donatesToDevFund: 0,
|
||||
hasGoodOpSec: false,
|
||||
robotsLove: false,
|
||||
hasLargeLimits: false,
|
||||
},
|
||||
mainnet: undefined,
|
||||
testnet: undefined,
|
||||
mainnetNodesPubkeys: '',
|
||||
testnetNodesPubkeys: '',
|
||||
federated: true,
|
||||
};
|
||||
|
||||
export interface Origins {
|
||||
clearnet: Origin | undefined;
|
||||
onion: Origin | undefined;
|
||||
@ -102,6 +135,7 @@ export class Coordinator {
|
||||
this.longAlias = value.longAlias;
|
||||
this.shortAlias = value.shortAlias;
|
||||
this.description = value.description;
|
||||
this.federated = value.federated;
|
||||
this.motto = value.motto;
|
||||
this.color = value.color;
|
||||
this.size_limit = value.badges.isFounder ? 21 * 100000000 : calculateSizeLimit(established);
|
||||
@ -122,6 +156,7 @@ export class Coordinator {
|
||||
// These properties are loaded from federation.json
|
||||
public longAlias: string;
|
||||
public shortAlias: string;
|
||||
public federated: boolean;
|
||||
public enabled?: boolean = true;
|
||||
public description: string;
|
||||
public motto: string;
|
||||
|
||||
@ -9,39 +9,34 @@ import {
|
||||
} from '.';
|
||||
import defaultFederation from '../../static/federation.json';
|
||||
import { getHost } from '../utils';
|
||||
import { coordinatorDefaultValues } from './Coordinator.model';
|
||||
import { updateExchangeInfo } from './Exchange.model';
|
||||
|
||||
type FederationHooks = 'onCoordinatorUpdate' | 'onFederationUpdate';
|
||||
|
||||
export class Federation {
|
||||
constructor(origin: Origin, settings: Settings, hostUrl: string) {
|
||||
this.coordinators = Object.entries(defaultFederation).reduce(
|
||||
(acc: Record<string, Coordinator>, [key, value]: [string, any]) => {
|
||||
if (getHost() !== '127.0.0.1:8000' && key === 'local') {
|
||||
// Do not add `Local Dev` unless it is running on localhost
|
||||
return acc;
|
||||
} else {
|
||||
acc[key] = new Coordinator(value, origin, settings, hostUrl);
|
||||
return acc;
|
||||
}
|
||||
},
|
||||
{},
|
||||
);
|
||||
this.exchange = {
|
||||
...defaultExchange,
|
||||
totalCoordinators: Object.keys(this.coordinators).length,
|
||||
};
|
||||
this.coordinators = {};
|
||||
this.exchange = { ...defaultExchange };
|
||||
this.book = [];
|
||||
this.hooks = {
|
||||
onCoordinatorUpdate: [],
|
||||
onFederationUpdate: [],
|
||||
};
|
||||
|
||||
this.loading = true;
|
||||
Object.keys(defaultFederation).forEach((key) => {
|
||||
if (key !== 'local' || getHost() === '127.0.0.1:8000') {
|
||||
// Do not add `Local Dev` unless it is running on localhost
|
||||
this.addCoordinator(origin, settings, hostUrl, defaultFederation[key]);
|
||||
}
|
||||
});
|
||||
|
||||
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
|
||||
this.loading = true;
|
||||
|
||||
const host = getHost();
|
||||
const url = `${window.location.protocol}//${host}`;
|
||||
|
||||
const tesnetHost = Object.values(this.coordinators).find((coor) => {
|
||||
return Object.values(coor.testnet).includes(url);
|
||||
});
|
||||
@ -55,6 +50,22 @@ export class Federation {
|
||||
|
||||
public hooks: Record<FederationHooks, Array<() => void>>;
|
||||
|
||||
addCoordinator = (
|
||||
origin: Origin,
|
||||
settings: Settings,
|
||||
hostUrl: string,
|
||||
attributes: Record<any, any>,
|
||||
) => {
|
||||
const value = {
|
||||
...coordinatorDefaultValues,
|
||||
...attributes,
|
||||
};
|
||||
this.coordinators[value.shortAlias] = new Coordinator(value, origin, settings, hostUrl);
|
||||
this.exchange.totalCoordinators = Object.keys(this.coordinators).length;
|
||||
this.updateEnabledCoordinators();
|
||||
this.triggerHook('onFederationUpdate');
|
||||
};
|
||||
|
||||
// Hooks
|
||||
registerHook = (hookName: FederationHooks, fn: () => void): void => {
|
||||
this.hooks[hookName].push(fn);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { type Order } from '.';
|
||||
import { Coordinator, type Order } from '.';
|
||||
import { systemClient } from '../services/System';
|
||||
import { saveAsJson } from '../utils';
|
||||
import Slot from './Slot.model';
|
||||
@ -62,12 +62,10 @@ class Garage {
|
||||
this.slots[rawSlot.token] = new Slot(rawSlot.token, Object.keys(rawSlot.robots), {}, () =>
|
||||
this.triggerHook('onRobotUpdate'),
|
||||
);
|
||||
|
||||
Object.keys(rawSlot.robots).forEach((shortAlias) => {
|
||||
const rawRobot = rawSlot.robots[shortAlias];
|
||||
this.updateRobot(rawSlot.token, shortAlias, rawRobot);
|
||||
});
|
||||
|
||||
this.currentSlot = rawSlot?.token;
|
||||
}
|
||||
});
|
||||
@ -160,6 +158,13 @@ class Garage {
|
||||
this.triggerHook('onOrderUpdate');
|
||||
}
|
||||
};
|
||||
|
||||
// Coordinators
|
||||
syncCoordinator: (coordinator: Coordinator) => void = (coordinator) => {
|
||||
Object.values(this.slots).forEach((slot) => {
|
||||
slot.syncCoordinator(coordinator, this);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default Garage;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { sha256 } from 'js-sha256';
|
||||
import { Robot, type Order } from '.';
|
||||
import { Coordinator, Garage, Robot, type Order } from '.';
|
||||
import { roboidentitiesClient } from '../services/Roboidentities/Web';
|
||||
|
||||
class Slot {
|
||||
@ -73,6 +73,18 @@ class Slot {
|
||||
|
||||
return this.robots[shortAlias];
|
||||
};
|
||||
|
||||
syncCoordinator: (coordinator: Coordinator, garage: Garage) => void = (coordinator, garage) => {
|
||||
const defaultRobot = this.getRobot();
|
||||
if (defaultRobot?.token) {
|
||||
this.robots[coordinator.shortAlias] = new Robot({
|
||||
token: defaultRobot.token,
|
||||
pubKey: defaultRobot.pubKey,
|
||||
encPrivKey: defaultRobot.encPrivKey,
|
||||
});
|
||||
coordinator.fetchRobot(garage, defaultRobot.token);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default Slot;
|
||||
|
||||
Reference in New Issue
Block a user