qapp-core/src/hooks/useResourceStatus.tsx

212 lines
6.4 KiB
TypeScript

import React, { 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;
}
export const useResourceStatus = ({
resource,
retryAttempts = 50,
}: PropsUseResourceStatus) => {
const resourceId = !resource ? null : `${resource.service}-${resource.name}-${resource.identifier}`;
const status = usePublishStore((state)=> state.getResourceStatus(resourceId)) || null
const intervalRef = useRef<null | number>(null)
const timeoutRef = useRef<null | number>(null)
const setResourceStatus = usePublishStore((state) => state.setResourceStatus);
const statusRef = useRef<ResourceStatus | null>(null)
useEffect(()=> {
statusRef.current = status
}, [status])
const downloadResource = useCallback(
({ service, name, identifier }: QortalGetMetadata, build?: boolean) => {
try {
if(statusRef.current && statusRef.current?.status === 'READY'){
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
return
}
setResourceStatus(
{ service, name, identifier },
{
"status": "SEARCHING",
"localChunkCount": 0,
"totalChunkCount": 0,
"percentLoaded": 0
}
);
let isCalling = false;
let percentLoaded = 0;
let timer = 24;
let tries = 0;
let calledFirstTime = false;
const callFunction = async () => {
if (isCalling) return;
isCalling = true;
let res;
if (!build) {
const urlFirstTime = `/arbitrary/resource/status/${service}/${name}/${identifier}`;
const resCall = await fetch(urlFirstTime, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
res = await resCall.json();
setResourceStatus(
{ service, name, identifier },
{
...res
}
);
if (tries > retryAttempts) {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
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 = 24;
}
if (timer < 0) {
timer = 24;
isCalling = true;
setResourceStatus(
{ service, name, identifier },
{
...res,
status: "REFETCHING",
}
);
timeoutRef.current = setTimeout(() => {
isCalling = false;
downloadResource({ name, service, identifier }, true);
}, 25000);
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);
}
setResourceStatus({service, name, identifier}, {
...res,
})
}
if (res?.status === "DOWNLOADED") {
const url = `/arbitrary/resource/status/${service}/${name}/${identifier}?build=true`;
const resCall = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
res = await resCall.json();
}
};
callFunction();
intervalRef.current = setInterval(async () => {
callFunction();
}, 5000);
} catch (error) {
console.error("Error during resource fetch:", error);
}
},
[retryAttempts]
);
useEffect(() => {
if (resource?.identifier && resource?.name && resource?.service) {
downloadResource({
service: resource?.service,
name: resource?.name,
identifier: resource?.identifier,
});
}
return ()=> {
if(intervalRef.current){
clearInterval(intervalRef.current)
}
if(timeoutRef.current){
clearTimeout(timeoutRef.current)
}
}
}, [
resource?.identifier,
resource?.name,
resource?.service,
downloadResource,
]);
const resourceUrl = resource ? `/arbitrary/${resource.service}/${resource.name}/${resource.identifier}` : null;
return useMemo(() => ({
status: status?.status || "SEARCHING",
localChunkCount: status?.localChunkCount || 0,
totalChunkCount: status?.totalChunkCount || 0,
percentLoaded: status?.percentLoaded || 0,
isReady: status?.status === 'READY',
resourceUrl,
}), [status?.status, status?.localChunkCount, status?.totalChunkCount, status?.percentLoaded, resourceUrl]);
};