mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-06-18 19:01:21 +00:00
added useResource status hook
This commit is contained in:
parent
069eca59d0
commit
6fbffcbb50
187
src/hooks/useResourceStatus.tsx
Normal file
187
src/hooks/useResourceStatus.tsx
Normal file
@ -0,0 +1,187 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import { usePublishStore } from "../state/publishes";
|
||||
import { QortalGetMetadata } from "../types/interfaces/resources";
|
||||
|
||||
interface PropsUseResourceStatus {
|
||||
resource: QortalGetMetadata;
|
||||
retryAttempts?: number;
|
||||
}
|
||||
export const useResourceStatus = ({
|
||||
resource,
|
||||
retryAttempts = 15,
|
||||
}: PropsUseResourceStatus) => {
|
||||
const resourceId = `${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 downloadResource = useCallback(
|
||||
({ service, name, identifier }: QortalGetMetadata, build?: boolean) => {
|
||||
try {
|
||||
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,
|
||||
]);
|
||||
return !status ? null : {...(status || {}), isReady: status?.status === 'READY'};
|
||||
};
|
@ -1,3 +1,4 @@
|
||||
export { useResourceStatus } from './hooks/useResourceStatus';
|
||||
import './index.css'
|
||||
export { EnumCollisionStrength } from './utils/encryption';
|
||||
export { showLoading, dismissToast, showError, showSuccess } from './utils/toast';
|
||||
|
@ -7,16 +7,41 @@ interface PublishCache {
|
||||
expiry: number;
|
||||
}
|
||||
|
||||
export type Status =
|
||||
| 'PUBLISHED'
|
||||
| 'NOT_PUBLISHED'
|
||||
| 'DOWNLOADING'
|
||||
| 'DOWNLOADED'
|
||||
| 'BUILDING'
|
||||
| 'READY'
|
||||
| 'MISSING_DATA'
|
||||
| 'BUILD_FAILED'
|
||||
| 'UNSUPPORTED'
|
||||
| 'BLOCKED'
|
||||
| 'FAILED_TO_DOWNLOAD'
|
||||
| 'REFETCHING'
|
||||
| 'SEARCHING'
|
||||
|
||||
export interface ResourceStatus {
|
||||
status: Status
|
||||
localChunkCount: number
|
||||
totalChunkCount: number
|
||||
percentLoaded: number
|
||||
|
||||
}
|
||||
interface PublishState {
|
||||
publishes: Record<string, PublishCache>;
|
||||
|
||||
resourceStatus: Record<string, ResourceStatus | null>;
|
||||
setResourceStatus: (qortalGetMetadata: QortalGetMetadata, data: ResourceStatus | null) => void;
|
||||
getPublish: (qortalGetMetadata: QortalGetMetadata | null, ignoreExpire?: boolean) => Resource | null;
|
||||
getResourceStatus: (resourceId: string) => ResourceStatus | null;
|
||||
setPublish: (qortalGetMetadata: QortalGetMetadata, data: Resource | null, customExpiry?: number) => void;
|
||||
clearExpiredPublishes: () => void;
|
||||
publishExpiryDuration: number; // Default expiry duration
|
||||
}
|
||||
|
||||
export const usePublishStore = create<PublishState>((set, get) => ({
|
||||
resourceStatus: {},
|
||||
publishes: {},
|
||||
publishExpiryDuration: 5 * 60 * 1000, // Default expiry: 5 minutes
|
||||
|
||||
@ -52,7 +77,23 @@ export const usePublishStore = create<PublishState>((set, get) => ({
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
setResourceStatus: (qortalGetMetadata, data) => {
|
||||
const id = `${qortalGetMetadata.service}-${qortalGetMetadata.name}-${qortalGetMetadata.identifier}`;
|
||||
const existingData = get().resourceStatus[id] || {};
|
||||
set((state) => ({
|
||||
resourceStatus: {
|
||||
...state.resourceStatus,
|
||||
[id]: !data ? null : {
|
||||
...existingData,
|
||||
...data
|
||||
},
|
||||
},
|
||||
}));
|
||||
},
|
||||
getResourceStatus: (resourceId) => {
|
||||
const status = get().resourceStatus[resourceId];
|
||||
return status || null;
|
||||
},
|
||||
clearExpiredPublishes: () => {
|
||||
set((state) => {
|
||||
const now = Date.now();
|
||||
|
Loading…
x
Reference in New Issue
Block a user