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'
|
import './index.css'
|
||||||
export { EnumCollisionStrength } from './utils/encryption';
|
export { EnumCollisionStrength } from './utils/encryption';
|
||||||
export { showLoading, dismissToast, showError, showSuccess } from './utils/toast';
|
export { showLoading, dismissToast, showError, showSuccess } from './utils/toast';
|
||||||
|
@ -7,16 +7,41 @@ interface PublishCache {
|
|||||||
expiry: number;
|
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 {
|
interface PublishState {
|
||||||
publishes: Record<string, PublishCache>;
|
publishes: Record<string, PublishCache>;
|
||||||
|
resourceStatus: Record<string, ResourceStatus | null>;
|
||||||
|
setResourceStatus: (qortalGetMetadata: QortalGetMetadata, data: ResourceStatus | null) => void;
|
||||||
getPublish: (qortalGetMetadata: QortalGetMetadata | null, ignoreExpire?: boolean) => Resource | null;
|
getPublish: (qortalGetMetadata: QortalGetMetadata | null, ignoreExpire?: boolean) => Resource | null;
|
||||||
|
getResourceStatus: (resourceId: string) => ResourceStatus | null;
|
||||||
setPublish: (qortalGetMetadata: QortalGetMetadata, data: Resource | null, customExpiry?: number) => void;
|
setPublish: (qortalGetMetadata: QortalGetMetadata, data: Resource | null, customExpiry?: number) => void;
|
||||||
clearExpiredPublishes: () => void;
|
clearExpiredPublishes: () => void;
|
||||||
publishExpiryDuration: number; // Default expiry duration
|
publishExpiryDuration: number; // Default expiry duration
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePublishStore = create<PublishState>((set, get) => ({
|
export const usePublishStore = create<PublishState>((set, get) => ({
|
||||||
|
resourceStatus: {},
|
||||||
publishes: {},
|
publishes: {},
|
||||||
publishExpiryDuration: 5 * 60 * 1000, // Default expiry: 5 minutes
|
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: () => {
|
clearExpiredPublishes: () => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user