Massive performance improvments my more accurately leveraging async, and searchSimple. Resolved issue of cards on AdminBoard not displaying properly. version 0.63beta.

This commit is contained in:
2024-12-27 23:04:16 -08:00
parent cd033bc756
commit f1d27a70f9
5 changed files with 658 additions and 613 deletions

View File

@@ -173,9 +173,10 @@ const extractCardsMinterName = (cardIdentifier) => {
if (parts.length < 3) {
throw new Error('Invalid identifier format');
}
if (parts.slice(2, -1).join('-') === 'TOPIC') {
console.log(`TOPIC found in identifier: ${cardIdentifier} - not including in duplicatesList`)
return
return 'topic'
}
// Extract minterName (everything from the second part to the second-to-last part)
const minterName = parts.slice(2, -1).join('-');
@@ -186,73 +187,39 @@ const extractCardsMinterName = (cardIdentifier) => {
const processCards = async (validEncryptedCards) => {
const latestCardsMap = new Map()
// Step 1: Filter and keep the most recent card per identifier
validEncryptedCards.forEach(card => {
// Step 1: Process all cards in parallel
await Promise.all(validEncryptedCards.map(async card => {
const timestamp = card.updated || card.created || 0
const existingCard = latestCardsMap.get(card.identifier)
if (!existingCard || timestamp > (existingCard.updated || existingCard.created || 0)) {
latestCardsMap.set(card.identifier, card)
}
})
}))
console.log(`latestCardsMap, by timestamp`, latestCardsMap)
// Step 2: Extract unique cards
const uniqueValidCards = Array.from(latestCardsMap.values())
// Step 3: Group by minterName and select the most recent card per minterName
const minterNameMap = new Map()
for (const card of validEncryptedCards) {
const minterName = await extractCardsMinterName(card.identifier)
const existingCard = minterNameMap.get(minterName)
const cardTimestamp = card.updated || card.created || 0
const existingTimestamp = existingCard?.updated || existingCard?.created || 0
if (!existingCardMinterNames.includes(minterName)) {
existingCardMinterNames.push(minterName)
console.log(`cardsMinterName: ${minterName} - added to list`)
}
// Keep only the most recent card for each minterName
if (!existingCard || cardTimestamp > existingTimestamp) {
minterNameMap.set(minterName, card)
}
}
// Step 4: Filter cards to ensure each minterName is included only once
const finalCards = []
const seenMinterNames = new Set()
for (const [minterName, card] of minterNameMap.entries()) {
if (!seenMinterNames.has(minterName)) {
finalCards.push(card)
seenMinterNames.add(minterName) // Mark the minterName as seen
}
}
// Step 5: Sort by the most recent timestamp
finalCards.sort((a, b) => {
const timestampA = a.updated || a.created || 0
const timestampB = b.updated || b.created || 0
return timestampB - timestampA
})
return finalCards
return uniqueValidCards
}
//Main function to load the Minter Cards ----------------------------------------
const fetchAllEncryptedCards = async () => {
const encryptedCardsContainer = document.getElementById("encrypted-cards-container");
encryptedCardsContainer.innerHTML = "<p>Loading cards...</p>";
try {
const response = await qortalRequest({
action: "SEARCH_QDN_RESOURCES",
service: "MAIL_PRIVATE",
query: encryptedCardIdentifierPrefix,
mode: "ALL"
});
// const response = await qortalRequest({
// action: "SEARCH_QDN_RESOURCES",
// service: "MAIL_PRIVATE",
// query: encryptedCardIdentifierPrefix,
// mode: "ALL"
// })
const response = await searchSimple('MAIL_PRIVATE', `${encryptedCardIdentifierPrefix}`, '', 0)
if (!response || !Array.isArray(response) || response.length === 0) {
encryptedCardsContainer.innerHTML = "<p>No cards found.</p>";
@@ -262,19 +229,21 @@ const fetchAllEncryptedCards = async () => {
// Validate cards and filter
const validatedEncryptedCards = await Promise.all(
response.map(async card => {
const isValid = await validateEncryptedCardIdentifier(card);
return isValid ? card : null;
const isValid = await validateEncryptedCardIdentifier(card)
return isValid ? card : null
})
);
)
console.log(`validatedEncryptedCards:`, validatedEncryptedCards, `... running next filter...`)
const validEncryptedCards = validatedEncryptedCards.filter(card => card !== null);
console.log(`validEncryptedcards:`, validEncryptedCards)
if (validEncryptedCards.length === 0) {
encryptedCardsContainer.innerHTML = "<p>No valid cards found.</p>";
return;
}
const finalCards = await processCards(validEncryptedCards)
console.log(`finalCards:`,finalCards)
// Display skeleton cards immediately
encryptedCardsContainer.innerHTML = "";
finalCards.forEach(card => {
@@ -371,14 +340,16 @@ const createEncryptedSkeletonCardHTML = (cardIdentifier) => {
// Function to check and fech an existing Minter Card if attempting to publish twice ----------------------------------------
const fetchExistingEncryptedCard = async (minterName) => {
try {
// Step 1: Perform the search
const response = await qortalRequest({
action: "SEARCH_QDN_RESOURCES",
service: "MAIL_PRIVATE",
identifier: encryptedCardIdentifierPrefix,
query: minterName,
mode: "ALL",
});
// const response = await qortalRequest({
// action: "SEARCH_QDN_RESOURCES",
// service: "MAIL_PRIVATE",
// identifier: encryptedCardIdentifierPrefix,
// query: minterName,
// mode: "ALL",
// })
//CHANGED to searchSimple to speed up search results.
const response = await searchSimple('MAIL_PRIVATE', `${encryptedCardIdentifierPrefix}`, '', 0)
console.log(`SEARCH_QDN_RESOURCES response: ${JSON.stringify(response, null, 2)}`);
@@ -598,17 +569,18 @@ const publishEncryptedCard = async (isTopicModePassed = false) => {
const getEncryptedCommentCount = async (cardIdentifier) => {
try {
const response = await qortalRequest({
action: 'SEARCH_QDN_RESOURCES',
service: 'MAIL_PRIVATE',
query: `comment-${cardIdentifier}`,
mode: "ALL"
});
// const response = await qortalRequest({
// action: 'SEARCH_QDN_RESOURCES',
// service: 'MAIL_PRIVATE',
// query: `comment-${cardIdentifier}`,
// mode: "ALL"
// })
const response = await searchSimple('MAIL_PRIVATE', `comment-${cardIdentifier}`, '', 0)
// Just return the count; no need to decrypt each comment here
return Array.isArray(response) ? response.length : 0;
return Array.isArray(response) ? response.length : 0
} catch (error) {
console.error(`Error fetching comment count for ${cardIdentifier}:`, error);
return 0;
console.error(`Error fetching comment count for ${cardIdentifier}:`, error)
return 0
}
};
@@ -666,14 +638,17 @@ const postEncryptedComment = async (cardIdentifier) => {
//Fetch the comments for a card with passed card identifier ----------------------------
const fetchEncryptedComments = async (cardIdentifier) => {
try {
const response = await qortalRequest({
action: 'SEARCH_QDN_RESOURCES',
service: 'MAIL_PRIVATE',
query: `comment-${cardIdentifier}`,
mode: "ALL"
});
// const response = await qortalRequest({
// action: 'SEARCH_QDN_RESOURCES',
// service: 'MAIL_PRIVATE',
// query: `comment-${cardIdentifier}`,
// mode: "ALL"
// })
const response = await searchSimple('MAIL_PRIVATE', `comment-${cardIdentifier}`, '', 0)
return response;
if (response) {
return response;
}
} catch (error) {
console.error(`Error fetching comments for ${cardIdentifier}:`, error);
return [];
@@ -683,7 +658,9 @@ const fetchEncryptedComments = async (cardIdentifier) => {
// display the comments on the card, with passed cardIdentifier to identify the card --------------
const displayEncryptedComments = async (cardIdentifier) => {
try {
const comments = await fetchEncryptedComments(cardIdentifier);
const commentsContainer = document.getElementById(`comments-container-${cardIdentifier}`);
// Fetch and display each comment
@@ -712,8 +689,8 @@ const displayEncryptedComments = async (cardIdentifier) => {
commentsContainer.insertAdjacentHTML('beforeend', commentHTML);
}
} catch (error) {
console.error(`Error displaying comments for ${cardIdentifier}:`, error);
alert("Failed to load comments. Please try again.");
console.error(`Error displaying comments (or no comments) for ${cardIdentifier}:`, error);
}
};
@@ -757,7 +734,7 @@ const calculateAdminBoardPollResults = async (pollData, minterGroupMembers, mint
// 4) Process votes
for (const vote of pollData.votes) {
const voterAddress = await getAddressFromPublicKey(vote.voterPublicKey);
console.log(`voter address: ${voterAddress}, optionIndex: ${vote.optionIndex}`);
// console.log(`voter address: ${voterAddress}, optionIndex: ${vote.optionIndex}`);
if (vote.optionIndex === 0) {
if (adminAddresses.includes(voterAddress)) {

View File

@@ -120,17 +120,17 @@ const loadMinterBoardPage = async () => {
const extractMinterCardsMinterName = async (cardIdentifier) => {
// Ensure the identifier starts with the prefix
if (!cardIdentifier.startsWith(`${cardIdentifierPrefix}-`)) {
throw new Error('Invalid identifier format or prefix mismatch');
throw new Error('Invalid identifier format or prefix mismatch')
}
// Split the identifier into parts
const parts = cardIdentifier.split('-');
const parts = cardIdentifier.split('-')
// Ensure the format has at least 3 parts
if (parts.length < 3) {
throw new Error('Invalid identifier format');
throw new Error('Invalid identifier format')
}
try {
const nameFromIdentifier = await searchSimple('BLOG_POST', cardIdentifier, "", 1)
const minterName = await nameFromIdentifier.name
const searchSimpleResults = await searchSimple('BLOG_POST', `${cardIdentifier}`, '', 1)
const minterName = await searchSimpleResults.name
return minterName
} catch (error) {
throw error
@@ -195,12 +195,14 @@ const loadCards = async () => {
cardsContainer.innerHTML = "<p>Loading cards...</p>";
try {
const response = await qortalRequest({
action: "SEARCH_QDN_RESOURCES",
service: "BLOG_POST",
query: cardIdentifierPrefix,
mode: "ALL"
});
// const response = await qortalRequest({
// action: "SEARCH_QDN_RESOURCES",
// service: "BLOG_POST",
// query: cardIdentifierPrefix,
// mode: "ALL"
// })
const response = await searchSimple('BLOG_POST', `${cardIdentifierPrefix}`, '' , 0)
if (!response || !Array.isArray(response) || response.length === 0) {
cardsContainer.innerHTML = "<p>No cards found.</p>";
@@ -320,14 +322,16 @@ const createSkeletonCardHTML = (cardIdentifier) => {
const fetchExistingCard = async () => {
try {
// Step 1: Perform the search
const response = await qortalRequest({
action: "SEARCH_QDN_RESOURCES",
service: "BLOG_POST",
identifier: cardIdentifierPrefix,
name: userState.accountName,
mode: "ALL",
exactMatchNames: true // Search for the exact userName only when finding existing cards
});
// const response = await qortalRequest({
// action: "SEARCH_QDN_RESOURCES",
// service: "BLOG_POST",
// identifier: cardIdentifierPrefix,
// name: userState.accountName,
// mode: "ALL",
// exactMatchNames: true // Search for the exact userName only when finding existing cards
// })
// Changed to searchSimple to improve load times.
const response = await searchSimple('BLOG_POST', `${cardIdentifierPrefix}`, `${userState.accountName}`, 0)
console.log(`SEARCH_QDN_RESOURCES response: ${JSON.stringify(response, null, 2)}`);
@@ -335,9 +339,11 @@ const fetchExistingCard = async () => {
if (!response || !Array.isArray(response) || response.length === 0) {
console.log("No cards found for the current user.");
return null;
} else if (response.length === 1) { // we don't need to go through all of the rest of the checks and filtering nonsense if there's only a single result, just return it.
return response[0]
}
// Step 3: Validate cards asynchronously
// Validate cards asynchronously, check that they are not comments, etc.
const validatedCards = await Promise.all(
response.map(async card => {
const isValid = await validateCardStructure(card);
@@ -345,14 +351,14 @@ const fetchExistingCard = async () => {
})
);
// Step 4: Filter out invalid cards
// Filter out invalid cards
const validCards = validatedCards.filter(card => card !== null);
if (validCards.length > 0) {
// Step 5: Sort by most recent timestamp
// Sort by most recent timestamp
const mostRecentCard = validCards.sort((a, b) => b.created - a.created)[0];
// Step 6: Fetch full card data
// Fetch full card data
const cardDataResponse = await qortalRequest({
action: "FETCH_QDN_RESOURCE",
name: userState.accountName, // User's account name
@@ -490,7 +496,7 @@ const calculatePollResults = async (pollData, minterGroupMembers, minterAdmins)
for (const vote of pollData.votes) {
const voterAddress = await getAddressFromPublicKey(vote.voterPublicKey)
console.log(`voter address: ${voterAddress}`)
// console.log(`voter address: ${voterAddress}`)
if (vote.optionIndex === 0) {
adminAddresses.includes(voterAddress) ? adminYes++ : memberAddresses.includes(voterAddress) ? minterYes++ : console.log(`voter ${voterAddress} is not a minter nor an admin...Not including results...`)
@@ -555,18 +561,19 @@ const postComment = async (cardIdentifier) => {
//Fetch the comments for a card with passed card identifier ----------------------------
const fetchCommentsForCard = async (cardIdentifier) => {
try {
const response = await qortalRequest({
action: 'SEARCH_QDN_RESOURCES',
service: 'BLOG_POST',
query: `comment-${cardIdentifier}`,
mode: "ALL"
});
return response;
// const response = await qortalRequest({
// action: 'SEARCH_QDN_RESOURCES',
// service: 'BLOG_POST',
// query: `comment-${cardIdentifier}`,
// mode: "ALL"
// })
const response = await searchSimple('BLOG_POST',`comment-${cardIdentifier}`, '', 0)
return response
} catch (error) {
console.error(`Error fetching comments for ${cardIdentifier}:`, error);
return [];
console.error(`Error fetching comments for ${cardIdentifier}:`, error)
return []
}
};
}
// display the comments on the card, with passed cardIdentifier to identify the card --------------
const displayComments = async (cardIdentifier) => {
@@ -594,8 +601,7 @@ const displayComments = async (cardIdentifier) => {
commentsContainer.insertAdjacentHTML('beforeend', commentHTML);
}
} catch (error) {
console.error(`Error displaying comments for ${cardIdentifier}:`, error);
alert("Failed to load comments. Please try again.");
console.error(`Error displaying comments (or no comments) for ${cardIdentifier}:`, error);
}
};
@@ -624,12 +630,14 @@ const toggleComments = async (cardIdentifier) => {
const countComments = async (cardIdentifier) => {
try {
const response = await qortalRequest({
action: 'SEARCH_QDN_RESOURCES',
service: 'BLOG_POST',
query: `comment-${cardIdentifier}`,
mode: "ALL"
});
// const response = await qortalRequest({
// action: 'SEARCH_QDN_RESOURCES',
// service: 'BLOG_POST',
// query: `comment-${cardIdentifier}`,
// mode: "ALL"
// })
// Changed to searchSimple to hopefully improve load times...
const response = await searchSimple('BLOG_POST', `comment-${cardIdentifier}`, '', 0)
// Just return the count; no need to decrypt each comment here
return Array.isArray(response) ? response.length : 0;
} catch (error) {

View File

@@ -649,8 +649,8 @@ const generateAttachmentID = (room, fileIndex = null) => {
const findMessagePage = async (room, identifier, limit) => {
const { service, query } = getServiceAndQuery(room)
const allMessages = await searchAllWithOffset(service, query, 0, 0, room)
//TODO check that searchSimple change worked.
const allMessages = await searchSimple(service, query, '', 0, 0, room, 'false')
const idx = allMessages.findIndex(msg => msg.identifier === identifier);
if (idx === -1) {
@@ -746,7 +746,8 @@ const getServiceAndQuery = (room) => {
};
const fetchResourceList = async (service, query, limit, offset, room) => {
return await searchAllWithOffset(service, query, limit, offset, room);
//TODO check
return await searchSimple(service, query, '', limit, offset, room, 'false');
};
const handleNoMessagesScenario = (isPolling, page, response, messagesContainer) => {

File diff suppressed because it is too large Load Diff