cleanup-kind3.go raw
1 //go:build !(js && wasm)
2
3 package database
4
5 import (
6 "context"
7 "time"
8
9 "next.orly.dev/pkg/nostr/encoders/filter"
10 "next.orly.dev/pkg/nostr/encoders/kind"
11 "next.orly.dev/pkg/lol/chk"
12 "next.orly.dev/pkg/lol/log"
13 )
14
15 // CleanupKind3WithoutPTags scans for kind 3 follow list events that have no p tags
16 // and deletes them. This cleanup is needed because the directory spider may have
17 // saved malformed events that lost their tags during serialization.
18 func (d *D) CleanupKind3WithoutPTags(ctx context.Context) error {
19 log.I.F("database: starting cleanup of kind 3 events without p tags")
20
21 startTime := time.Now()
22
23 // Query for all kind 3 events
24 f := &filter.F{
25 Kinds: kind.NewS(kind.FollowList),
26 }
27
28 events, err := d.QueryEvents(ctx, f)
29 if chk.E(err) {
30 return err
31 }
32
33 deletedCount := 0
34
35 // Check each event for p tags
36 for _, ev := range events {
37 hasPTag := false
38
39 if ev.Tags != nil && ev.Tags.Len() > 0 {
40 // Look for at least one p tag
41 for _, tag := range *ev.Tags {
42 if tag != nil && tag.Len() >= 2 {
43 key := tag.Key()
44 if len(key) == 1 && key[0] == 'p' {
45 hasPTag = true
46 break
47 }
48 }
49 }
50 }
51
52 // Delete events without p tags
53 if !hasPTag {
54 log.W.F("database: deleting kind 3 event without p tags from pubkey %x", ev.Pubkey)
55 if err := d.DeleteEvent(ctx, ev.ID); chk.E(err) {
56 log.E.F("database: failed to delete kind 3 event %x: %v", ev.ID, err)
57 continue
58 }
59 deletedCount++
60 }
61 }
62
63 duration := time.Since(startTime)
64
65 if deletedCount > 0 {
66 log.I.F("database: cleanup completed in %v - deleted %d kind 3 events without p tags (scanned %d total)",
67 duration, deletedCount, len(events))
68 } else {
69 log.I.F("database: cleanup completed in %v - no kind 3 events needed deletion (scanned %d total)",
70 duration, len(events))
71 }
72
73 return nil
74 }
75