@ -76,25 +76,24 @@ func (ws *WikiService) FetchWikiIndex(ctx context.Context, naddrStr string) (*In
return index , nil
return index , nil
}
}
// FetchWikiEvents fetches all wiki events referenced in an index
// fetchIndexEventsByKind is a helper that fetches events of a specific kind from an index
// Uses ProcessEventsWithCache for the initial fetch, then filters by index items
// Returns a map of kind:pubkey:dtag -> event for matching
func ( ws * WikiService ) FetchWikiEvents ( ctx context . Context , index * IndexEvent ) ( [ ] * Wiki Event, error ) {
func ( ws * WikiService ) fetchIndexEventsByKind ( ctx context . Context , index * IndexEvent , targetKind int ) ( map [ string ] * nostr . Event , error ) {
// Build a map of expected items (kind:pubkey:dtag) for fast lookup
// Build a map of expected items (kind:pubkey:dtag) for fast lookup
expectedItems := make ( map [ string ] IndexItem )
expectedItems := make ( map [ string ] IndexItem )
for _ , item := range index . Items {
for _ , item := range index . Items {
if item . Kind == ws . wiki Kind {
if item . Kind == target Kind {
key := fmt . Sprintf ( "%d:%s:%s" , item . Kind , item . Pubkey , item . DTag )
key := fmt . Sprintf ( "%d:%s:%s" , item . Kind , item . Pubkey , item . DTag )
expectedItems [ key ] = item
expectedItems [ key ] = item
}
}
}
}
if len ( expectedItems ) == 0 {
if len ( expectedItems ) == 0 {
return [ ] * WikiEvent { } , nil
return make ( map [ string ] * nostr . Event ) , nil
}
}
// Use ProcessEventsWithCache to fetch events of this kind
// Use ProcessEventsWithCache to fetch events of this kind
// Use a high display limit (1000) to ensure we get all events referenced in the index
// Use a high display limit (1000) to ensure we get all events referenced in the index
// This means we'll fetch 2000 events, which should be enough for most cases
displayLimit := 1000
displayLimit := 1000
primaryRelay := ws . client . GetPrimaryRelay ( )
primaryRelay := ws . client . GetPrimaryRelay ( )
if primaryRelay == "" {
if primaryRelay == "" {
@ -102,37 +101,21 @@ func (ws *WikiService) FetchWikiEvents(ctx context.Context, index *IndexEvent) (
}
}
logger . WithFields ( map [ string ] interface { } {
logger . WithFields ( map [ string ] interface { } {
"kind" : ws . wiki Kind,
"kind" : target Kind,
"items" : len ( expectedItems ) ,
"items" : len ( expectedItems ) ,
"index_event_id" : index . Event . ID ,
"index_event_id" : index . Event . ID ,
} ) . Debug ( "Fetching wiki events using ProcessEventsWithCache with index" )
} ) . Debug ( "Fetching events using ProcessEventsWithCache with index" )
// Use standard process with index event ID: fetch index, query only referenced events, merge cache, deduplicate, filter deletions, sort, limit, fetch profiles
// Use standard process with index event ID
result , err := ws . client . ProcessEventsWithCache ( ctx , ws . wiki Kind, displayLimit , make ( map [ string ] * nostr . Event ) , primaryRelay , index . Event . ID , ws . indexKind )
result , err := ws . client . ProcessEventsWithCache ( ctx , target Kind, displayLimit , make ( map [ string ] * nostr . Event ) , primaryRelay , index . Event . ID , ws . indexKind )
if err != nil {
if err != nil {
logger . WithField ( "error" , err ) . Warn ( "Failed to fetch wiki events using ProcessEventsWithCache" )
return nil , fmt . Errorf ( "failed to fetch events using ProcessEventsWithCache: %w" , err )
return nil , err
}
}
allEvents := result . Events
logger . WithFields ( map [ string ] interface { } {
"fetched" : len ( allEvents ) ,
"expected" : len ( expectedItems ) ,
} ) . Debug ( "Fetched wiki events using ProcessEventsWithCache with index" )
// Build event map by kind:pubkey:dtag for matching
// Build event map by kind:pubkey:dtag for matching
eventMap := make ( map [ string ] * nostr . Event )
eventMap := make ( map [ string ] * nostr . Event )
for _ , event := range allEvents {
for _ , event := range result . Events {
// Extract d-tag from event
dTag := getDTag ( event . Tags )
var dTag string
for _ , tag := range event . Tags {
if len ( tag ) > 0 && tag [ 0 ] == "d" && len ( tag ) > 1 {
dTag = tag [ 1 ]
break
}
}
if dTag == "" {
if dTag == "" {
continue // Skip events without d-tag
continue // Skip events without d-tag
}
}
@ -145,6 +128,24 @@ func (ws *WikiService) FetchWikiEvents(ctx context.Context, index *IndexEvent) (
}
}
}
}
logger . WithFields ( map [ string ] interface { } {
"fetched" : len ( result . Events ) ,
"matched" : len ( eventMap ) ,
"expected" : len ( expectedItems ) ,
"kind" : targetKind ,
} ) . Debug ( "Fetched and matched events from index" )
return eventMap , nil
}
// FetchWikiEvents fetches all wiki events referenced in an index
// Uses ProcessEventsWithCache for the initial fetch, then filters by index items
func ( ws * WikiService ) FetchWikiEvents ( ctx context . Context , index * IndexEvent ) ( [ ] * WikiEvent , error ) {
eventMap , err := ws . fetchIndexEventsByKind ( ctx , index , ws . wikiKind )
if err != nil {
return nil , err
}
// Convert matched events to wiki events, preserving order from index.Items
// Convert matched events to wiki events, preserving order from index.Items
var wikiEvents [ ] * WikiEvent
var wikiEvents [ ] * WikiEvent
for _ , item := range index . Items {
for _ , item := range index . Items {
@ -166,11 +167,6 @@ func (ws *WikiService) FetchWikiEvents(ctx context.Context, index *IndexEvent) (
wikiEvents = append ( wikiEvents , wiki )
wikiEvents = append ( wikiEvents , wiki )
}
}
logger . WithFields ( map [ string ] interface { } {
"matched" : len ( wikiEvents ) ,
"expected" : len ( expectedItems ) ,
} ) . Debug ( "Matched wiki events" )
if len ( wikiEvents ) == 0 && len ( index . Items ) > 0 {
if len ( wikiEvents ) == 0 && len ( index . Items ) > 0 {
logger . WithField ( "items" , len ( index . Items ) ) . Warn ( "No wiki events matched from fetched events" )
logger . WithField ( "items" , len ( index . Items ) ) . Warn ( "No wiki events matched from fetched events" )
}
}
@ -218,72 +214,11 @@ func (ws *WikiService) FetchIndexEvents(ctx context.Context, index *IndexEvent,
return nil , fmt . Errorf ( "unsupported event kind: %d (only %v are supported)" , targetKind , ws . articleKinds )
return nil , fmt . Errorf ( "unsupported event kind: %d (only %v are supported)" , targetKind , ws . articleKinds )
}
}
// Build a map of expected items (kind:pubkey:dtag) for fast lookup
eventMap , err := ws . fetchIndexEventsByKind ( ctx , index , targetKind )
expectedItems := make ( map [ string ] IndexItem )
for _ , item := range index . Items {
if item . Kind == targetKind {
key := fmt . Sprintf ( "%d:%s:%s" , item . Kind , item . Pubkey , item . DTag )
expectedItems [ key ] = item
}
}
if len ( expectedItems ) == 0 {
return [ ] * nostr . Event { } , nil
}
// Use ProcessEventsWithCache to fetch events of this kind
// Use a high display limit (1000) to ensure we get all events referenced in the index
// This means we'll fetch 2000 events, which should be enough for most cases
displayLimit := 1000
primaryRelay := ws . client . GetPrimaryRelay ( )
if primaryRelay == "" {
return nil , fmt . Errorf ( "primary relay not configured" )
}
logger . WithFields ( map [ string ] interface { } {
"kind" : targetKind ,
"items" : len ( expectedItems ) ,
"index_event_id" : index . Event . ID ,
} ) . Debug ( "Fetching events using ProcessEventsWithCache with index" )
// Use standard process with index event ID: fetch index, query only referenced events, merge cache, deduplicate, filter deletions, sort, limit, fetch profiles
result , err := ws . client . ProcessEventsWithCache ( ctx , targetKind , displayLimit , make ( map [ string ] * nostr . Event ) , primaryRelay , index . Event . ID , ws . indexKind )
if err != nil {
if err != nil {
logger . WithField ( "error" , err ) . Warn ( "Failed to fetch events using ProcessEventsWithCache" )
return nil , err
return nil , err
}
}
allEvents := result . Events
logger . WithFields ( map [ string ] interface { } {
"fetched" : len ( allEvents ) ,
"expected" : len ( expectedItems ) ,
} ) . Debug ( "Fetched events using ProcessEventsWithCache with index" )
// Build event map by kind:pubkey:dtag for matching
eventMap := make ( map [ string ] * nostr . Event )
for _ , event := range allEvents {
// Extract d-tag from event
var dTag string
for _ , tag := range event . Tags {
if len ( tag ) > 0 && tag [ 0 ] == "d" && len ( tag ) > 1 {
dTag = tag [ 1 ]
break
}
}
if dTag == "" {
continue // Skip events without d-tag
}
key := fmt . Sprintf ( "%d:%s:%s" , event . Kind , event . PubKey , dTag )
// Keep the newest version if we have multiple
existing , exists := eventMap [ key ]
if ! exists || event . CreatedAt > existing . CreatedAt {
eventMap [ key ] = event
}
}
// Convert to result slice, preserving order from index.Items
// Convert to result slice, preserving order from index.Items
events := make ( [ ] * nostr . Event , 0 , len ( eventMap ) )
events := make ( [ ] * nostr . Event , 0 , len ( eventMap ) )
for _ , item := range index . Items {
for _ , item := range index . Items {
@ -298,12 +233,6 @@ func (ws *WikiService) FetchIndexEvents(ctx context.Context, index *IndexEvent,
events = append ( events , event )
events = append ( events , event )
}
}
logger . WithFields ( map [ string ] interface { } {
"matched" : len ( events ) ,
"expected" : len ( expectedItems ) ,
"kind" : targetKind ,
} ) . Debug ( "Matched index events" )
if len ( events ) == 0 && len ( index . Items ) > 0 {
if len ( events ) == 0 && len ( index . Items ) > 0 {
logger . WithFields ( map [ string ] interface { } {
logger . WithFields ( map [ string ] interface { } {
"kind" : targetKind ,
"kind" : targetKind ,