mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-07-31 14:11:46 +00:00
Rename files and folders (uniform the case)
This commit is contained in:
211
src/messaging/MessageQueueContext.tsx
Normal file
211
src/messaging/MessageQueueContext.tsx
Normal file
@@ -0,0 +1,211 @@
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useCallback,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
|
||||
const MessageQueueContext = createContext(null);
|
||||
const uid = new ShortUniqueId({ length: 8 });
|
||||
|
||||
export const useMessageQueue = () => useContext(MessageQueueContext);
|
||||
|
||||
export const MessageQueueProvider = ({ children }) => {
|
||||
const messageQueueRef = useRef([]);
|
||||
const [queueChats, setQueueChats] = useState({}); // Stores chats and status for display
|
||||
const maxRetries = 2;
|
||||
|
||||
const clearStatesMessageQueueProvider = useCallback(() => {
|
||||
setQueueChats({});
|
||||
messageQueueRef.current = [];
|
||||
}, []);
|
||||
|
||||
// Promise-based lock to prevent concurrent executions
|
||||
const processingPromiseRef = useRef(Promise.resolve());
|
||||
|
||||
// Function to add a message to the queue
|
||||
const addToQueue = useCallback(
|
||||
(sendMessageFunc, messageObj, type, groupDirectId) => {
|
||||
const tempId = uid.rnd();
|
||||
const chatData = {
|
||||
...messageObj,
|
||||
type,
|
||||
groupDirectId,
|
||||
signature: uid.rnd(),
|
||||
identifier: tempId,
|
||||
retries: 0, // Retry count for display purposes
|
||||
status: 'pending', // Initial status is 'pending'
|
||||
};
|
||||
|
||||
// Add chat data to queueChats for status tracking
|
||||
setQueueChats((prev) => ({
|
||||
...prev,
|
||||
[groupDirectId]: [...(prev[groupDirectId] || []), chatData],
|
||||
}));
|
||||
|
||||
// Add the message to the global messageQueueRef
|
||||
messageQueueRef.current.push({
|
||||
func: sendMessageFunc,
|
||||
identifier: tempId,
|
||||
groupDirectId,
|
||||
specialId: messageObj?.message?.specialId,
|
||||
});
|
||||
|
||||
// Start processing the queue
|
||||
processQueue([], groupDirectId);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
// Function to process the message queue
|
||||
const processQueue = useCallback((newMessages = [], groupDirectId) => {
|
||||
processingPromiseRef.current = processingPromiseRef.current
|
||||
.then(() => processQueueInternal(newMessages, groupDirectId))
|
||||
.catch((err) => console.error('Error in processQueue:', err));
|
||||
}, []);
|
||||
|
||||
// Internal function to handle queue processing
|
||||
const processQueueInternal = async (newMessages, groupDirectId) => {
|
||||
// Remove any messages from the queue that match the specialId from newMessages
|
||||
|
||||
// If the queue is empty, no need to process
|
||||
if (messageQueueRef.current.length === 0) return;
|
||||
|
||||
// Process messages sequentially
|
||||
while (messageQueueRef.current.length > 0) {
|
||||
const currentMessage = messageQueueRef.current[0]; // Get the first message in the queue
|
||||
const { groupDirectId, identifier } = currentMessage;
|
||||
|
||||
// Update the chat status to 'sending'
|
||||
setQueueChats((prev) => {
|
||||
const updatedChats = { ...prev };
|
||||
if (updatedChats[groupDirectId]) {
|
||||
const chatIndex = updatedChats[groupDirectId].findIndex(
|
||||
(item) => item.identifier === identifier
|
||||
);
|
||||
if (chatIndex !== -1) {
|
||||
updatedChats[groupDirectId][chatIndex].status = 'sending';
|
||||
}
|
||||
}
|
||||
return updatedChats;
|
||||
});
|
||||
|
||||
try {
|
||||
// Execute the function stored in the messageQueueRef
|
||||
|
||||
await currentMessage.func();
|
||||
|
||||
// Remove the message from the queue after successful sending
|
||||
messageQueueRef.current.shift();
|
||||
} catch (error) {
|
||||
console.error('Message sending failed', error);
|
||||
|
||||
// Retry logic
|
||||
setQueueChats((prev) => {
|
||||
const updatedChats = { ...prev };
|
||||
const chatIndex = updatedChats[groupDirectId]?.findIndex(
|
||||
(item) => item.identifier === identifier
|
||||
);
|
||||
if (chatIndex !== -1) {
|
||||
const retries = updatedChats[groupDirectId][chatIndex].retries;
|
||||
if (retries < maxRetries) {
|
||||
// Increment retry count and set status to 'failed'
|
||||
updatedChats[groupDirectId][chatIndex].retries += 1;
|
||||
updatedChats[groupDirectId][chatIndex].status = 'failed';
|
||||
} else {
|
||||
// Max retries reached, set status to 'failed-permanent'
|
||||
updatedChats[groupDirectId][chatIndex].status =
|
||||
'failed-permanent';
|
||||
|
||||
// Remove the message from the queue after max retries
|
||||
messageQueueRef.current.shift();
|
||||
}
|
||||
}
|
||||
return updatedChats;
|
||||
});
|
||||
}
|
||||
|
||||
// Optional delay between processing messages
|
||||
// await new Promise((res) => setTimeout(res, 5000));
|
||||
}
|
||||
};
|
||||
|
||||
// Method to process with new messages and groupDirectId
|
||||
const processWithNewMessages = (newMessages, groupDirectId) => {
|
||||
let updatedNewMessages = newMessages;
|
||||
if (newMessages.length > 0) {
|
||||
// Remove corresponding entries in queueChats for the provided groupDirectId
|
||||
setQueueChats((prev) => {
|
||||
const updatedChats = { ...prev };
|
||||
if (updatedChats[groupDirectId]) {
|
||||
updatedNewMessages = newMessages?.map((msg) => {
|
||||
const findTempMsg = updatedChats[groupDirectId]?.find(
|
||||
(msg2) => msg2?.message?.specialId === msg?.specialId
|
||||
);
|
||||
if (findTempMsg) {
|
||||
return {
|
||||
...msg,
|
||||
tempSignature: findTempMsg?.signature,
|
||||
};
|
||||
}
|
||||
return msg;
|
||||
});
|
||||
|
||||
updatedChats[groupDirectId] = updatedChats[groupDirectId].filter(
|
||||
(chat) => {
|
||||
return !newMessages.some(
|
||||
(newMsg) => newMsg?.specialId === chat?.message?.specialId
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Remove messages with status 'failed-permanent'
|
||||
updatedChats[groupDirectId] = updatedChats[groupDirectId].filter(
|
||||
(chat) => {
|
||||
return chat?.status !== 'failed-permanent';
|
||||
}
|
||||
);
|
||||
|
||||
// If no more chats for this group, delete the groupDirectId entry
|
||||
if (updatedChats[groupDirectId].length === 0) {
|
||||
delete updatedChats[groupDirectId];
|
||||
}
|
||||
}
|
||||
return updatedChats;
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (
|
||||
!messageQueueRef.current.find(
|
||||
(msg) => msg?.groupDirectId === groupDirectId
|
||||
)
|
||||
) {
|
||||
setQueueChats((prev) => {
|
||||
const updatedChats = { ...prev };
|
||||
if (updatedChats[groupDirectId]) {
|
||||
delete updatedChats[groupDirectId];
|
||||
}
|
||||
|
||||
return updatedChats;
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
|
||||
return updatedNewMessages;
|
||||
};
|
||||
|
||||
return (
|
||||
<MessageQueueContext.Provider
|
||||
value={{
|
||||
addToQueue,
|
||||
queueChats,
|
||||
clearStatesMessageQueueProvider,
|
||||
processWithNewMessages,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</MessageQueueContext.Provider>
|
||||
);
|
||||
};
|
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
// Utility to generate unique request IDs
|
||||
function generateRequestId() {
|
||||
return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
||||
@@ -9,34 +7,55 @@ function generateRequestId() {
|
||||
const callbackMap = new Map();
|
||||
|
||||
// Global listener for handling message responses
|
||||
window.addEventListener("message", (event) => {
|
||||
window.addEventListener('message', (event) => {
|
||||
const { type, requestId, payload, error, message } = event.data;
|
||||
|
||||
// Only process messages of type `backgroundMessageResponse`
|
||||
if (type !== "backgroundMessageResponse") return;
|
||||
if (type !== 'backgroundMessageResponse') return;
|
||||
|
||||
// Check if there’s a callback stored for this requestId
|
||||
if (callbackMap.has(requestId)) {
|
||||
const { resolve, reject } = callbackMap.get(requestId);
|
||||
callbackMap.delete(requestId); // Remove callback after use
|
||||
|
||||
resolve(event.data)
|
||||
resolve(event.data);
|
||||
}
|
||||
});
|
||||
|
||||
export const sendMessageBackground = (action, data = {}, timeout = 240000, isExtension, appInfo, skipAuth) => {
|
||||
export const sendMessageBackground = (
|
||||
action,
|
||||
data = {},
|
||||
timeout = 240000,
|
||||
isExtension,
|
||||
appInfo,
|
||||
skipAuth
|
||||
) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestId = generateRequestId(); // Unique ID for each request
|
||||
callbackMap.set(requestId, { resolve, reject }); // Store both resolve and reject callbacks
|
||||
const targetOrigin = window.location.origin
|
||||
const targetOrigin = window.location.origin;
|
||||
// Send the message with `backgroundMessage` type
|
||||
window.postMessage({ type: "backgroundMessage", action, requestId, payload: data, isExtension, appInfo, skipAuth }, targetOrigin);
|
||||
window.postMessage(
|
||||
{
|
||||
type: 'backgroundMessage',
|
||||
action,
|
||||
requestId,
|
||||
payload: data,
|
||||
isExtension,
|
||||
appInfo,
|
||||
skipAuth,
|
||||
},
|
||||
targetOrigin
|
||||
);
|
||||
|
||||
// Set up a timeout to automatically reject if no response is received
|
||||
const timeoutId = setTimeout(() => {
|
||||
// Remove the callback to prevent memory leaks
|
||||
callbackMap.delete(requestId);
|
||||
reject({ error: "timeout", message: `Request timed out after ${timeout} ms` });
|
||||
reject({
|
||||
error: 'timeout',
|
||||
message: `Request timed out after ${timeout} ms`,
|
||||
});
|
||||
}, timeout);
|
||||
|
||||
// Adjust resolve/reject to clear the timeout when a response arrives
|
||||
@@ -48,14 +67,17 @@ export const sendMessageBackground = (action, data = {}, timeout = 240000, isExt
|
||||
reject: (error) => {
|
||||
clearTimeout(timeoutId); // Clear the timeout if an error occurs
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}).then((response) => {
|
||||
// Return payload or error based on response content
|
||||
if (response?.payload !== null && response?.payload !== undefined) {
|
||||
return response.payload;
|
||||
} else if (response?.error) {
|
||||
return { error: response.error, message: response?.message || "An error occurred" };
|
||||
return {
|
||||
error: response.error,
|
||||
message: response?.message || 'An error occurred',
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
Reference in New Issue
Block a user