fixes to publish and status

This commit is contained in:
PhilReact 2025-06-21 06:21:07 +03:00
parent 9e5c39fede
commit 07620054ca
7 changed files with 191 additions and 46 deletions

View File

@ -826,6 +826,11 @@ function App() {
executeEvent("openThreadNewPost", { executeEvent("openThreadNewPost", {
data: message.payload.data, data: message.payload.data,
}); });
} else if (
message.action === "receiveChunks" &&
isMainWindow
) {
executeEvent('receiveChunks', message.payload?.data);
} }
// Call the permission request handler for "QORTAL_REQUEST_PERMISSION" // Call the permission request handler for "QORTAL_REQUEST_PERMISSION"

View File

@ -102,12 +102,15 @@ export const AppViewer = React.forwardRef(({ app , hide, isDevMode, skipAuth}, i
const receiveChunksFunc = useCallback( const receiveChunksFunc = useCallback(
(e) => { (e) => {
console.log('eee', e)
const iframe = iframeRef?.current; const iframe = iframeRef?.current;
if (!iframe || !iframe?.src) return; if (!iframe || !iframe?.src) return;
if (app?.tabId !== e.detail?.tabId) return; if (app?.tabId !== e.detail?.tabId) return;
const publishLocation = e.detail?.publishLocation; const publishLocation = e.detail?.publishLocation;
const chunksSubmitted = e.detail?.chunksSubmitted; const chunksSubmitted = e.detail?.chunksSubmitted;
const totalChunks = e.detail?.totalChunks; const totalChunks = e.detail?.totalChunks;
const retry = e.detail?.retry;
const filename = e.detail?.filename;
try { try {
if (publishLocation === undefined || publishLocation === null) return; if (publishLocation === undefined || publishLocation === null) return;
const dataToBeSent = {}; const dataToBeSent = {};
@ -117,8 +120,15 @@ export const AppViewer = React.forwardRef(({ app , hide, isDevMode, skipAuth}, i
if (totalChunks !== undefined && totalChunks !== null) { if (totalChunks !== undefined && totalChunks !== null) {
dataToBeSent.totalChunks = totalChunks; dataToBeSent.totalChunks = totalChunks;
} }
const targetOrigin = new URL(iframe.src).origin; if (retry !== undefined && retry !== null) {
iframe.contentWindow?.postMessage( dataToBeSent.retry = retry;
}
if (filename !== undefined && filename !== null) {
dataToBeSent.filename = filename;
}
const targetOrigin = iframeRef.current ? new URL(iframeRef.current.src).origin : "*";
console.log('targetOrigin', targetOrigin)
iframeRef.current?.contentWindow?.postMessage(
{ {
action: 'PUBLISH_STATUS', action: 'PUBLISH_STATUS',
publishLocation, publishLocation,
@ -128,6 +138,7 @@ export const AppViewer = React.forwardRef(({ app , hide, isDevMode, skipAuth}, i
}, },
targetOrigin targetOrigin
); );
} catch (err) { } catch (err) {
console.error('Failed to send status to iframe:', err); console.error('Failed to send status to iframe:', err);
} }

View File

@ -6,6 +6,7 @@ import { navigationControllerAtom } from '../../atoms/global';
import { extractComponents } from '../Chat/MessageDisplay'; import { extractComponents } from '../Chat/MessageDisplay';
import { isRunningGateway } from '../../qortalRequests'; import { isRunningGateway } from '../../qortalRequests';
import { MAX_SIZE_PUBLIC_NODE, MAX_SIZE_PUBLISH } from '../../constants/constants'; import { MAX_SIZE_PUBLIC_NODE, MAX_SIZE_PUBLISH } from '../../constants/constants';
import { createEndpoint } from '../../background';
@ -303,14 +304,26 @@ async function handleGetFileFromIndexedDB(fileId, sendResponse) {
} }
} }
async function handleSendDataChunksToCore(fileId, chunkUrl, sendResponse){ async function handleSendDataChunksToCore(fileId, chunkUrl, sendResponse, appInfo, resourceInfo){
try { try {
if(!fileReferences[fileId]) throw new Error('No file reference found') if(!fileReferences[fileId]) throw new Error('No file reference found')
const chunkSize = 5 * 1024 * 1024; // 5MB const chunkSize = 5 * 1024 * 1024; // 5MB
const file = fileReferences[fileId] const file = fileReferences[fileId]
const totalChunks = Math.ceil(file.size / chunkSize); const totalChunks = Math.ceil(file.size / chunkSize);
executeEvent('receiveChunks', {
tabId: appInfo.tabId,
publishLocation: {
name: resourceInfo?.name,
identifier: resourceInfo?.identifier,
service: resourceInfo?.service,
},
chunksSubmitted: 0,
totalChunks,
processed: false,
filename:
resourceInfo?.filename
})
for (let index = 0; index < totalChunks; index++) { for (let index = 0; index < totalChunks; index++) {
const start = index * chunkSize; const start = index * chunkSize;
const end = Math.min(start + chunkSize, file.size); const end = Math.min(start + chunkSize, file.size);
@ -321,6 +334,16 @@ async function handleGetFileFromIndexedDB(fileId, sendResponse) {
formData.append('index', index); formData.append('index', index);
await uploadChunkWithRetry(chunkUrl, formData, index); await uploadChunkWithRetry(chunkUrl, formData, index);
executeEvent('receiveChunks', {
tabId: appInfo.tabId,
publishLocation: {
name: resourceInfo?.name,
identifier: resourceInfo?.identifier,
service: resourceInfo?.service,
},
chunksSubmitted: index + 1,
totalChunks,
})
} }
sendResponse({ result: true }); sendResponse({ result: true });
} catch (error) { } catch (error) {
@ -678,7 +701,9 @@ isDOMContentLoaded: false
} }
if (data) { if (data) {
sendMessageToRuntime( sendMessageToRuntime(
{ action: event.data.action, type: 'qortalRequest', payload: data, isExtension: true }, { action: event.data.action, type: 'qortalRequest', payload: data, isExtension: true, appInfo: {
name: appName, service: appService, tabId
} },
event.ports[0] event.ports[0]
); );
} else { } else {
@ -709,7 +734,9 @@ isDOMContentLoaded: false
} }
if (data) { if (data) {
sendMessageToRuntime( sendMessageToRuntime(
{ action: event.data.action, type: 'qortalRequest', payload: data, isExtension: true }, { action: event.data.action, type: 'qortalRequest', payload: data, isExtension: true, appInfo: {
name: appName, service: appService, tabId
} },
event.ports[0] event.ports[0]
); );
} else { } else {
@ -761,6 +788,22 @@ isDOMContentLoaded: false
); );
} }
} }
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 hasOversizedFile = resources.some((resource) => { const hasOversizedFile = resources.some((resource) => {
const file = resource?.file; const file = resource?.file;
@ -793,7 +836,9 @@ isDOMContentLoaded: false
} }
sendMessageToRuntime( sendMessageToRuntime(
{ action: event.data.action, type: 'qortalRequest', payload: data, isExtension: true }, { action: event.data.action, type: 'qortalRequest', payload: data, isExtension: true , appInfo: {
name: appName, service: appService, tabId
}},
event.ports[0] event.ports[0]
); );
} else if(event?.data?.action === 'LINK_TO_QDN_RESOURCE' || } else if(event?.data?.action === 'LINK_TO_QDN_RESOURCE' ||
@ -917,7 +962,8 @@ isDOMContentLoaded: false
handleGetFileFromIndexedDB(message.fileId, sendResponse); handleGetFileFromIndexedDB(message.fileId, sendResponse);
return true; // Keep channel open for async return true; // Keep channel open for async
} else if (message.action === 'sendDataChunksToCore') { } else if (message.action === 'sendDataChunksToCore') {
handleSendDataChunksToCore(message.fileId, message.chunkUrl, sendResponse); console.log('message', message)
handleSendDataChunksToCore(message.fileId, message.chunkUrl, sendResponse, message?.appInfo, message?.resourceInfo);
return true; // Keep channel open for async return true; // Keep channel open for async
} else if (message.action === 'getFileBase64') { } else if (message.action === 'getFileBase64') {
handleGetFileBase64(message.fileId, sendResponse); handleGetFileBase64(message.fileId, sendResponse);

View File

@ -702,7 +702,7 @@ const sendMessage = async ()=> {
} }
); );
}); });
if (res !== true) throw new Error('Unable to publish images'); if (res?.error) throw new Error('Unable to publish images');
} }
const images = const images =

View File

@ -26,6 +26,10 @@ async function reusablePost(endpoint, _body) {
}, },
body: _body, body: _body,
}); });
if (!response.ok) {
const errorText = await response.text();
throw new Error(errorText);
}
let data; let data;
try { try {
data = await response.clone().json(); data = await response.clone().json();
@ -73,7 +77,48 @@ async function uploadChunkWithRetry(endpoint, formData, index, maxRetries = 3) {
} }
} }
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) {
chrome.runtime.sendMessage({
action: "receiveChunks",
payload: { data: {
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));
}
}
}
export const publishData = async ({ export const publishData = async ({
registeredName, registeredName,
@ -100,7 +145,13 @@ export const publishData = async ({
}; };
const convertBytesForSigning = async (transactionBytesBase58: string) => { 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 () => { const getArbitraryFee = async () => {
@ -157,9 +208,12 @@ export const publishData = async ({
}; };
const processTransactionVersion2 = async (bytes) => { const processTransactionVersion2 = async (bytes) => {
return await reusablePost( return await resuablePostRetry(
'/transactions/process?apiVersion=2', '/transactions/process?apiVersion=2',
Base58.encode(bytes) Base58.encode(bytes),
3,
appInfo,
{ identifier, name: registeredName, service }
); );
}; };
@ -196,15 +250,19 @@ export const publishData = async ({
myResponse = response; myResponse = response;
} }
if (appInfo?.tabId) { if (appInfo?.tabId) {
executeEvent('receiveChunks', {
tabId: appInfo.tabId, chrome.runtime.sendMessage({
action: "receiveChunks",
payload: { data: {
tabId: appInfo.tabId,
publishLocation: { publishLocation: {
name: registeredName, name: registeredName,
identifier, identifier,
service, service,
}, },
processed: true, processed: true,
}); } },
});
} }
return myResponse; return myResponse;
}; };
@ -319,8 +377,11 @@ export const publishData = async ({
} }
uploadDataUrl = uploadDataUrl + paramQueries; uploadDataUrl = uploadDataUrl + paramQueries;
if (appInfo?.tabId) { if (appInfo?.tabId) {
executeEvent('receiveChunks', {
tabId: appInfo.tabId, chrome.runtime.sendMessage({
action: "receiveChunks",
payload: { data: {
tabId: appInfo.tabId,
publishLocation: { publishLocation: {
name: registeredName, name: registeredName,
identifier, identifier,
@ -329,9 +390,14 @@ export const publishData = async ({
chunksSubmitted: 1, chunksSubmitted: 1,
totalChunks: 1, totalChunks: 1,
processed: false, processed: false,
}); } },
});
} }
return await reusablePost(uploadDataUrl, postBody); return await resuablePostRetry(uploadDataUrl, postBody, 3, appInfo, {
identifier,
name: registeredName,
service,
});
} }
const file = data; const file = data;
@ -346,15 +412,23 @@ export const publishData = async ({
const chunkUrl = uploadDataUrl + `/chunk`; const chunkUrl = uploadDataUrl + `/chunk`;
const createdChunkUrl = await createEndpoint(chunkUrl) const createdChunkUrl = await createEndpoint(chunkUrl)
if(sender){ if(sender){
await sendDataChunksToCore(file, createdChunkUrl, sender) await sendDataChunksToCore(file, createdChunkUrl, sender, appInfo, {
name: registeredName,
identifier,
service,
filename: file?.name || filename || title || `${service}-${identifier || ''}`
})
} else { } else {
const chunkSize = 5 * 1024 * 1024; // 5MB const chunkSize = 5 * 1024 * 1024; // 5MB
const totalChunks = Math.ceil(file.size / chunkSize); const totalChunks = Math.ceil(file.size / chunkSize);
if (appInfo?.tabId) { if (appInfo?.tabId) {
executeEvent('receiveChunks', {
tabId: appInfo.tabId, chrome.runtime.sendMessage({
action: "receiveChunks",
payload: { data: {
tabId: appInfo.tabId,
publishLocation: { publishLocation: {
name: registeredName, name: registeredName,
identifier, identifier,
@ -363,7 +437,10 @@ export const publishData = async ({
chunksSubmitted: 0, chunksSubmitted: 0,
totalChunks, totalChunks,
processed: false, processed: false,
}); filename:
file?.name || filename || title || `${service}-${identifier || ''}`,
} },
});
} }
for (let index = 0; index < totalChunks; index++) { for (let index = 0; index < totalChunks; index++) {
const start = index * chunkSize; const start = index * chunkSize;
@ -375,8 +452,11 @@ export const publishData = async ({
await uploadChunkWithRetry(chunkUrl, formData, index); await uploadChunkWithRetry(chunkUrl, formData, index);
if (appInfo?.tabId) { if (appInfo?.tabId) {
executeEvent('receiveChunks', {
tabId: appInfo.tabId, chrome.runtime.sendMessage({
action: "receiveChunks",
payload: { data: {
tabId: appInfo.tabId,
publishLocation: { publishLocation: {
name: registeredName, name: registeredName,
identifier, identifier,
@ -384,7 +464,8 @@ export const publishData = async ({
}, },
chunksSubmitted: index + 1, chunksSubmitted: index + 1,
totalChunks, totalChunks,
}); } },
});
} }
} }
} }
@ -398,7 +479,7 @@ export const publishData = async ({
headers: {}, headers: {},
}); });
if (!response.ok) { if (!response?.ok) {
const errorText = await response.text(); const errorText = await response.text();
throw new Error(`Finalize failed: ${errorText}`); throw new Error(`Finalize failed: ${errorText}`);
} }

View File

@ -947,7 +947,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
case "GET_PRIMARY_NAME": { case "GET_PRIMARY_NAME": {
const data = request.payload; const data = request.payload;
getNameInfoForOthers(data) getNameInfoForOthers(data?.address)
.then((res) => { .then((res) => {
const resData = res ? res : ""; const resData = res ? res : "";
sendResponse(resData); sendResponse(resData);

View File

@ -425,11 +425,11 @@ function getFileFromContentScript(fileId, sender) {
}); });
} }
export function sendDataChunksToCore(fileId, chunkUrl, sender) { export function sendDataChunksToCore(fileId, chunkUrl, sender, appInfo, resourceInfo) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
chrome.tabs.sendMessage( chrome.tabs.sendMessage(
sender.tab.id, sender.tab.id,
{ action: "sendDataChunksToCore", fileId: fileId, chunkUrl }, { action: "sendDataChunksToCore", fileId: fileId, chunkUrl, appInfo, resourceInfo },
(response) => { (response) => {
if (response && response.result) { if (response && response.result) {
resolve(response.result); resolve(response.result);
@ -1220,6 +1220,7 @@ export const publishMultipleQDNResources = async (data: any, sender, isFromExten
throw new Error("User declined request"); throw new Error("User declined request");
} }
let failedPublishesIdentifiers = []; let failedPublishesIdentifiers = [];
const publishedResponses = [];
for (const resource of resources) { for (const resource of resources) {
try { try {
const requiredFields = ["service"]; const requiredFields = ["service"];
@ -1322,28 +1323,29 @@ export const publishMultipleQDNResources = async (data: any, sender, isFromExten
(resource?.base64 || resource?.data64 || resourceEncrypt) (resource?.base64 || resource?.data64 || resourceEncrypt)
? 'base64' ? 'base64'
: 'file'; : 'file';
await retryTransaction(publishData, [ const response = await publishData({
{ apiVersion: 2,
registeredName: encodeURIComponent(name),
data: rawData,
service: service,
identifier: encodeURIComponent(identifier),
uploadType: dataType,
filename: filename,
title,
description,
category, category,
data: rawData,
description,
filename: filename,
identifier: encodeURIComponent(identifier),
registeredName: encodeURIComponent(resource?.name || name),
service: service,
tag1, tag1,
tag2, tag2,
tag3, tag3,
tag4, tag4,
tag5, tag5,
apiVersion: 2, title,
withFee: true,
sender, sender,
appInfo uploadType: dataType,
}, withFee: true,
], true); appInfo,
});
if (response?.signature) {
publishedResponses.push(response);
}
await new Promise((res) => { await new Promise((res) => {
setTimeout(() => { setTimeout(() => {
res(); res();
@ -1382,7 +1384,7 @@ export const publishMultipleQDNResources = async (data: any, sender, isFromExten
receiver: appFeeRecipient receiver: appFeeRecipient
}, true) }, true)
} }
return true; return publishedResponses;
}; };
export const voteOnPoll = async (data, isFromExtension) => { export const voteOnPoll = async (data, isFromExtension) => {