From df8a167c11a9698534dde2c2b023cc2a7722324b Mon Sep 17 00:00:00 2001 From: PhilReact Date: Fri, 20 Jun 2025 21:10:09 +0300 Subject: [PATCH] fixes --- src/components/Apps/AppViewer.tsx | 8 ++++ src/components/Chat/ChatGroup.tsx | 2 +- src/qdn/publish/publish.ts | 72 ++++++++++++++++++++++++++++--- src/qortal/get.ts | 69 +++++++++++++++++------------ 4 files changed, 116 insertions(+), 35 deletions(-) diff --git a/src/components/Apps/AppViewer.tsx b/src/components/Apps/AppViewer.tsx index 24350bf..5ec416d 100644 --- a/src/components/Apps/AppViewer.tsx +++ b/src/components/Apps/AppViewer.tsx @@ -165,6 +165,8 @@ export const AppViewer = forwardRef( const publishLocation = e.detail?.publishLocation; const chunksSubmitted = e.detail?.chunksSubmitted; const totalChunks = e.detail?.totalChunks; + const retry = e.detail?.retry; + const filename = e.detail?.filename; try { if (publishLocation === undefined || publishLocation === null) return; const dataToBeSent = {}; @@ -174,6 +176,12 @@ export const AppViewer = forwardRef( if (totalChunks !== undefined && totalChunks !== null) { dataToBeSent.totalChunks = totalChunks; } + if (retry !== undefined && retry !== null) { + dataToBeSent.retry = retry; + } + if (filename !== undefined && filename !== null) { + dataToBeSent.filename = filename; + } const targetOrigin = new URL(iframe.src).origin; iframe.contentWindow?.postMessage( { diff --git a/src/components/Chat/ChatGroup.tsx b/src/components/Chat/ChatGroup.tsx index a0efe00..762f281 100644 --- a/src/components/Chat/ChatGroup.tsx +++ b/src/components/Chat/ChatGroup.tsx @@ -903,7 +903,7 @@ export const ChatGroup = ({ 240000, true ); - if (res !== true) + if (res?.error) throw new Error( t('core:message.error.publish_image', { postProcess: 'capitalizeFirstChar', diff --git a/src/qdn/publish/publish.ts b/src/qdn/publish/publish.ts index 41deab2..82f3dc1 100644 --- a/src/qdn/publish/publish.ts +++ b/src/qdn/publish/publish.ts @@ -26,6 +26,10 @@ async function reusablePost(endpoint, _body) { }, body: _body, }); + if (!response.ok) { + const errorText = await response.text(); + throw new Error(errorText); + } let data; try { data = await response.clone().json(); @@ -68,7 +72,46 @@ async function uploadChunkWithRetry(endpoint, formData, index, maxRetries = 3) { throw new Error(`Chunk ${index} failed after ${maxRetries} attempts`); } // Wait 10 seconds before next retry - await new Promise((res) => setTimeout(res, 10_000)); + await new Promise((res) => setTimeout(res, 25_000)); + } + } +} + +async function resuablePostRetry( + endpoint, + body, + maxRetries = 3, + appInfo, + resourceInfo +) { + let attempt = 0; + while (attempt < maxRetries) { + try { + const response = await reusablePost(endpoint, body); + + return response; + } catch (err) { + attempt++; + if (attempt >= maxRetries) { + throw new Error( + err instanceof Error + ? err?.message || `Failed to make request` + : `Failed to make request` + ); + } + if (appInfo?.tabId && resourceInfo) { + executeEvent('receiveChunks', { + tabId: appInfo.tabId, + publishLocation: { + name: resourceInfo?.name, + identifier: resourceInfo?.identifier, + service: resourceInfo?.service, + }, + retry: true, + }); + } + // Wait 10 seconds before next retry + await new Promise((res) => setTimeout(res, 25_000)); } } } @@ -106,7 +149,13 @@ export const publishData = async ({ }; const convertBytesForSigning = async (transactionBytesBase58: string) => { - return await reusablePost('/transactions/convert', transactionBytesBase58); + return await resuablePostRetry( + '/transactions/convert', + transactionBytesBase58, + 3, + appInfo, + { identifier, name: registeredName, service } + ); }; const getArbitraryFee = async () => { @@ -163,9 +212,12 @@ export const publishData = async ({ }; const processTransactionVersion2 = async (bytes) => { - return await reusablePost( + return await resuablePostRetry( '/transactions/process?apiVersion=2', - Base58.encode(bytes) + Base58.encode(bytes), + 3, + appInfo, + { identifier, name: registeredName, service } ); }; @@ -226,7 +278,6 @@ export const publishData = async ({ } let transactionBytes = await uploadData(registeredName, data, fee); - if (!transactionBytes || transactionBytes.error) { throw new Error(transactionBytes?.message || 'Error when uploading'); } else if (transactionBytes.includes('Error 500 Internal Server Error')) { @@ -336,9 +387,14 @@ export const publishData = async ({ chunksSubmitted: 1, totalChunks: 1, processed: false, + filename: filename || title || `${service}-${identifier || ''}`, }); } - return await reusablePost(uploadDataUrl, postBody); + return await resuablePostRetry(uploadDataUrl, postBody, 3, appInfo, { + identifier, + name: registeredName, + service, + }); } const file = data; @@ -365,6 +421,8 @@ export const publishData = async ({ chunksSubmitted: 0, totalChunks, processed: false, + filename: + file?.name || filename || title || `${service}-${identifier || ''}`, }); } for (let index = 0; index < totalChunks; index++) { @@ -399,7 +457,7 @@ export const publishData = async ({ headers: {}, }); - if (!response.ok) { + if (!response?.ok) { const errorText = await response.text(); throw new Error(`Finalize failed: ${errorText}`); } diff --git a/src/qortal/get.ts b/src/qortal/get.ts index efc81fe..fe26d7e 100644 --- a/src/qortal/get.ts +++ b/src/qortal/get.ts @@ -1600,6 +1600,23 @@ export const publishMultipleQDNResources = async ( ); } + const totalFileSize = resources.reduce((acc, resource) => { + const file = resource?.file; + if (file && file?.size && !isNaN(file?.size)) { + return acc + file.size; + } + return acc; + }, 0); + if (totalFileSize > 0) { + const urlCheck = `/arbitrary/check/tmp?totalSize=${totalFileSize}`; + + const checkEndpoint = await createEndpoint(urlCheck); + const checkRes = await fetch(checkEndpoint); + if (!checkRes.ok) { + throw new Error('Not enough space on your hard drive'); + } + } + const encrypt = data?.encrypt; for (const resource of resources) { @@ -1746,7 +1763,7 @@ export const publishMultipleQDNResources = async ( }; const failedPublishesIdentifiers: FailedPublish[] = []; - + const publishedResponses = []; for (const resource of resources) { try { const requiredFields = ['service']; @@ -1861,31 +1878,29 @@ export const publishMultipleQDNResources = async ( resource?.base64 || resource?.data64 || resourceEncrypt ? 'base64' : 'file'; - await retryTransaction( - publishData, - [ - { - apiVersion: 2, - category, - data: rawData, - description, - filename: filename, - identifier: encodeURIComponent(identifier), - registeredName: encodeURIComponent(resource?.name || name), - service: service, - tag1, - tag2, - tag3, - tag4, - tag5, - title, - uploadType: dataType, - withFee: true, - appInfo, - }, - ], - true - ); + + const response = await publishData({ + apiVersion: 2, + category, + data: rawData, + description, + filename: filename, + identifier: encodeURIComponent(identifier), + registeredName: encodeURIComponent(resource?.name || name), + service: service, + tag1, + tag2, + tag3, + tag4, + tag5, + title, + uploadType: dataType, + withFee: true, + appInfo, + }); + if (response?.signature) { + publishedResponses.push(response); + } await new Promise((res) => { setTimeout(() => { res(); @@ -1937,7 +1952,7 @@ export const publishMultipleQDNResources = async ( true ); } - return true; + return publishedResponses; }; export const voteOnPoll = async (data, isFromExtension) => {