mirror of
https://github.com/logos-messaging/lab.waku.org.git
synced 2026-01-07 16:23:11 +00:00
feat: add a control for querying store in dogfooding app (#142)
This commit is contained in:
parent
07c9a6a1eb
commit
90c7927283
@ -51,6 +51,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="store-query">
|
||||||
|
<h2>Store Protocol Query</h2>
|
||||||
|
<div class="store-controls">
|
||||||
|
<label for="storeMessageCount">Number of messages to fetch:</label>
|
||||||
|
<input type="number" id="storeMessageCount" value="5" min="1" max="100" />
|
||||||
|
<button id="queryStoreButton" class="btn btn-primary">Query Store</button>
|
||||||
|
</div>
|
||||||
|
<div id="storeQueryStatus" class="store-status"></div>
|
||||||
|
<div id="storeQueryResults" class="store-results"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="charts">
|
<section class="charts">
|
||||||
<h2>Discovery Peers Over Time</h2>
|
<h2>Discovery Peers Over Time</h2>
|
||||||
<canvas id="discoveryChart"></canvas>
|
<canvas id="discoveryChart"></canvas>
|
||||||
|
|||||||
@ -92,6 +92,24 @@ h2 {
|
|||||||
background-color: #2980b9;
|
background-color: #2980b9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-success {
|
||||||
|
background-color: #27ae60;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-success:hover {
|
||||||
|
background-color: #229954;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger {
|
||||||
|
background-color: #e74c3c;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger:hover {
|
||||||
|
background-color: #c0392b;
|
||||||
|
}
|
||||||
|
|
||||||
.search-container {
|
.search-container {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -106,6 +124,40 @@ h2 {
|
|||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Store Query Section */
|
||||||
|
.store-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.store-controls label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.store-controls input[type="number"] {
|
||||||
|
width: 80px;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.store-status {
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.store-results {
|
||||||
|
margin-top: 15px;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/* Message Display */
|
/* Message Display */
|
||||||
.message-list {
|
.message-list {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
@ -214,7 +266,7 @@ footer {
|
|||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-stats, .message-controls {
|
.message-stats, .message-controls, .store-query, .charts {
|
||||||
grid-column: span 1;
|
grid-column: span 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,9 @@ import {
|
|||||||
trackMessageSent,
|
trackMessageSent,
|
||||||
trackMessageReceived,
|
trackMessageReceived,
|
||||||
recordLatency,
|
recordLatency,
|
||||||
|
updateStoreQueryStatus,
|
||||||
|
displayStoreQueryResults,
|
||||||
|
clearStoreQueryResults,
|
||||||
} from "./ui-manager";
|
} from "./ui-manager";
|
||||||
|
|
||||||
const NUM_MESSAGES_PER_BATCH = 5;
|
const NUM_MESSAGES_PER_BATCH = 5;
|
||||||
@ -206,6 +209,100 @@ async function initializeApp() {
|
|||||||
console.log("Subscription active.");
|
console.log("Subscription active.");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const queryStoreMessages = async () => {
|
||||||
|
const storeMessageCountInput = document.getElementById("storeMessageCount") as HTMLInputElement;
|
||||||
|
const messageLimit = storeMessageCountInput ? parseInt(storeMessageCountInput.value, 10) : 5;
|
||||||
|
|
||||||
|
if (isNaN(messageLimit) || messageLimit < 1) {
|
||||||
|
updateStoreQueryStatus("Please enter a valid number of messages (minimum 1)", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearStoreQueryResults();
|
||||||
|
updateStoreQueryStatus("Querying store...", false);
|
||||||
|
console.log(`Querying store for up to ${messageLimit} messages...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decoder = createWakuDecoder();
|
||||||
|
const allMessages: ChatMessage[] = [];
|
||||||
|
|
||||||
|
console.log("Decoder content topic:", decoder.contentTopic);
|
||||||
|
console.log("Decoder pubsub topic:", decoder.pubsubTopic);
|
||||||
|
|
||||||
|
// Query for messages from the last hour, using paginationLimit to control result size
|
||||||
|
const timeEnd = new Date();
|
||||||
|
const timeStart = new Date(Date.now() - 1000 * 60 * 60);
|
||||||
|
|
||||||
|
const queryOptions = {
|
||||||
|
timeStart,
|
||||||
|
timeEnd,
|
||||||
|
paginationForward: false, // Start from newest
|
||||||
|
paginationLimit: messageLimit, // Limit the number of messages returned
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("Store query options:", queryOptions);
|
||||||
|
console.log("Time range:", timeStart.toISOString(), "to", timeEnd.toISOString());
|
||||||
|
|
||||||
|
// Collect messages - stop once we have enough
|
||||||
|
await node.store.queryWithOrderedCallback(
|
||||||
|
[decoder],
|
||||||
|
async (wakuMessage) => {
|
||||||
|
// Check if we already have enough messages before processing more
|
||||||
|
if (allMessages.length >= messageLimit) {
|
||||||
|
console.log(`Already collected ${messageLimit} messages, stopping`);
|
||||||
|
return true; // Stop processing
|
||||||
|
}
|
||||||
|
|
||||||
|
const chatMessage = decodeMessage(wakuMessage.payload);
|
||||||
|
if (chatMessage) {
|
||||||
|
allMessages.push(chatMessage);
|
||||||
|
console.log(`Store found message ${allMessages.length}/${messageLimit}:`, {
|
||||||
|
id: chatMessage.id,
|
||||||
|
content: chatMessage.content.substring(0, 50),
|
||||||
|
timestamp: new Date(chatMessage.timestamp).toISOString(),
|
||||||
|
sender: chatMessage.senderPeerId.substring(0, 12)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stop if we've reached the limit
|
||||||
|
if (allMessages.length >= messageLimit) {
|
||||||
|
console.log(`Reached limit of ${messageLimit} messages, stopping`);
|
||||||
|
return true; // Stop processing
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("Failed to decode message from store");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Continue to next message
|
||||||
|
},
|
||||||
|
queryOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Store query completed. Collected ${allMessages.length} messages.`);
|
||||||
|
|
||||||
|
if (allMessages.length > 0) {
|
||||||
|
// Sort by timestamp descending (newest first)
|
||||||
|
// Since we're querying with paginationForward: false, we're getting recent messages,
|
||||||
|
// but they may not be in perfect order, so we sort them
|
||||||
|
allMessages.sort((a, b) => b.timestamp - a.timestamp);
|
||||||
|
|
||||||
|
console.log(`Returning ${allMessages.length} message(s)`);
|
||||||
|
console.log("Newest message timestamp:", new Date(allMessages[0].timestamp).toISOString());
|
||||||
|
if (allMessages.length > 1) {
|
||||||
|
console.log("Oldest returned message timestamp:", new Date(allMessages[allMessages.length - 1].timestamp).toISOString());
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStoreQueryStatus(`✓ Successfully retrieved ${allMessages.length} message${allMessages.length !== 1 ? 's' : ''} from store`, false);
|
||||||
|
displayStoreQueryResults(allMessages);
|
||||||
|
} else {
|
||||||
|
updateStoreQueryStatus("✓ Query completed successfully, but no messages found in store", false);
|
||||||
|
displayStoreQueryResults([]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error querying store:", error);
|
||||||
|
updateStoreQueryStatus(`✗ Error querying store: ${error instanceof Error ? error.message : String(error)}`, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const sendMessageButton = document.getElementById("sendMessageButton");
|
const sendMessageButton = document.getElementById("sendMessageButton");
|
||||||
if (sendMessageButton) {
|
if (sendMessageButton) {
|
||||||
sendMessageButton.addEventListener("click", () => {
|
sendMessageButton.addEventListener("click", () => {
|
||||||
@ -241,6 +338,14 @@ async function initializeApp() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const queryStoreButton = document.getElementById("queryStoreButton");
|
||||||
|
if (queryStoreButton) {
|
||||||
|
queryStoreButton.addEventListener("click", () => {
|
||||||
|
console.log("Query Store button clicked");
|
||||||
|
queryStoreMessages();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
initCharts();
|
initCharts();
|
||||||
(window as any).onDiscoveryUpdate = onDiscoveryUpdate;
|
(window as any).onDiscoveryUpdate = onDiscoveryUpdate;
|
||||||
(window as any).onConnectionsUpdate = onConnectionsUpdate;
|
(window as any).onConnectionsUpdate = onConnectionsUpdate;
|
||||||
|
|||||||
@ -322,3 +322,82 @@ export function recordLatency(id: string, sent: number, received?: number) {
|
|||||||
export function wireUiToggles() {
|
export function wireUiToggles() {
|
||||||
setupCollapsibles();
|
setupCollapsibles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store Query UI
|
||||||
|
const storeQueryStatusEl = document.getElementById("storeQueryStatus") as HTMLDivElement | null;
|
||||||
|
const storeQueryResultsEl = document.getElementById("storeQueryResults") as HTMLDivElement | null;
|
||||||
|
|
||||||
|
export function updateStoreQueryStatus(message: string, isError: boolean = false) {
|
||||||
|
if (!storeQueryStatusEl) return;
|
||||||
|
storeQueryStatusEl.textContent = message;
|
||||||
|
storeQueryStatusEl.style.color = isError ? '#d32f2f' : '#2e7d32';
|
||||||
|
storeQueryStatusEl.style.fontWeight = 'bold';
|
||||||
|
storeQueryStatusEl.style.marginTop = '10px';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function displayStoreQueryResults(messages: ChatMessage[]) {
|
||||||
|
if (!storeQueryResultsEl) return;
|
||||||
|
|
||||||
|
storeQueryResultsEl.innerHTML = "";
|
||||||
|
|
||||||
|
if (messages.length === 0) {
|
||||||
|
storeQueryResultsEl.innerHTML = "<p style='color: #666; font-style: italic;'>No messages found.</p>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = document.createElement("h3");
|
||||||
|
title.textContent = `Found ${messages.length} message${messages.length !== 1 ? 's' : ''}:`;
|
||||||
|
title.style.marginTop = "15px";
|
||||||
|
storeQueryResultsEl.appendChild(title);
|
||||||
|
|
||||||
|
messages.forEach((message, index) => {
|
||||||
|
const item = document.createElement("div");
|
||||||
|
item.classList.add("message-item");
|
||||||
|
item.style.marginBottom = "10px";
|
||||||
|
item.style.padding = "10px";
|
||||||
|
item.style.border = "1px solid #ddd";
|
||||||
|
item.style.borderRadius = "4px";
|
||||||
|
item.style.backgroundColor = "#f9f9f9";
|
||||||
|
|
||||||
|
const indexLabel = document.createElement("p");
|
||||||
|
indexLabel.style.fontWeight = "bold";
|
||||||
|
indexLabel.style.marginBottom = "5px";
|
||||||
|
indexLabel.textContent = `Message ${index + 1}`;
|
||||||
|
|
||||||
|
const idText = document.createElement("p");
|
||||||
|
idText.style.fontSize = "0.9em";
|
||||||
|
idText.style.color = "#666";
|
||||||
|
idText.textContent = `ID: ${message.id}`;
|
||||||
|
|
||||||
|
const contentP = document.createElement("p");
|
||||||
|
contentP.style.margin = "8px 0";
|
||||||
|
contentP.textContent = message.content;
|
||||||
|
|
||||||
|
const senderInfoP = document.createElement("p");
|
||||||
|
senderInfoP.style.fontSize = "0.9em";
|
||||||
|
senderInfoP.style.color = "#666";
|
||||||
|
senderInfoP.textContent = `From: ${message.senderPeerId.substring(0, 12)}...`;
|
||||||
|
|
||||||
|
const timestampP = document.createElement("p");
|
||||||
|
timestampP.style.fontSize = "0.9em";
|
||||||
|
timestampP.style.color = "#666";
|
||||||
|
timestampP.textContent = `Time: ${new Date(message.timestamp).toLocaleString()}`;
|
||||||
|
|
||||||
|
item.appendChild(indexLabel);
|
||||||
|
item.appendChild(idText);
|
||||||
|
item.appendChild(contentP);
|
||||||
|
item.appendChild(senderInfoP);
|
||||||
|
item.appendChild(timestampP);
|
||||||
|
|
||||||
|
storeQueryResultsEl.appendChild(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearStoreQueryResults() {
|
||||||
|
if (storeQueryResultsEl) {
|
||||||
|
storeQueryResultsEl.innerHTML = "";
|
||||||
|
}
|
||||||
|
if (storeQueryStatusEl) {
|
||||||
|
storeQueryStatusEl.textContent = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user