Rename files and folders (uniform the case)

This commit is contained in:
Nicola Benaglia
2025-05-24 12:19:11 +02:00
parent 75dada87cb
commit cb86a9b89d
10 changed files with 40 additions and 18 deletions

View 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>
);
};

View File

@@ -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 theres 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',
};
}
});
};