Improve Federation start order

This commit is contained in:
KoalaSat 2024-03-28 23:21:15 +01:00
parent 52c20099b6
commit 7128ac7157
No known key found for this signature in database
GPG Key ID: 2F7F61C6146AB157
9 changed files with 33 additions and 113 deletions

View File

@ -226,7 +226,6 @@ const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
value={settings.network}
onChange={(e, network) => {
setSettings({ ...settings, network });
void federation.updateUrls(origin, { ...settings, network }, hostUrl);
systemClient.setItem('settings_network', network);
}}
>

View File

@ -9,7 +9,7 @@ import React, {
type ReactNode,
} from 'react';
import { type Order, Federation } from '../models';
import { type Order, Federation, Settings } from '../models';
import { federationLottery } from '../utils';
@ -62,7 +62,7 @@ export interface UseFederationStoreType {
}
export const initialFederationContext: UseFederationStoreType = {
federation: new Federation(),
federation: new Federation('onion', new Settings(), ''),
sortedCoordinators: [],
setDelay: () => {},
currentOrderId: { id: null, shortAlias: null },
@ -80,7 +80,7 @@ export const FederationContextProvider = ({
const { settings, page, origin, hostUrl, open, torStatus } =
useContext<UseAppStoreType>(AppContext);
const { setMaker, garage, setBadOrder } = useContext<UseGarageStoreType>(GarageContext);
const [federation, setFederation] = useState(initialFederationContext.federation);
const [federation] = useState(new Federation(origin, settings, hostUrl));
const sortedCoordinators = useMemo(() => federationLottery(federation), []);
const [coordinatorUpdatedAt, setCoordinatorUpdatedAt] = useState<string>(
new Date().toISOString(),
@ -102,20 +102,19 @@ export const FederationContextProvider = ({
setMaker((maker) => {
return { ...maker, coordinator: sortedCoordinators[0] };
}); // default MakerForm coordinator is decided via sorted lottery
federation.registerHook('onFederationUpdate', () => {
setFederationUpdatedAt(new Date().toISOString());
});
federation.registerHook('onCoordinatorUpdate', () => {
setCoordinatorUpdatedAt(new Date().toISOString());
});
}, []);
useEffect(() => {
// On bitcoin network change we reset book, limits and federation info and fetch everything again
if (window.NativeRobosats === undefined || torStatus === 'ON') {
const newFed = initialFederationContext.federation;
newFed.registerHook('onFederationUpdate', () => {
setFederationUpdatedAt(new Date().toISOString());
});
newFed.registerHook('onCoordinatorUpdate', () => {
setCoordinatorUpdatedAt(new Date().toISOString());
});
void newFed.start(origin, settings, hostUrl);
setFederation(newFed);
void federation.updateUrl(origin, settings, hostUrl);
void federation.update();
}
}, [settings.network, torStatus]);

View File

@ -97,7 +97,7 @@ function calculateSizeLimit(inputDate: Date): number {
}
export class Coordinator {
constructor(value: any) {
constructor(value: any, origin: Origin, settings: Settings, hostUrl: string) {
const established = new Date(value.established);
this.longAlias = value.longAlias;
this.shortAlias = value.shortAlias;
@ -115,6 +115,8 @@ export class Coordinator {
this.testnetNodesPubkeys = value.testnetNodesPubkeys;
this.url = '';
this.basePath = '';
this.updateUrl(origin, settings, hostUrl);
}
// These properties are loaded from federation.json
@ -145,22 +147,7 @@ export class Coordinator {
public loadingLimits: boolean = false;
public loadingRobot: boolean = true;
start = async (
origin: Origin,
settings: Settings,
hostUrl: string,
onUpdate: (shortAlias: string) => void = () => {},
): Promise<void> => {
if (this.enabled !== true) return;
void this.updateUrl(settings, origin, hostUrl, onUpdate);
};
updateUrl = async (
settings: Settings,
origin: Origin,
hostUrl: string,
onUpdate: (shortAlias: string) => void = () => {},
): Promise<void> => {
updateUrl = (origin: Origin, settings: Settings, hostUrl: string): void => {
if (settings.selfhostedClient && this.shortAlias !== 'local') {
this.url = hostUrl;
this.basePath = `/${settings.network}/${this.shortAlias}`;
@ -168,9 +155,6 @@ export class Coordinator {
this.url = String(this[settings.network][origin]);
this.basePath = '';
}
void this.update(() => {
onUpdate(this.shortAlias);
});
};
update = async (onUpdate: (shortAlias: string) => void = () => {}): Promise<void> => {
@ -205,7 +189,6 @@ export class Coordinator {
apiClient
.get(this.url, `${this.basePath}/api/book/`)
.then((data) => {
console.log('BOOK', data);
if (!data?.not_found) {
this.book = (data as PublicOrder[]).map((order) => {
order.coordinatorShortAlias = this.shortAlias;

View File

@ -14,14 +14,14 @@ import { updateExchangeInfo } from './Exchange.model';
type FederationHooks = 'onCoordinatorUpdate' | 'onFederationUpdate';
export class Federation {
constructor() {
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);
acc[key] = new Coordinator(value, origin, settings, hostUrl);
return acc;
}
},
@ -36,7 +36,16 @@ export class Federation {
onCoordinatorUpdate: [],
onFederationUpdate: [],
};
this.loading = true;
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
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';
}
public coordinators: Record<string, Coordinator>;
@ -69,38 +78,10 @@ export class Federation {
this.triggerHook('onFederationUpdate');
};
// Setup
start = async (origin: Origin, settings: Settings, hostUrl: string): Promise<void> => {
const onCoordinatorStarted = (): void => {
this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1;
this.onCoordinatorSaved();
};
this.loading = true;
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
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';
updateUrl = async (origin: Origin, settings: Settings, hostUrl: string): Promise<void> => {
for (const coor of Object.values(this.coordinators)) {
if (coor.enabled) {
await coor.start(origin, settings, hostUrl, onCoordinatorStarted);
coor.updateUrl(origin, settings, hostUrl);
}
}
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;
};
update = async (): Promise<void> => {
@ -115,9 +96,12 @@ export class Federation {
lifetime_volume: 0,
version: { major: 0, minor: 0, patch: 0 },
};
this.exchange.onlineCoordinators = 0;
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
this.updateEnabledCoordinators();
for (const coor of Object.values(this.coordinators)) {
await coor.update(() => {
this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1;
this.onCoordinatorSaved();
});
}

View File

@ -14,7 +14,7 @@ export interface ReactNativeWebView {
export interface NativeWebViewMessageHttp {
id?: number;
category: 'http';
type: 'post' | 'get' | 'put' | 'delete' | 'xhr';
type: 'post' | 'get' | 'put' | 'delete';
path: string;
baseUrl: string;
headers?: object;

View File

@ -90,41 +90,6 @@ class ApiNativeClient implements ApiClient {
headers: this.getHeaders(auth),
}).then(this.parseResponse);
};
public fileImageUrl: (baseUrl: string, path: string) => Promise<string | undefined> = async (
baseUrl,
path,
) => {
if (path === '') {
return await Promise.resolve('');
}
if (this.assetsCache[path] != null) {
return await Promise.resolve(this.assetsCache[path]);
} else if (this.assetsPromises.has(path)) {
return await this.assetsPromises.get(path);
}
this.assetsPromises.set(
path,
new Promise<string>((resolve, reject) => {
window.NativeRobosats?.postMessage({
category: 'http',
type: 'xhr',
baseUrl,
path,
})
.then((fileB64: { b64Data: string }) => {
this.assetsCache[path] = `data:image/png;base64,${fileB64.b64Data}`;
this.assetsPromises.delete(path);
resolve(this.assetsCache[path]);
})
.catch(reject);
}),
);
return await this.assetsPromises.get(path);
};
}
export default ApiNativeClient;

View File

@ -11,7 +11,6 @@ export interface ApiClient {
put: (baseUrl: string, path: string, body: object, auth?: Auth) => Promise<object | undefined>;
get: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined>;
delete: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined>;
fileImageUrl?: (baseUrl: string, path: string) => Promise<string | undefined>;
}
export const apiClient: ApiClient =

View File

@ -23,7 +23,6 @@ const App = () => {
useEffect(() => {
TorModule.start();
DeviceEventEmitter.addListener('TorStatus', (payload) => {
console.log(payload.torStatus);
if (payload.torStatus === 'OFF') TorModule.restart();
injectMessage({
category: 'system',
@ -119,14 +118,6 @@ const App = () => {
})
.catch((e) => onCatch(data.id, e))
.finally(TorModule.getTorStatus);
} else if (data.type === 'xhr') {
torClient
.request(data.baseUrl, data.path)
.then((response: object) => {
injectMessageResolve(data.id, response);
})
.catch((e) => onCatch(data.id, e))
.finally(TorModule.getTorStatus);
}
} else if (data.category === 'system') {
if (data.type === 'init') {

View File

@ -85,7 +85,7 @@ public class TorModule extends ReactContextBaseJavaModule {
throw new RuntimeException(e);
}
});
if (response.code() != 200) {
if (response.code() != 200 && response.code() != 201) {
Log.d("RobosatsError", "Request error code: " + response.code());
} else if (response.isSuccessful()) {
promise.resolve("{\"json\":" + body + ", \"headers\": " + headersJson +"}");