mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-06-14 17:41:20 +00:00
fixes
This commit is contained in:
parent
5e05ecff28
commit
f83ce67072
@ -66,6 +66,7 @@ interface BaseProps {
|
||||
resourceCacheDuration?: number
|
||||
disablePagination?: boolean
|
||||
disableScrollTracker?: boolean
|
||||
retryAttempts: number
|
||||
}
|
||||
|
||||
// ✅ Restrict `direction` only when `disableVirtualization = false`
|
||||
@ -99,9 +100,10 @@ export const MemorizedComponent = ({
|
||||
resourceCacheDuration,
|
||||
disablePagination,
|
||||
disableScrollTracker,
|
||||
entityParams
|
||||
entityParams,
|
||||
retryAttempts = 2
|
||||
}: PropsResourceListDisplay) => {
|
||||
const { fetchResources } = useResources();
|
||||
const { fetchResources } = useResources(retryAttempts);
|
||||
const { filterOutDeletedResources } = useCacheStore();
|
||||
const {identifierOperations} = useGlobal()
|
||||
const deletedResources = useCacheStore().deletedResources
|
||||
|
106
src/hooks/usePublish.tsx
Normal file
106
src/hooks/usePublish.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { usePublishStore } from "../state/publishes";
|
||||
import { QortalGetMetadata } from "../types/interfaces/resources";
|
||||
import { base64ToObject, retryTransaction } from "../utils/publish";
|
||||
|
||||
|
||||
export const usePublish = (
|
||||
maxFetchTries: number = 3,
|
||||
returnType: "PUBLIC_JSON" = "PUBLIC_JSON",
|
||||
metadata?: QortalGetMetadata
|
||||
) => {
|
||||
const hasFetched = useRef(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const publish = usePublishStore().getPublish(metadata || null);
|
||||
const setPublish = usePublishStore().setPublish;
|
||||
const [hasResource, setHasResource] = useState<boolean | null>(null)
|
||||
const fetchRawData = useCallback(async (item: QortalGetMetadata) => {
|
||||
const url = `/arbitrary/${item?.service}/${item?.name}/${item?.identifier}?encoding=base64`;
|
||||
const res = await fetch(url);
|
||||
const data = await res.text();
|
||||
return base64ToObject(data);
|
||||
}, []);
|
||||
|
||||
const fetchPublish = useCallback(
|
||||
async (metadataProp: QortalGetMetadata, returnTypeProp: "PUBLIC_JSON" = "PUBLIC_JSON") => {
|
||||
let resourceExists = null;
|
||||
let resource = null;
|
||||
let error = null;
|
||||
try {
|
||||
if (metadata) {
|
||||
setIsLoading(true);
|
||||
}
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=${metadataProp?.service}&limit=1&includemetadata=true&reverse=true&excludeblocked=true&name=${metadataProp?.name}&exactmatchnames=true&offset=0&identifier=${metadataProp?.identifier}`;
|
||||
const responseMetadata = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!responseMetadata?.ok) return false;
|
||||
const resMetadata = await responseMetadata.json();
|
||||
if (resMetadata?.length === 0) {
|
||||
resourceExists = false;
|
||||
setHasResource(false)
|
||||
} else {
|
||||
resourceExists = true
|
||||
setHasResource(true)
|
||||
const response = await retryTransaction(
|
||||
fetchRawData,
|
||||
[metadataProp],
|
||||
true,
|
||||
maxFetchTries
|
||||
);
|
||||
const fullData = {
|
||||
qortalMetadata: resMetadata[0],
|
||||
data: response,
|
||||
};
|
||||
if (metadata) {
|
||||
setPublish(resMetadata[0], fullData);
|
||||
}
|
||||
resource = {
|
||||
qortalMetadata: resMetadata[0],
|
||||
data: response,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
setError(error?.message);
|
||||
if (!metadata) {
|
||||
error = error?.message;
|
||||
}
|
||||
} finally {
|
||||
if (metadata) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
return {
|
||||
resourceExists,
|
||||
resource,
|
||||
error,
|
||||
};
|
||||
},
|
||||
[metadata]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasFetched.current) return;
|
||||
if (metadata?.identifier && metadata?.name && metadata?.service) {
|
||||
hasFetched.current = true;
|
||||
fetchPublish(metadata, returnType);
|
||||
}
|
||||
}, [metadata, returnType]);
|
||||
|
||||
if (!metadata)
|
||||
return {
|
||||
fetchPublish,
|
||||
};
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
resource: publish || null,
|
||||
hasResource,
|
||||
refetch: fetchPublish,
|
||||
fetchPublish,
|
||||
};
|
||||
};
|
@ -6,17 +6,18 @@ import {
|
||||
import { ListItem, useCacheStore } from "../state/cache";
|
||||
import { RequestQueueWithPromise } from "../utils/queue";
|
||||
import { base64ToUint8Array, uint8ArrayToObject } from "../utils/base64";
|
||||
import { retryTransaction } from "../utils/publish";
|
||||
|
||||
export const requestQueueProductPublishes = new RequestQueueWithPromise(20);
|
||||
export const requestQueueProductPublishesBackup = new RequestQueueWithPromise(
|
||||
5
|
||||
10
|
||||
);
|
||||
|
||||
interface TemporaryResource {
|
||||
export interface TemporaryResource {
|
||||
qortalMetadata: QortalMetadata;
|
||||
data: any;
|
||||
}
|
||||
export const useResources = () => {
|
||||
export const useResources = (retryAttempts: number = 2) => {
|
||||
const {
|
||||
setSearchCache,
|
||||
getSearchCache,
|
||||
@ -120,18 +121,26 @@ export const useResources = () => {
|
||||
await new Promise((res) => {
|
||||
setTimeout(() => {
|
||||
res(null);
|
||||
}, 15000);
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
try {
|
||||
res = await requestQueueProductPublishesBackup.enqueue(
|
||||
(): Promise<string> => {
|
||||
return getArbitraryResource(
|
||||
`/arbitrary/${item?.service}/${item?.name}/${item?.identifier}?encoding=base64`,
|
||||
key
|
||||
);
|
||||
}
|
||||
);
|
||||
const fetchRetries = async ()=> {
|
||||
return await requestQueueProductPublishesBackup.enqueue(
|
||||
(): Promise<string> => {
|
||||
return getArbitraryResource(
|
||||
`/arbitrary/${item?.service}/${item?.name}/${item?.identifier}?encoding=base64`,
|
||||
key
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
res = await retryTransaction(
|
||||
fetchRetries,
|
||||
[],
|
||||
true,
|
||||
retryAttempts
|
||||
);
|
||||
} catch (error) {
|
||||
setResourceCache(
|
||||
`${item?.service}-${item?.name}-${item?.identifier}`,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import './index.css'
|
||||
export { GlobalProvider, useGlobal } from "./context/GlobalProvider";
|
||||
export {usePublish} from "./hooks/usePublish"
|
||||
export {ResourceListDisplay} from "./components/ResourceList/ResourceListDisplay"
|
35
src/state/publishes.ts
Normal file
35
src/state/publishes.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { create } from "zustand";
|
||||
import { IdentifierBuilder } from "../utils/encryption";
|
||||
import { QortalGetMetadata } from "../types/interfaces/resources";
|
||||
import { TemporaryResource } from "../hooks/useResources";
|
||||
|
||||
|
||||
|
||||
interface PublishState {
|
||||
publishes: Record<string, TemporaryResource> ;
|
||||
|
||||
getPublish: (qortalGetMetadata: QortalGetMetadata | null) => TemporaryResource | null;
|
||||
setPublish: (qortalGetMetadata: QortalGetMetadata, data: TemporaryResource) => void;
|
||||
}
|
||||
|
||||
// ✅ Typed Zustand Store
|
||||
export const usePublishStore = create<PublishState>((set, get) => ({
|
||||
publishes: {},
|
||||
getPublish: (qortalGetMetadata) => {
|
||||
if(qortalGetMetadata === null) return null
|
||||
const cache = get().publishes[`${qortalGetMetadata.service}-${qortalGetMetadata.name}-${qortalGetMetadata.identifier}`];
|
||||
if (cache) {
|
||||
return cache
|
||||
}
|
||||
return null;
|
||||
},
|
||||
setPublish: (qortalGetMetadata, data) =>
|
||||
set((state) => {
|
||||
return {
|
||||
publishes: {
|
||||
...state.publishes,
|
||||
[`${qortalGetMetadata.service}-${qortalGetMetadata.name}-${qortalGetMetadata.identifier}`]: data,
|
||||
},
|
||||
};
|
||||
}),
|
||||
}));
|
@ -70,6 +70,12 @@ export interface QortalMetadata {
|
||||
updated?: number
|
||||
}
|
||||
|
||||
export interface QortalGetMetadata {
|
||||
name: string
|
||||
identifier: string
|
||||
service: Service
|
||||
}
|
||||
|
||||
export interface QortalSearchParams {
|
||||
identifier: string;
|
||||
service: Service;
|
||||
|
59
src/utils/publish.ts
Normal file
59
src/utils/publish.ts
Normal file
@ -0,0 +1,59 @@
|
||||
const MAX_RETRIES = 3; // Define your max retries constant
|
||||
|
||||
export async function retryTransaction<T>(
|
||||
fn: (...args: any[]) => Promise<T>, // Function that returns a promise
|
||||
args: any[], // Arguments for the function
|
||||
throwError: boolean,
|
||||
retries: number = MAX_RETRIES
|
||||
): Promise<T | null> {
|
||||
let attempt = 0;
|
||||
|
||||
while (attempt < retries) {
|
||||
try {
|
||||
return await fn(...args); // Attempt to execute the function
|
||||
} catch (error: any) {
|
||||
console.error(`Attempt ${attempt + 1} failed: ${error.message}`);
|
||||
attempt++;
|
||||
|
||||
if (attempt === retries) {
|
||||
console.error("Max retries reached. Skipping transaction.");
|
||||
if (throwError) {
|
||||
throw new Error(error?.message || "Unable to process transaction");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait before retrying
|
||||
await new Promise((res) => setTimeout(res, 10000));
|
||||
}
|
||||
}
|
||||
|
||||
return null; // This should never be reached, but added for type safety
|
||||
}
|
||||
|
||||
export function base64ToUint8Array(base64: string) {
|
||||
const binaryString = atob(base64)
|
||||
const len = binaryString.length
|
||||
const bytes = new Uint8Array(len)
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i)
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
export function uint8ArrayToObject(uint8Array: Uint8Array) {
|
||||
// Decode the byte array using TextDecoder
|
||||
const decoder = new TextDecoder()
|
||||
const jsonString = decoder.decode(uint8Array)
|
||||
// Convert the JSON string back into an object
|
||||
return JSON.parse(jsonString)
|
||||
}
|
||||
|
||||
|
||||
export function base64ToObject(base64: string){
|
||||
const toUint = base64ToUint8Array(base64);
|
||||
const toObject = uint8ArrayToObject(toUint);
|
||||
|
||||
return toObject
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user