robosats/frontend/src/models/Federation.model.ts

176 lines
5.1 KiB
TypeScript
Raw Normal View History

import {
Coordinator,
2023-10-27 11:00:53 +00:00
type Exchange,
type Garage,
type Origin,
type PublicOrder,
type Settings,
defaultExchange,
} from '.';
import defaultFederation from '../../static/federation.json';
import { getHost } from '../utils';
import { updateExchangeInfo } from './Exchange.model';
type FederationHooks = 'onCoordinatorUpdate' | 'onFederationUpdate';
export class Federation {
constructor() {
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);
return acc;
}
},
{},
);
this.exchange = {
...defaultExchange,
totalCoordinators: Object.keys(this.coordinators).length,
};
this.book = [];
this.hooks = {
onCoordinatorUpdate: [],
onFederationUpdate: [],
};
this.loading = true;
}
public coordinators: Record<string, Coordinator>;
public exchange: Exchange;
public book: PublicOrder[];
public loading: boolean;
2023-10-27 11:00:53 +00:00
public hooks: Record<FederationHooks, Array<() => void>>;
// Hooks
registerHook = (hookName: FederationHooks, fn: () => void): void => {
this.hooks[hookName].push(fn);
};
triggerHook = (hookName: FederationHooks): void => {
2023-10-27 11:00:53 +00:00
this.hooks[hookName]?.forEach((fn) => {
fn();
});
};
onCoordinatorSaved = (): void => {
this.book = Object.values(this.coordinators).reduce<PublicOrder[]>((array, coordinator) => {
return [...array, ...coordinator.book];
}, []);
this.triggerHook('onCoordinatorUpdate');
this.exchange.loadingCoordinators =
this.exchange.loadingCoordinators < 1 ? 0 : this.exchange.loadingCoordinators - 1;
this.loading = this.exchange.loadingCoordinators > 0;
this.updateExchange();
this.triggerHook('onFederationUpdate');
};
// Setup
2023-11-02 14:15:18 +00:00
start = async (origin: Origin, settings: Settings, hostUrl: string): Promise<void> => {
const onCoordinatorStarted = (): void => {
this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1;
this.onCoordinatorSaved();
};
2024-03-19 15:02:46 +00:00
this.loading = true;
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
2024-03-19 15:02:46 +00:00
const host = getHost();
const url = `${window.location.protocol}//${host}`;
const tesnetHost = Object.values(this.coordinators).find((coor) => {
return Object.values(coor.testnet).includes(url);
});
if (tesnetHost) settings.network = 'testnet';
2023-11-02 14:15:18 +00:00
for (const coor of Object.values(this.coordinators)) {
if (coor.enabled) {
await coor.start(origin, settings, hostUrl, onCoordinatorStarted);
}
2023-11-02 14:15:18 +00:00
}
this.updateEnabledCoordinators();
};
// On Testnet/Mainnet change
updateUrls = async (origin: Origin, settings: Settings, hostUrl: string): Promise<void> => {
this.loading = true;
for (const coor of Object.values(this.coordinators)) {
await coor.updateUrl(settings, origin, hostUrl);
}
this.loading = false;
};
2023-11-02 14:15:18 +00:00
update = async (): Promise<void> => {
this.loading = true;
this.exchange.info = {
num_public_buy_orders: 0,
num_public_sell_orders: 0,
book_liquidity: 0,
active_robots_today: 0,
last_day_nonkyc_btc_premium: 0,
last_day_volume: 0,
lifetime_volume: 0,
version: { major: 0, minor: 0, patch: 0 },
};
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
2023-11-02 14:15:18 +00:00
for (const coor of Object.values(this.coordinators)) {
2023-10-27 11:00:53 +00:00
await coor.update(() => {
this.onCoordinatorSaved();
2023-10-27 11:00:53 +00:00
});
2023-11-02 14:15:18 +00:00
}
};
2023-12-22 12:58:59 +00:00
updateBook = async (): Promise<void> => {
this.loading = true;
this.triggerHook('onCoordinatorUpdate');
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
2023-12-22 12:58:59 +00:00
for (const coor of Object.values(this.coordinators)) {
await coor.updateBook(() => {
this.onCoordinatorSaved();
2023-12-22 12:58:59 +00:00
});
}
};
2023-11-02 14:15:18 +00:00
updateExchange = (): void => {
this.exchange.info = updateExchangeInfo(this);
this.triggerHook('onFederationUpdate');
};
// Fetchs
2023-11-21 17:36:59 +00:00
fetchRobot = async (garage: Garage, token: string): Promise<void> => {
Object.values(this.coordinators).forEach((coor) => {
2024-01-14 16:56:03 +00:00
void coor.fetchRobot(garage, token);
});
};
2023-10-27 11:00:53 +00:00
// Coordinators
getCoordinator = (shortAlias: string): Coordinator => {
return this.coordinators[shortAlias];
};
2023-11-02 14:15:18 +00:00
disableCoordinator = (shortAlias: string): void => {
this.coordinators[shortAlias].disable();
this.updateEnabledCoordinators();
2023-11-01 12:18:00 +00:00
this.triggerHook('onCoordinatorUpdate');
};
2023-11-02 14:15:18 +00:00
enableCoordinator = (shortAlias: string): void => {
2023-11-01 12:18:00 +00:00
this.coordinators[shortAlias].enable(() => {
this.updateEnabledCoordinators();
2023-11-01 12:18:00 +00:00
this.triggerHook('onCoordinatorUpdate');
});
};
updateEnabledCoordinators = (): void => {
this.exchange.enabledCoordinators = Object.values(this.coordinators).filter(
(c) => c.enabled,
).length;
this.triggerHook('onFederationUpdate');
};
}
export default Federation;