mirror of
https://github.com/Qortal/qapp-core.git
synced 2026-04-30 20:09:22 +00:00
339 lines
9.5 KiB
TypeScript
339 lines
9.5 KiB
TypeScript
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
import { ResourceStatus, usePublishStore } from '../state/publishes';
|
|
import { QortalGetMetadata } from '../types/interfaces/resources';
|
|
|
|
interface PropsUseResourceStatus {
|
|
resource: QortalGetMetadata | null;
|
|
retryAttempts?: number;
|
|
path?: string;
|
|
filename?: string;
|
|
isGlobal?: boolean;
|
|
disableAutoFetch?: boolean;
|
|
}
|
|
export const useResourceStatus = ({
|
|
resource,
|
|
retryAttempts = 40,
|
|
path,
|
|
filename,
|
|
isGlobal,
|
|
disableAutoFetch,
|
|
}: PropsUseResourceStatus) => {
|
|
const resourceId = !resource
|
|
? null
|
|
: `${resource.service}-${resource.name}-${resource.identifier}`;
|
|
const status =
|
|
usePublishStore((state) => state.getResourceStatus(resourceId)) || null;
|
|
const intervalRef = useRef<any>(null);
|
|
const timeoutRef = useRef<any>(null);
|
|
const setResourceStatus = usePublishStore((state) => state.setResourceStatus);
|
|
const getResourceStatus = usePublishStore((state) => state.getResourceStatus);
|
|
|
|
const statusRef = useRef<ResourceStatus | null>(null);
|
|
const startGlobalDownload = usePublishStore(
|
|
(state) => state.startGlobalDownload
|
|
);
|
|
const stopGlobalDownload = usePublishStore(
|
|
(state) => state.stopGlobalDownload
|
|
);
|
|
useEffect(() => {
|
|
statusRef.current = status;
|
|
}, [status]);
|
|
const downloadResource = useCallback(
|
|
(
|
|
{ service, name, identifier }: QortalGetMetadata,
|
|
build?: boolean,
|
|
isRecalling?: boolean
|
|
) => {
|
|
try {
|
|
if (statusRef.current && statusRef.current?.status === 'READY') {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
}
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
}
|
|
intervalRef.current = null;
|
|
timeoutRef.current = null;
|
|
return;
|
|
}
|
|
if (!isRecalling) {
|
|
const id = `${service}-${name}-${identifier}`;
|
|
const resourceStatus = getResourceStatus(id);
|
|
if (!resourceStatus) {
|
|
setResourceStatus(
|
|
{ service, name, identifier },
|
|
{
|
|
status: 'SEARCHING',
|
|
localChunkCount: 0,
|
|
totalChunkCount: 0,
|
|
percentLoaded: 0,
|
|
path: path || '',
|
|
filename: filename || '',
|
|
}
|
|
);
|
|
}
|
|
}
|
|
let isCalling = false;
|
|
let percentLoaded = 0;
|
|
let timer = 29;
|
|
let tries = 0;
|
|
let calledFirstTime = false;
|
|
const callFunction = async () => {
|
|
if (isCalling) return;
|
|
isCalling = true;
|
|
|
|
let res;
|
|
if (!build) {
|
|
res = await qortalRequest({
|
|
action: 'GET_QDN_RESOURCE_STATUS',
|
|
name: name,
|
|
service: service,
|
|
identifier: identifier,
|
|
});
|
|
|
|
setResourceStatus(
|
|
{ service, name, identifier },
|
|
{
|
|
...res,
|
|
}
|
|
);
|
|
if (tries > retryAttempts) {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
}
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
}
|
|
intervalRef.current = null;
|
|
timeoutRef.current = null;
|
|
setResourceStatus(
|
|
{ service, name, identifier },
|
|
{
|
|
...res,
|
|
status: 'FAILED_TO_DOWNLOAD',
|
|
}
|
|
);
|
|
|
|
return;
|
|
}
|
|
tries = tries + 1;
|
|
}
|
|
|
|
if (build || (calledFirstTime === false && res?.status !== 'READY')) {
|
|
const url = `/arbitrary/resource/properties/${service}/${name}/${identifier}?build=true`;
|
|
const resCall = await fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
res = await resCall.json();
|
|
}
|
|
calledFirstTime = true;
|
|
isCalling = false;
|
|
|
|
if (res.localChunkCount) {
|
|
if (res.percentLoaded) {
|
|
if (
|
|
res.percentLoaded === percentLoaded &&
|
|
res.percentLoaded !== 100
|
|
) {
|
|
timer = timer - 5;
|
|
} else {
|
|
timer = 29;
|
|
}
|
|
|
|
if (timer < 0) {
|
|
timer = 29;
|
|
isCalling = true;
|
|
|
|
setResourceStatus(
|
|
{ service, name, identifier },
|
|
{
|
|
...res,
|
|
status: 'REFETCHING',
|
|
}
|
|
);
|
|
|
|
timeoutRef.current = setTimeout(() => {
|
|
isCalling = false;
|
|
downloadResource({ name, service, identifier }, true, true);
|
|
}, 10000);
|
|
|
|
return;
|
|
}
|
|
|
|
percentLoaded = res.percentLoaded;
|
|
}
|
|
|
|
setResourceStatus(
|
|
{ service, name, identifier },
|
|
{
|
|
...res,
|
|
}
|
|
);
|
|
}
|
|
// Check if progress is 100% and clear interval if true
|
|
if (res?.status === 'READY') {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
}
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
}
|
|
intervalRef.current = null;
|
|
timeoutRef.current = null;
|
|
setResourceStatus(
|
|
{ service, name, identifier },
|
|
{
|
|
...res,
|
|
}
|
|
);
|
|
return;
|
|
}
|
|
if (res?.status === 'DOWNLOADED') {
|
|
res = await qortalRequest({
|
|
action: 'GET_QDN_RESOURCE_STATUS',
|
|
name: name,
|
|
service: service,
|
|
identifier: identifier,
|
|
build: true,
|
|
});
|
|
}
|
|
};
|
|
callFunction();
|
|
|
|
if (!intervalRef.current) {
|
|
intervalRef.current = setInterval(callFunction, 5000);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error during resource fetch:', error);
|
|
}
|
|
return () => {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = null;
|
|
}
|
|
};
|
|
},
|
|
[retryAttempts]
|
|
);
|
|
useEffect(() => {
|
|
if (disableAutoFetch) return;
|
|
if (resource?.identifier && resource?.name && resource?.service) {
|
|
const id = `${resource.service}-${resource.name}-${resource.identifier}`;
|
|
|
|
if (isGlobal) {
|
|
startGlobalDownload(id, resource, retryAttempts, path, filename);
|
|
} else {
|
|
statusRef.current = null;
|
|
downloadResource({
|
|
service: resource?.service,
|
|
name: resource?.name,
|
|
identifier: resource?.identifier,
|
|
});
|
|
}
|
|
}
|
|
return () => {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = null;
|
|
}
|
|
};
|
|
}, [
|
|
resource?.identifier,
|
|
resource?.name,
|
|
resource?.service,
|
|
downloadResource,
|
|
isGlobal,
|
|
retryAttempts,
|
|
path,
|
|
filename,
|
|
disableAutoFetch,
|
|
]);
|
|
|
|
const handledownloadResource = useCallback(() => {
|
|
if (resource?.identifier && resource?.name && resource?.service) {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
if (timeoutRef.current) {
|
|
clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = null;
|
|
}
|
|
const id = `${resource?.service}-${resource?.name}-${resource?.identifier}`;
|
|
const resourceStatus = getResourceStatus(id);
|
|
if (!resourceStatus) {
|
|
setResourceStatus(
|
|
{
|
|
service: resource.service,
|
|
name: resource.name,
|
|
identifier: resource.identifier,
|
|
},
|
|
{
|
|
status: 'SEARCHING',
|
|
localChunkCount: 0,
|
|
totalChunkCount: 0,
|
|
percentLoaded: 0,
|
|
path: path || '',
|
|
filename: filename || '',
|
|
}
|
|
);
|
|
}
|
|
if (isGlobal) {
|
|
const id = `${resource.service}-${resource.name}-${resource.identifier}`;
|
|
stopGlobalDownload(id);
|
|
startGlobalDownload(id, resource, retryAttempts, path, filename);
|
|
} else {
|
|
downloadResource({
|
|
service: resource?.service,
|
|
name: resource?.name,
|
|
identifier: resource?.identifier,
|
|
});
|
|
}
|
|
}
|
|
}, [
|
|
resource?.identifier,
|
|
resource?.name,
|
|
resource?.service,
|
|
downloadResource,
|
|
isGlobal,
|
|
retryAttempts,
|
|
path,
|
|
filename,
|
|
]);
|
|
|
|
const resourceUrl = resource
|
|
? `/arbitrary/${resource.service}/${resource.name}/${resource.identifier}`
|
|
: null;
|
|
|
|
return useMemo(
|
|
() => ({
|
|
status: status?.status || 'INITIAL',
|
|
localChunkCount: status?.localChunkCount || 0,
|
|
totalChunkCount: status?.totalChunkCount || 0,
|
|
percentLoaded: status?.percentLoaded || 0,
|
|
isReady: status?.status === 'READY',
|
|
resourceUrl,
|
|
downloadResource: handledownloadResource,
|
|
}),
|
|
[
|
|
status?.status,
|
|
status?.localChunkCount,
|
|
status?.totalChunkCount,
|
|
status?.percentLoaded,
|
|
resourceUrl,
|
|
downloadResource,
|
|
]
|
|
);
|
|
};
|