diff --git a/src/components/molecules/Bookmarks.tsx b/src/components/molecules/Bookmarks.tsx index 527a62e0a..5449acd9c 100644 --- a/src/components/molecules/Bookmarks.tsx +++ b/src/components/molecules/Bookmarks.tsx @@ -9,6 +9,7 @@ import { getAssetsFromDidList } from '../../utils/aquarius' import { getAssetsBestPrices, AssetListPrices } from '../../utils/subgraph' import axios, { CancelToken } from 'axios' import { useSiteMetadata } from '../../hooks/useSiteMetadata' +import { useCancelToken } from '../../hooks/useCancelToken' async function getAssetsBookmarked( bookmarks: string[], @@ -60,12 +61,10 @@ export default function Bookmarks(): ReactElement { const [pinned, setPinned] = useState() const [isLoading, setIsLoading] = useState() const { chainIds } = useUserPreferences() - + const newCancelToken = useCancelToken() useEffect(() => { if (!appConfig?.metadataCacheUri || bookmarks === []) return - const source = axios.CancelToken.source() - async function init() { if (!bookmarks?.length) { setPinned([]) @@ -78,7 +77,7 @@ export default function Bookmarks(): ReactElement { const resultPinned = await getAssetsBookmarked( bookmarks, chainIds, - source.token + newCancelToken() ) const pinnedAssets: AssetListPrices[] = await getAssetsBestPrices( resultPinned?.results @@ -91,11 +90,7 @@ export default function Bookmarks(): ReactElement { setIsLoading(false) } init() - - return () => { - source.cancel() - } - }, [bookmarks, chainIds, appConfig?.metadataCacheUri]) + }, [appConfig?.metadataCacheUri, bookmarks, chainIds, newCancelToken]) return ( () const { chainId } = useWeb3() + const newCancelToken = useCancelToken() function loadFileInfo() { - const source = axios.CancelToken.source() const config = getOceanConfig(chainId || 1) async function validateUrl() { @@ -25,7 +26,7 @@ export default function FilesInput(props: InputProps): ReactElement { const checkedFile = await fileinfo( fileUrl, config?.providerUri, - source.token + newCancelToken() ) checkedFile && helpers.setValue([checkedFile]) } catch (error) { @@ -37,10 +38,6 @@ export default function FilesInput(props: InputProps): ReactElement { } fileUrl && validateUrl() - - return () => { - source.cancel() - } } useEffect(() => { diff --git a/src/components/organisms/AssetActions/Compute/index.tsx b/src/components/organisms/AssetActions/Compute/index.tsx index 14a8b0f79..189338164 100644 --- a/src/components/organisms/AssetActions/Compute/index.tsx +++ b/src/components/organisms/AssetActions/Compute/index.tsx @@ -40,6 +40,8 @@ import { getPreviousOrders, getPrice } from '../../../../utils/subgraph' import AssetActionHistoryTable from '../../AssetActionHistoryTable' import ComputeJobs from '../../../pages/Profile/History/ComputeJobs' import { BestPrice } from '../../../../models/BestPrice' +import { useCancelToken } from '../../../../hooks/useCancelToken' +import { useIsMounted } from '../../../../hooks/useIsMounted' const SuccessAction = () => (
(1) const [service, setServiceType] = useState('dataset OR algorithm') + const newCancelToken = useCancelToken() useEffect(() => { if (!accountId) return - const cancelTokenSource = axios.CancelToken.source() - async function getPublished() { try { setIsLoading(true) const result = await getPublishedAssets( accountId, chainIds, - cancelTokenSource.token, + newCancelToken(), page - 1, service ) @@ -44,11 +43,14 @@ export default function PublishedList({ } } getPublished() - - return () => { - cancelTokenSource.cancel() - } - }, [accountId, page, appConfig.metadataCacheUri, chainIds, service]) + }, [ + accountId, + page, + appConfig.metadataCacheUri, + chainIds, + service, + newCancelToken + ]) return accountId ? ( <> diff --git a/src/components/pages/Publish/index.tsx b/src/components/pages/Publish/index.tsx index 8b73c1884..609ec96ee 100644 --- a/src/components/pages/Publish/index.tsx +++ b/src/components/pages/Publish/index.tsx @@ -122,12 +122,11 @@ export default function PublishPage({ nextState?: Partial>> ) => void ): Promise { - const metadata = transformPublishFormToMetadata(values) - const timeout = mapTimeoutStringToSeconds(values.timeout) - - const serviceType = values.access === 'Download' ? 'access' : 'compute' - try { + const metadata = transformPublishFormToMetadata(values) + const timeout = mapTimeoutStringToSeconds(values.timeout) + + const serviceType = values.access === 'Download' ? 'access' : 'compute' Logger.log( 'Publish with ', metadata, diff --git a/src/components/templates/Search/index.tsx b/src/components/templates/Search/index.tsx index 9642ce209..94d211988 100644 --- a/src/components/templates/Search/index.tsx +++ b/src/components/templates/Search/index.tsx @@ -7,9 +7,8 @@ import Sort from './sort' import { getResults } from './utils' import { navigate } from 'gatsby' import { updateQueryStringParameter } from '../../../utils' -import { useSiteMetadata } from '../../../hooks/useSiteMetadata' import { useUserPreferences } from '../../../providers/UserPreferences' -import axios from 'axios' +import { useCancelToken } from '../../../hooks/useCancelToken' import styles from './index.module.css' export default function SearchPage({ @@ -21,7 +20,6 @@ export default function SearchPage({ setTotalResults: (totalResults: number) => void setTotalPagesNumber: (totalPagesNumber: number) => void }): ReactElement { - const { appConfig } = useSiteMetadata() const parsed = queryString.parse(location.search) const { text, owner, tags, page, sort, sortOrder, serviceType, accessType } = parsed @@ -34,23 +32,19 @@ export default function SearchPage({ const [sortDirection, setSortDirection] = useState( sortOrder as string ) + const newCancelToken = useCancelToken() useEffect(() => { - const source = axios.CancelToken.source() - async function initSearch() { setLoading(true) setTotalResults(undefined) - const queryResult = await getResults(parsed, chainIds, source.token) + const queryResult = await getResults(parsed, chainIds, newCancelToken()) setQueryResult(queryResult) setTotalResults(queryResult.totalResults) setTotalPagesNumber(queryResult.totalPages) setLoading(false) } initSearch() - return () => { - source.cancel() - } }, [ text, owner, @@ -60,7 +54,8 @@ export default function SearchPage({ serviceType, accessType, sortOrder, - chainIds + chainIds, + newCancelToken ]) function setPage(page: number) { diff --git a/src/hooks/useCancelToken.ts b/src/hooks/useCancelToken.ts new file mode 100644 index 000000000..35eb3d0a9 --- /dev/null +++ b/src/hooks/useCancelToken.ts @@ -0,0 +1,18 @@ +import { useRef, useEffect, useCallback } from 'react' +import axios, { CancelToken } from 'axios' +export const useCancelToken = (): (() => CancelToken) => { + const axiosSource = useRef(null) + const newCancelToken = useCallback(() => { + axiosSource.current = axios.CancelToken.source() + return axiosSource.current.token + }, []) + + useEffect( + () => () => { + if (axiosSource.current) axiosSource.current.cancel() + }, + [] + ) + + return newCancelToken +} diff --git a/src/hooks/useIsMounted.ts b/src/hooks/useIsMounted.ts new file mode 100644 index 000000000..a214c7bcb --- /dev/null +++ b/src/hooks/useIsMounted.ts @@ -0,0 +1,14 @@ +import { useCallback, useEffect, useRef } from 'react' + +export function useIsMounted(): () => boolean { + const isMountedRef = useRef(true) + const isMounted = useCallback(() => isMountedRef.current, []) + + useEffect(() => { + return () => { + isMountedRef.current = false + } + }, []) + + return isMounted +} diff --git a/src/providers/Asset.tsx b/src/providers/Asset.tsx index ed9800310..19bf78e3a 100644 --- a/src/providers/Asset.tsx +++ b/src/providers/Asset.tsx @@ -17,6 +17,7 @@ import { MetadataMarket } from '../@types/MetaData' import { useWeb3 } from './Web3' import { useSiteMetadata } from '../hooks/useSiteMetadata' import { BestPrice } from '../models/BestPrice' +import { useCancelToken } from '../hooks/useCancelToken' interface AssetProviderValue { isInPurgatory: boolean @@ -61,7 +62,7 @@ function AssetProvider({ const [type, setType] = useState() const [loading, setLoading] = useState(false) const [isAssetNetwork, setIsAssetNetwork] = useState() - + const newCancelToken = useCancelToken() const fetchDdo = async (token?: CancelToken) => { Logger.log('[asset] Init asset, get DDO') setLoading(true) @@ -92,11 +93,10 @@ function AssetProvider({ useEffect(() => { if (!asset || !appConfig.metadataCacheUri) return - const source = axios.CancelToken.source() let isMounted = true async function init() { - const ddo = await fetchDdo(source.token) + const ddo = await fetchDdo(newCancelToken()) if (!isMounted) return Logger.debug('[asset] Got DDO', ddo) setDDO(ddo) @@ -105,7 +105,6 @@ function AssetProvider({ init() return () => { isMounted = false - source.cancel() } }, [asset, appConfig.metadataCacheUri]) diff --git a/src/utils/aquarius.ts b/src/utils/aquarius.ts index c671ed0ce..94ed89716 100644 --- a/src/utils/aquarius.ts +++ b/src/utils/aquarius.ts @@ -146,9 +146,9 @@ export async function getAssetsNames( export async function transformDDOToAssetSelection( datasetProviderEndpoint: string, ddoList: DDO[], - selectedAlgorithms?: PublisherTrustedAlgorithm[] + selectedAlgorithms?: PublisherTrustedAlgorithm[], + cancelToken?: CancelToken ): Promise { - const source = axios.CancelToken.source() const didList: string[] = [] const priceList: PriceList = await getAssetsPriceList(ddoList) const symbolList: any = {} @@ -160,7 +160,7 @@ export async function transformDDOToAssetSelection( algoComputeService?.serviceEndpoint && (didProviderEndpointMap[ddo.id] = algoComputeService?.serviceEndpoint) } - const ddoNames = await getAssetsNames(didList, source.token) + const ddoNames = await getAssetsNames(didList, cancelToken) const algorithmList: AssetSelectionAsset[] = [] didList?.forEach((did: string) => { if ( @@ -197,12 +197,12 @@ export async function transformDDOToAssetSelection( export async function getAlgorithmDatasetsForCompute( algorithmId: string, datasetProviderUri: string, - datasetChainId?: number + datasetChainId?: number, + cancelToken?: CancelToken ): Promise { - const source = axios.CancelToken.source() const computeDatasets = await queryMetadata( getQueryForAlgorithmDatasets(algorithmId, datasetChainId), - source.token + cancelToken ) const computeDatasetsForCurrentAlgorithm: DDO[] = [] computeDatasets.results.forEach((data: DDO) => { @@ -219,7 +219,8 @@ export async function getAlgorithmDatasetsForCompute( const datasets = await transformDDOToAssetSelection( datasetProviderUri, computeDatasetsForCurrentAlgorithm, - [] + [], + cancelToken ) return datasets } diff --git a/src/utils/provider.ts b/src/utils/provider.ts index 898894eee..89c253c98 100644 --- a/src/utils/provider.ts +++ b/src/utils/provider.ts @@ -62,21 +62,30 @@ export async function getFileInfo( url: string | DID, providerUri: string, cancelToken: CancelToken -): Promise { +): Promise { let postBody try { if (url instanceof DID) postBody = { - did: url.getDid(), - cancelToken + did: url.getDid() } else postBody = { - url, - cancelToken + url } - return await axios.post(`${providerUri}/api/v1/services/fileinfo`, postBody) + const response = await axios.post( + `${providerUri}/api/v1/services/fileinfo`, + postBody, + { cancelToken } + ) + + if (!response || response.status !== 200 || !response.data) return + return response.data } catch (error) { - Logger.error(error.message) + if (axios.isCancel(error)) { + Logger.log(error.message) + } else { + Logger.error(error.message) + } } } diff --git a/src/utils/rbac.ts b/src/utils/rbac.ts index 80b08e4f5..3add363ed 100644 --- a/src/utils/rbac.ts +++ b/src/utils/rbac.ts @@ -3,7 +3,8 @@ import appConfig from '../../app.config' export default async function rbacRequest( eventType: string, - address: string + address: string, + signal?: AbortSignal ): Promise { const url = appConfig.rbacUrl if (url === undefined) { @@ -23,7 +24,8 @@ export default async function rbacRequest( headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(data) + body: JSON.stringify(data), + signal: signal }) return await response.json() } catch (error) {