From cd031149de24c8db8fba2bc82cfbcd2121719416 Mon Sep 17 00:00:00 2001 From: koalasat Date: Thu, 10 Jul 2025 18:23:45 +0200 Subject: [PATCH] Improve client performance --- .../src/basic/SettingsPage/Coordinators.tsx | 37 ++++++++++++- frontend/src/components/BookTable/index.tsx | 13 ++--- .../src/components/Dialogs/Coordinator.tsx | 2 +- .../src/components/FederationTable/index.tsx | 3 +- .../src/components/MakerForm/MakerForm.tsx | 27 ++++----- .../MakerForm/SelectCoordinator.tsx | 3 +- frontend/src/contexts/FederationContext.tsx | 55 ++----------------- frontend/src/models/Federation.model.ts | 29 +++++----- 8 files changed, 73 insertions(+), 96 deletions(-) diff --git a/frontend/src/basic/SettingsPage/Coordinators.tsx b/frontend/src/basic/SettingsPage/Coordinators.tsx index c1a7731c..4e0e9392 100644 --- a/frontend/src/basic/SettingsPage/Coordinators.tsx +++ b/frontend/src/basic/SettingsPage/Coordinators.tsx @@ -4,9 +4,14 @@ import FederationTable from '../../components/FederationTable'; import { t } from 'i18next'; import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext'; import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext'; +import { Garage } from '../../models'; +import { Origin, Origins } from '../../models/Coordinator.model'; +import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; const Coordinators = (): React.JSX.Element => { - const { federation, addNewCoordinator } = useContext(FederationContext); + const { settings, origin, hostUrl } = useContext(AppContext); + const { federation, setFederationUpdatedAt } = + useContext(FederationContext); const { garage } = useContext(GarageContext); const [newAlias, setNewAlias] = useState(''); const [newUrl, setNewUrl] = useState(''); @@ -15,6 +20,34 @@ const Coordinators = (): React.JSX.Element => { // Regular expression to match a valid .onion URL const onionUrlPattern = /^((http|https):\/\/)?[a-zA-Z2-7]{16,56}\.onion$\/?/; + const addNewCoordinator: (alias: string, garage: Garage, url: string) => void = ( + alias, + garage, + url, + ) => { + if (!federation.getCoordinator(alias)) { + const attributes: object = { + longAlias: alias, + shortAlias: alias, + federated: false, + enabled: true, + }; + const origins: Origins = { + clearnet: undefined, + onion: url as Origin, + i2p: undefined, + }; + if (settings.network === 'mainnet') { + attributes.mainnet = origins; + } else { + attributes.testnet = origins; + } + federation.addCoordinator(origin, settings, hostUrl, attributes); + garage.syncCoordinator(federation, alias); + setFederationUpdatedAt(new Date().toISOString()); + } + }; + const addCoordinator: () => void = () => { if (federation.getCoordinator(newAlias)) { setError(t('Alias already exists')); @@ -24,7 +57,7 @@ const Coordinators = (): React.JSX.Element => { if (!/^((http|https):\/\/)/.test(fullNewUrl)) { fullNewUrl = `http://${newUrl}`; } - addNewCoordinator(newAlias, fullNewUrl); + addNewCoordinator(newAlias, garage, fullNewUrl); garage.syncCoordinator(federation, newAlias); setNewAlias(''); setNewUrl(''); diff --git a/frontend/src/components/BookTable/index.tsx b/frontend/src/components/BookTable/index.tsx index e7c64ba6..3eaa5bda 100644 --- a/frontend/src/components/BookTable/index.tsx +++ b/frontend/src/components/BookTable/index.tsx @@ -343,11 +343,9 @@ const BookTable = ({ flex: 2, renderCell: (params: { row: PublicOrder }) => { const currencyCode = String(currencyDict[params.row.currency.toString()]); - const coordinator = - federation.getCoordinator(params.row.coordinatorShortAlias) ?? - federation.getCoordinators()[0]; + const limits = federation.getLimits(params.row.coordinatorShortAlias); const premium = parseFloat(params.row.premium); - const limitPrice = coordinator.limits[params.row.currency.toString()]?.price; + const limitPrice = limits[params.row.currency.toString()]?.price; const price = (limitPrice ?? 1) * (1 + premium / 100); return ( @@ -501,16 +499,13 @@ const BookTable = ({ type: 'number', flex: 1, renderCell: (params: { row: PublicOrder }) => { - const coordinator = - federation.getCoordinator(params.row.coordinatorShortAlias) ?? - federation.getCoordinators()[0]; + const limits = federation.getLimits(params.row.coordinatorShortAlias); const amount = params.row.has_range === true ? parseFloat(params.row.max_amount) : parseFloat(params.row.amount); const premium = parseFloat(params.row.premium); - const price = - (coordinator.limits[params.row.currency.toString()]?.price ?? 1) * (1 + premium / 100); + const price = (limits[params.row.currency.toString()]?.price ?? 1) * (1 + premium / 100); const satoshisNow = (100000000 * amount) / price; return ( diff --git a/frontend/src/components/Dialogs/Coordinator.tsx b/frontend/src/components/Dialogs/Coordinator.tsx index fde6fc92..847d31a5 100644 --- a/frontend/src/components/Dialogs/Coordinator.tsx +++ b/frontend/src/components/Dialogs/Coordinator.tsx @@ -388,7 +388,7 @@ const CoordinatorDialog = ({ open = false, onClose, shortAlias }: Props): React. coordinator.shortAlias, ); } - coordinator?.loadInfo(); + if (!coordinator.info) coordinator?.loadInfo(); } }, [open]); diff --git a/frontend/src/components/FederationTable/index.tsx b/frontend/src/components/FederationTable/index.tsx index d7013022..236b04b2 100644 --- a/frontend/src/components/FederationTable/index.tsx +++ b/frontend/src/components/FederationTable/index.tsx @@ -57,6 +57,7 @@ const FederationTable = ({ const mobile = windowSize.width < 44; useEffect(() => { + federation.loadInfo(); loadRatings(); }, []); @@ -240,7 +241,7 @@ const FederationTable = ({ onClickCoordinator(params.row.shortAlias); }} > - {Boolean(params.row.loadingLimits) && Boolean(params.row.enabled) ? ( + {Boolean(params.row.loadingInfo) && Boolean(params.row.enabled) ? ( ) : params.row.limits !== undefined ? ( diff --git a/frontend/src/components/MakerForm/MakerForm.tsx b/frontend/src/components/MakerForm/MakerForm.tsx index f4526794..6ca78f55 100644 --- a/frontend/src/components/MakerForm/MakerForm.tsx +++ b/frontend/src/components/MakerForm/MakerForm.tsx @@ -86,31 +86,26 @@ const MakerForm = ({ const amountSafeThresholds = [1.03, 0.98]; - useEffect(() => { - federation - .loadInfo() - .then(() => {}) - .catch((error) => { - console.error('Error loading info:', error); - }); - }, []); - useEffect(() => { setCurrencyCode(currencyDict[fav.currency === 0 ? 1 : fav.currency]); }, [federationUpdatedAt]); useEffect(() => { updateCoordinatorInfo(); - }, [maker.coordinator, federationUpdatedAt]); + }, [maker.coordinator]); const updateCoordinatorInfo = (): void => { if (maker.coordinator != null) { - const newLimits = federation.getCoordinator(maker.coordinator)?.limits; - if (newLimits && Object.keys(newLimits).length !== 0) { - updateAmountLimits(newLimits, fav.currency, maker.premium); - updateCurrentPrice(newLimits, fav.currency, maker.premium); - setLimits(newLimits); - } + const coordinator = federation.getCoordinator(maker.coordinator); + coordinator.loadInfo(); + coordinator.loadLimits(() => { + const newLimits = coordinator.limits; + if (newLimits && Object.keys(newLimits).length !== 0) { + updateAmountLimits(newLimits, fav.currency, maker.premium); + updateCurrentPrice(newLimits, fav.currency, maker.premium); + setLimits(newLimits); + } + }); } }; diff --git a/frontend/src/components/MakerForm/SelectCoordinator.tsx b/frontend/src/components/MakerForm/SelectCoordinator.tsx index 2b5c4a2a..9f112b68 100644 --- a/frontend/src/components/MakerForm/SelectCoordinator.tsx +++ b/frontend/src/components/MakerForm/SelectCoordinator.tsx @@ -102,8 +102,7 @@ const SelectCoordinator: React.FC = ({ flipHorizontally={false} small={true} /> - {(coordinator?.limits === undefined || - Object.keys(coordinator?.limits).length === 0) && ( + {(coordinator?.loadingInfo || coordinator?.loadingLimits) && ( void; + setFederationUpdatedAt: (federationUpdatedAt: string) => void; } const initialFederation = new Federation('onion', new Settings(), ''); export const initialFederationContext: UseFederationStoreType = { federation: initialFederation, - coordinatorUpdatedAt: '', federationUpdatedAt: '', - addNewCoordinator: () => {}, + setFederationUpdatedAt: () => {}, }; export const FederationContext = createContext(initialFederationContext); @@ -37,13 +33,10 @@ export const FederationContext = createContext(initialFe export const FederationContextProvider = ({ children, }: FederationContextProviderProps): React.JSX.Element => { - const { settings, page, origin, hostUrl, open, torStatus, client, fav } = + const { settings, page, origin, hostUrl, torStatus, client, fav } = useContext(AppContext); - const { setMaker, garage } = useContext(GarageContext); + const { setMaker } = useContext(GarageContext); const [federation] = useState(initialFederationContext.federation); - const [coordinatorUpdatedAt, setCoordinatorUpdatedAt] = useState( - new Date().toISOString(), - ); const [federationUpdatedAt, setFederationUpdatedAt] = useState(new Date().toISOString()); useEffect(() => { @@ -61,54 +54,16 @@ export const FederationContextProvider = ({ } }, [settings.network, settings.useProxy, torStatus, settings.connection]); - const addNewCoordinator: (alias: string, url: string) => void = (alias, url) => { - if (!federation.getCoordinator(alias)) { - const attributes: object = { - longAlias: alias, - shortAlias: alias, - federated: false, - enabled: true, - }; - const origins: Origins = { - clearnet: undefined, - onion: url as Origin, - i2p: undefined, - }; - if (settings.network === 'mainnet') { - attributes.mainnet = origins; - } else { - attributes.testnet = origins; - } - federation.addCoordinator(origin, settings, hostUrl, attributes); - const newCoordinator: Coordinator = federation.getCoordinator(alias); - newCoordinator.loadLimits(() => { - setCoordinatorUpdatedAt(new Date().toISOString()); - }); - garage.syncCoordinator(federation, alias); - setFederationUpdatedAt(new Date().toISOString()); - } - }; - useEffect(() => { if (page === 'offers') void federation.loadBook(); }, [page]); - // use effects to fetchRobots on Profile open - useEffect(() => { - const slot = garage.getSlot(); - - if (open.profile && slot?.hashId && slot?.token) { - void garage.fetchRobot(federation, slot?.token); // refresh/update existing robot - } - }, [open.profile]); - return ( {children} diff --git a/frontend/src/models/Federation.model.ts b/frontend/src/models/Federation.model.ts index 17dac90c..69bc2fd4 100644 --- a/frontend/src/models/Federation.model.ts +++ b/frontend/src/models/Federation.model.ts @@ -1,6 +1,7 @@ import { Coordinator, type Exchange, + LimitList, type Origin, type PublicOrder, type Settings, @@ -90,7 +91,7 @@ export class Federation { coordinators.forEach((c) => c.updateUrl(origin, settings, hostUrl)); this.roboPool.updateRelays(hostUrl, Object.values(this.coordinators)); - void this.loadLimits(); + coordinators[0].loadLimits(); if (this.connection === 'nostr') { this.loadBookNostr(coordinator !== 'any'); @@ -194,20 +195,6 @@ export class Federation { } }; - loadLimits = async (): Promise => { - this.loading = true; - this.exchange.onlineCoordinators = 0; - this.exchange.loadingCoordinators = Object.keys(this.coordinators).length; - this.updateEnabledCoordinators(); - - for (const coor of Object.values(this.coordinators)) { - coor.loadLimits(() => { - this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1; - this.onCoordinatorSaved(); - }); - } - }; - loadBook = async (): Promise => { if (this.connection !== 'api') return; @@ -229,6 +216,18 @@ export class Federation { this.triggerHook('onFederationUpdate'); }; + getLimits = (shortAlias: string): LimitList => { + console.log('shortAlias', shortAlias); + let limits = this.coordinators[shortAlias]?.limits || {}; + + console.log('limits pre', Object.keys(limits).length); + if (Object.keys(limits).length === 0) { + limits = this.getCoordinators()[0]?.limits; + } + console.log('limits', Object.keys(limits).length); + return limits; + }; + // Coordinators getCoordinators = (): Coordinator[] => { return Object.values(this.coordinators);