Browse Source

improved search some more

master
silberengel 7 months ago
parent
commit
11c605b5ef
  1. 132
      src/lib/components/EventSearch.svelte
  2. 7
      src/lib/utils/search_constants.ts
  3. 50
      src/lib/utils/subscription_search.ts
  4. 12
      src/routes/events/+page.svelte

132
src/lib/components/EventSearch.svelte

@ -488,6 +488,61 @@ @@ -488,6 +488,61 @@
searchType,
searchTerm,
});
// AI-NOTE: 2025-01-24 - Check cache first for profile searches to provide immediate response
if (searchType === "n") {
try {
const { getUserMetadata } = await import("$lib/utils/nostrUtils");
const cachedProfile = await getUserMetadata(searchTerm, false);
if (cachedProfile && cachedProfile.name) {
console.log("EventSearch: Found cached profile, displaying immediately:", cachedProfile);
// Create a mock NDKEvent for the cached profile
const { NDKEvent } = await import("@nostr-dev-kit/ndk");
const { nip19 } = await import("$lib/utils/nostrUtils");
// Decode the npub to get the actual pubkey
let pubkey = searchTerm;
try {
const decoded = nip19.decode(searchTerm);
if (decoded && decoded.type === "npub") {
pubkey = decoded.data;
}
} catch (error) {
console.warn("EventSearch: Failed to decode npub for mock event:", error);
}
const mockEvent = new NDKEvent(undefined, {
kind: 0,
pubkey: pubkey,
content: JSON.stringify(cachedProfile),
tags: [],
created_at: Math.floor(Date.now() / 1000),
id: "", // Will be computed by NDK
sig: "", // Will be computed by NDK
});
// Display the cached profile immediately
handleFoundEvent(mockEvent);
updateSearchState(false, true, 1, "profile-cached");
// AI-NOTE: 2025-01-24 - Still perform background search for second-order events
// but with better timeout handling to prevent hanging
setTimeout(async () => {
try {
await performBackgroundProfileSearch(searchType, searchTerm);
} catch (error) {
console.warn("EventSearch: Background profile search failed:", error);
}
}, 100);
return;
}
} catch (error) {
console.warn("EventSearch: Cache check failed, proceeding with subscription search:", error);
}
}
isResetting = false; // Allow effects to run for new searches
localError = null;
updateSearchState(true);
@ -663,6 +718,83 @@ @@ -663,6 +718,83 @@
}
}
// AI-NOTE: 2025-01-24 - Function to perform background profile search without blocking UI
async function performBackgroundProfileSearch(
searchType: "d" | "t" | "n",
searchTerm: string,
) {
console.log("EventSearch: Performing background profile search:", {
searchType,
searchTerm,
});
try {
// Cancel existing search
if (currentAbortController) {
currentAbortController.abort();
}
currentAbortController = new AbortController();
// AI-NOTE: 2025-01-24 - Add timeout to prevent hanging background searches
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject(new Error("Background search timeout"));
}, 10000); // 10 second timeout for background searches
});
const searchPromise = searchBySubscription(
searchType,
searchTerm,
{
onSecondOrderUpdate: (updatedResult) => {
console.log("EventSearch: Background second order update:", updatedResult);
// Only update if we have new results
if (updatedResult.events.length > 0) {
onSearchResults(
updatedResult.events,
updatedResult.secondOrder,
updatedResult.tTagEvents,
updatedResult.eventIds,
updatedResult.addresses,
updatedResult.searchType,
updatedResult.searchTerm,
);
}
},
onSubscriptionCreated: (sub) => {
console.log("EventSearch: Background subscription created:", sub);
if (activeSub) {
activeSub.stop();
}
activeSub = sub;
},
},
currentAbortController.signal,
);
// Race between search and timeout
const result = await Promise.race([searchPromise, timeoutPromise]) as any;
console.log("EventSearch: Background search completed:", result);
// Only update results if we have new data
if (result.events.length > 0) {
onSearchResults(
result.events,
result.secondOrder,
result.tTagEvents,
result.eventIds,
result.addresses,
result.searchType,
result.searchTerm,
);
}
} catch (error) {
console.warn("EventSearch: Background profile search failed:", error);
}
}
// Search utility functions
function handleClear() {
isResetting = true;
searchQuery = "";

7
src/lib/utils/search_constants.ts

@ -17,7 +17,7 @@ export const TIMEOUTS = { @@ -17,7 +17,7 @@ export const TIMEOUTS = {
SUBSCRIPTION_SEARCH: 10000,
/** Timeout for second-order search operations */
SECOND_ORDER_SEARCH: 5000,
SECOND_ORDER_SEARCH: 3000, // AI-NOTE: 2025-01-24 - Reduced timeout since we limit scope
/** Timeout for relay diagnostics */
RELAY_DIAGNOSTICS: 5000,
@ -44,7 +44,10 @@ export const SEARCH_LIMITS = { @@ -44,7 +44,10 @@ export const SEARCH_LIMITS = {
SPECIFIC_PROFILE: 10,
/** Limit for general profile searches */
GENERAL_PROFILE: 500,
GENERAL_PROFILE: 100, // AI-NOTE: 2025-01-24 - Reduced from 500 to prevent wild searches
/** Limit for general content searches (t-tag, d-tag, etc.) */
GENERAL_CONTENT: 100, // AI-NOTE: 2025-01-24 - Added limit for all content searches
/** Limit for community relay checks */
COMMUNITY_CHECK: 1,

50
src/lib/utils/subscription_search.ts

@ -59,19 +59,11 @@ export async function searchBySubscription( @@ -59,19 +59,11 @@ export async function searchBySubscription(
const cachedResult = searchCache.get(searchType, normalizedSearchTerm);
if (cachedResult) {
console.log("subscription_search: Found cached result:", cachedResult);
// AI-NOTE: 2025-01-08 - For profile searches, clear cache if it's empty to force fresh search
if (searchType === "n" && cachedResult.events.length === 0) {
console.log("subscription_search: Clearing empty cached profile result to force fresh search");
searchCache.clear(); // Clear all cache to force fresh search
} else if (searchType === "n" && cachedResult.events.length > 0 && cachedResult.secondOrder.length === 0) {
// AI-NOTE: 2025-01-08 - Clear cache if we have profile results but no second-order events
// This forces a fresh search that includes second-order searching
console.log("subscription_search: Clearing cached profile result with no second-order events to force fresh search");
searchCache.clear();
} else if (searchType === "n") {
// AI-NOTE: 2025-01-08 - For profile searches, always clear cache to ensure fresh second-order search
console.log("subscription_search: Clearing cache for profile search to ensure fresh second-order search");
searchCache.clear();
// AI-NOTE: 2025-01-24 - For profile searches, return cached results immediately
// The EventSearch component now handles cache checking before calling this function
if (searchType === "n") {
console.log("subscription_search: Returning cached profile result immediately");
return cachedResult;
} else {
return cachedResult;
}
@ -91,7 +83,7 @@ export async function searchBySubscription( @@ -91,7 +83,7 @@ export async function searchBySubscription(
searchState.timeoutId = setTimeout(() => {
console.log("subscription_search: Search timeout reached");
cleanup();
}, searchType === "n" ? 5000 : TIMEOUTS.SUBSCRIPTION_SEARCH); // AI-NOTE: 2025-01-08 - Shorter timeout for profile searches
}, TIMEOUTS.SUBSCRIPTION_SEARCH); // AI-NOTE: 2025-01-24 - Use standard timeout since cache is checked first
// Check for abort signal
if (abortSignal?.aborted) {
@ -332,7 +324,7 @@ async function createSearchFilter( @@ -332,7 +324,7 @@ async function createSearchFilter(
switch (searchType) {
case "d": {
const dFilter = {
filter: { "#d": [normalizedSearchTerm] },
filter: { "#d": [normalizedSearchTerm], limit: SEARCH_LIMITS.GENERAL_CONTENT },
subscriptionType: "d-tag",
};
console.log("subscription_search: Created d-tag filter:", dFilter);
@ -340,7 +332,7 @@ async function createSearchFilter( @@ -340,7 +332,7 @@ async function createSearchFilter(
}
case "t": {
const tFilter = {
filter: { "#t": [normalizedSearchTerm] },
filter: { "#t": [normalizedSearchTerm], limit: SEARCH_LIMITS.GENERAL_CONTENT },
subscriptionType: "t-tag",
};
console.log("subscription_search: Created t-tag filter:", tFilter);
@ -929,21 +921,33 @@ async function performSecondOrderSearchInBackground( @@ -929,21 +921,33 @@ async function performSecondOrderSearchInBackground(
if (searchType === "n" && targetPubkey) {
console.log("subscription_search: Searching for events mentioning pubkey:", targetPubkey);
// AI-NOTE: 2025-01-24 - Use only active relays for second-order profile search to prevent hanging
const activeRelays = [...get(activeInboxRelays), ...get(activeOutboxRelays)];
const availableRelays = activeRelays
.map(url => ndk.pool.relays.get(url))
.filter((relay): relay is any => relay !== undefined);
const relaySet = new NDKRelaySet(
new Set(availableRelays),
ndk
);
console.log("subscription_search: Using", activeRelays.length, "active relays for second-order search");
// Search for events that mention this pubkey via p-tags
const pTagFilter = { "#p": [targetPubkey] };
const pTagFilter = { "#p": [targetPubkey], limit: 50 }; // AI-NOTE: 2025-01-24 - Limit results to prevent hanging
const pTagEvents = await ndk.fetchEvents(
pTagFilter,
{ closeOnEose: true },
new NDKRelaySet(new Set(Array.from(ndk.pool.relays.values())), ndk),
relaySet,
);
console.log("subscription_search: Found", pTagEvents.size, "events with p-tag for", targetPubkey);
// AI-NOTE: 2025-01-08 - Also search for events written by this pubkey
const authorFilter = { authors: [targetPubkey] };
// AI-NOTE: 2025-01-24 - Also search for events written by this pubkey with limit
const authorFilter = { authors: [targetPubkey], limit: 50 }; // AI-NOTE: 2025-01-24 - Limit results to prevent hanging
const authorEvents = await ndk.fetchEvents(
authorFilter,
{ closeOnEose: true },
new NDKRelaySet(new Set(Array.from(ndk.pool.relays.values())), ndk),
relaySet,
);
console.log("subscription_search: Found", authorEvents.size, "events written by", targetPubkey);
@ -964,14 +968,14 @@ async function performSecondOrderSearchInBackground( @@ -964,14 +968,14 @@ async function performSecondOrderSearchInBackground(
const [eTagEvents, aTagEvents] = await Promise.all([
eventIds.size > 0
? ndk.fetchEvents(
{ "#e": Array.from(eventIds) },
{ "#e": Array.from(eventIds), limit: SEARCH_LIMITS.SECOND_ORDER_RESULTS },
{ closeOnEose: true },
relaySet,
)
: Promise.resolve([]),
addresses.size > 0
? ndk.fetchEvents(
{ "#a": Array.from(addresses) },
{ "#a": Array.from(addresses), limit: SEARCH_LIMITS.SECOND_ORDER_RESULTS },
{ closeOnEose: true },
relaySet,
)

12
src/routes/events/+page.svelte

@ -453,15 +453,17 @@ import CommentViewer from "$lib/components/CommentViewer.svelte"; @@ -453,15 +453,17 @@ import CommentViewer from "$lib/components/CommentViewer.svelte";
{#if searchResults.length > 0}
<div class="mt-8">
<Heading tag="h2" class="h-leather mb-4">
<Heading tag="h2" class="h-leather mb-4 break-words">
{#if searchType === "n"}
Search Results for name: "{searchTerm}" ({searchResults.length} profiles)
Search Results for name: "{searchTerm && searchTerm.length > 50 ? searchTerm.slice(0, 50) + '...' : searchTerm || ''}" ({searchResults.length} profiles)
{:else if searchType === "t"}
Search Results for t-tag: "{searchTerm}" ({searchResults.length}
Search Results for t-tag: "{searchTerm && searchTerm.length > 50 ? searchTerm.slice(0, 50) + '...' : searchTerm || ''}" ({searchResults.length}
events)
{:else}
Search Results for d-tag: "{searchTerm ||
dTagValue?.toLowerCase()}" ({searchResults.length} events)
Search Results for d-tag: "{(() => {
const term = searchTerm || dTagValue?.toLowerCase() || '';
return term.length > 50 ? term.slice(0, 50) + '...' : term;
})()}" ({searchResults.length} events)
{/if}
</Heading>
<div class="space-y-4">

Loading…
Cancel
Save