From 79e5d60751e8e033f83105c3568392cd994fff71 Mon Sep 17 00:00:00 2001 From: ice-cronus <105345303+ice-cronus@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:53:59 +0300 Subject: [PATCH] fix comments, rollback messed events validations, removed tests checking existence of event links in db --- cmd/seeder/README.md | 7 +- cmd/seeder/fetcher.go | 150 ++++++++++++++++++++----- cmd/seeder/images.go | 190 ++++++++++++++++++++++++++++++++ cmd/seeder/seeder.go | 11 +- database/query/query.go | 30 ----- database/query/query_test.go | 125 --------------------- go.mod | 17 ++- go.sum | 113 +++++++++++++++++-- server/ws/subscriptions_test.go | 46 ++++++-- 9 files changed, 474 insertions(+), 215 deletions(-) create mode 100644 cmd/seeder/images.go diff --git a/cmd/seeder/README.md b/cmd/seeder/README.md index 908dbe8..d71fcd7 100644 --- a/cmd/seeder/README.md +++ b/cmd/seeder/README.md @@ -1,10 +1,11 @@ Tool to seed the relay with data Sample call: ```bash -seeder --relays=wss://relay.damus.io/ --outputRelay=wss://localhost:9998 --profilesCount=1000 --threads=100 --perUser=100 +seeder --relays=wss://relay.damus.io/ --outputRelay=wss://localhost:9998 --profilesCount=1000 --threads=100 --perUser=100 --uploadKey=... ``` Params: -* relays = relay list to fetch data from +* relays = relay list to fetch data from (multiple can be passed like --relays=wss://relay.damus.io/ --relays=wss://strfry.iris.to/) * outputRelay = relay to write data to * profilesCount = count of profiles to fetch -* perUser = count of posts / articles to fetch for each user \ No newline at end of file +* perUser = count of posts / articles to fetch for each user +* uploadKey = imgbb free api key to host random webp images if user dont have any, if not provided - default image urls are rotated \ No newline at end of file diff --git a/cmd/seeder/fetcher.go b/cmd/seeder/fetcher.go index 9dc1d3c..5e5a0ac 100644 --- a/cmd/seeder/fetcher.go +++ b/cmd/seeder/fetcher.go @@ -7,12 +7,15 @@ import ( "encoding/json" "fmt" "log" + "net/http" "sync" "sync/atomic" "time" + "github.com/0x6flab/namegenerator" + "github.com/JohnNON/ImgBB" "github.com/alitto/pond" - "github.com/gookit/goutil/errorx" + "github.com/cockroachdb/errors" "github.com/nbd-wtf/go-nostr" "github.com/ice-blockchain/subzero/model" @@ -23,24 +26,29 @@ type ( StartFetching(ctx context.Context) } fetcher struct { - relays [][]*nostr.Relay - outputRelays []*nostr.Relay - outputLBIdx uint64 - profiles int - perUser int - threads int + relays [][]*nostr.Relay + outputRelays []*nostr.Relay + outputLBIdx uint64 + imgsLBIndex uint64 + profiles int + perUser int + threads int + uploadKey string + webpUploadClient *imgbb.Client } ) const concurrentReqs = 10 -func NewFetcher(ctx context.Context, relayUrls []string, threads, profiles, perUser int, output string) Fetcher { +func NewFetcher(ctx context.Context, relayUrls []string, threads, profiles, perUser int, output, uploadApiKey string) Fetcher { f := &fetcher{ - relays: make([][]*nostr.Relay, 0, len(relayUrls)), - outputRelays: make([]*nostr.Relay, 0, threads), - profiles: profiles, - perUser: perUser, - threads: threads, + relays: make([][]*nostr.Relay, 0, len(relayUrls)), + outputRelays: make([]*nostr.Relay, 0, threads), + profiles: profiles, + perUser: perUser, + threads: threads, + uploadKey: uploadApiKey, + webpUploadClient: imgbb.NewClient(http.DefaultClient, uploadApiKey), } for _ = range threads { relay, err := connectToRelay(ctx, output) @@ -49,7 +57,7 @@ func NewFetcher(ctx context.Context, relayUrls []string, threads, profiles, perU } f.outputRelays = append(f.outputRelays, relay) } - log.Println(fmt.Sprintf("Established %v conns to %v", threads, output)) + log.Printf("Established %v conns to %v", threads, output) for _, relayUrl := range relayUrls { rels := make([]*nostr.Relay, 0, threads/concurrentReqs) @@ -128,11 +136,17 @@ func (f *fetcher) mustFetchUsers(ctx context.Context, profiles int, relayConns [ } if profile, ok := <-eventAuthor; ok { e := &model.Event{Event: *profile} - if e.Validate() == nil { + privKey := nostr.GeneratePrivateKey() + updated, pErr := f.populateProfile(ctx, e, privKey) + if e.Validate() == nil && pErr == nil { if aErr := f.AcceptEvent(ctx, e); aErr != nil { log.Fatal(aErr) } - f.fetchUserContent(ctx, ev.PubKey, relayConns[idx]) + var remapEventsToKey string + if updated { + remapEventsToKey = privKey + } + f.fetchUserContent(ctx, ev.PubKey, relayConns[idx], remapEventsToKey) atomic.AddUint64(&profilesProcessed, 1) } } @@ -141,7 +155,7 @@ func (f *fetcher) mustFetchUsers(ctx context.Context, profiles int, relayConns [ } pool.StopAndWait() } -func (f *fetcher) fetchUserContent(ctx context.Context, userKey string, relay *nostr.Relay) { +func (f *fetcher) fetchUserContent(ctx context.Context, userKey string, relay *nostr.Relay, remapEventsToKey string) { events, err := relay.QueryEvents(ctx, nostr.Filter{ Kinds: []int{nostr.KindTextNote, nostr.KindArticle, nostr.KindReaction, nostr.KindRepost}, Authors: []string{userKey}, @@ -154,11 +168,11 @@ func (f *fetcher) fetchUserContent(ctx context.Context, userKey string, relay *n for ev := range events { evList = append(evList, ev) } - eventsCount := f.fetchLinkedAndProcessEvents(ctx, evList, relay) + eventsCount := f.fetchLinkedAndProcessEvents(ctx, evList, relay, userKey, remapEventsToKey) fmt.Println(relay.URL, userKey, eventsCount) } -func (f *fetcher) fetchLinkedAndProcessEvents(ctx context.Context, events []*nostr.Event, relay *nostr.Relay) int { +func (f *fetcher) fetchLinkedAndProcessEvents(ctx context.Context, events []*nostr.Event, relay *nostr.Relay, user, remapEventsToKey string) int { repliesAndReactionsGroupedByRelay := map[string][]string{} repostedEventsGroupedByRelay := map[string][]string{} eventsAndReplies := map[string]*nostr.Event{} @@ -184,16 +198,34 @@ func (f *fetcher) fetchLinkedAndProcessEvents(ctx context.Context, events []*nos if len(repliesAndReactionsGroupedByRelay) > 0 { evCount += f.fetchLinkedEvents(ctx, relay, repliesAndReactionsGroupedByRelay, func(evID string) { delete(eventsAndReplies, evID) - }) + }, user, remapEventsToKey) } if len(repostedEventsGroupedByRelay) > 0 { evCount += f.fetchLinkedEvents(ctx, relay, repostedEventsGroupedByRelay, func(evID string) { delete(eventsAndReplies, evID) - }) + }, user, remapEventsToKey) } + var profileEventForUpdatedReactions model.Event + var privKey string for _, ev := range eventsAndReplies { e := &model.Event{Event: *ev} - if e.Validate() == nil { + if !validKind(e) { + continue + } + if remapEventsToKey != "" { + if e.PubKey == user { + e.ID = "" + if err := e.Sign(remapEventsToKey); err != nil { + log.Fatal(err) + } + } + } + if e.Kind == nostr.KindReaction && e.Content != "+" && e.Content != "-" && e.Content != "" { + if err := f.updateReaction(ctx, e, &profileEventForUpdatedReactions, &privKey); err != nil { + continue + } + } + if err := e.Validate(); err == nil { if aErr := f.AcceptEvent(ctx, e); aErr != nil { log.Fatal(aErr) } @@ -202,8 +234,10 @@ func (f *fetcher) fetchLinkedAndProcessEvents(ctx context.Context, events []*nos } return evCount } - -func (f *fetcher) fetchLinkedEvents(ctx context.Context, currentRelay *nostr.Relay, groupedByRelay map[string][]string, onFailure func(evID string)) int { +func validKind(e *model.Event) bool { + return e.Kind == nostr.KindTextNote || e.Kind == nostr.KindArticle || e.Kind == nostr.KindReaction || e.Kind == nostr.KindRepost +} +func (f *fetcher) fetchLinkedEvents(ctx context.Context, currentRelay *nostr.Relay, groupedByRelay map[string][]string, onFailure func(evID string), userKey, remapEventsToKey string) int { evCount := 0 for relayUrl, eventsFromRelay := range groupedByRelay { origEvents, oErr := f.fetchPost(ctx, eventsFromRelay, relayUrl, currentRelay) @@ -218,7 +252,7 @@ func (f *fetcher) fetchLinkedEvents(ctx context.Context, currentRelay *nostr.Rel evList = append(evList, ev) } if len(evList) > 0 { - evCount += f.fetchLinkedAndProcessEvents(ctx, evList, currentRelay) + evCount += f.fetchLinkedAndProcessEvents(ctx, evList, currentRelay, userKey, remapEventsToKey) } } return evCount @@ -249,14 +283,14 @@ func (f *fetcher) fetchPost(ctx context.Context, events []string, relayUrl strin }() r, err = connectToRelay(connCtx, relayUrl) if err != nil { - return nil, errorx.Withf(err, "failed to connect to %v", relayUrl) + return nil, errors.Wrapf(err, "failed to connect to %v", relayUrl) } } fetchedEvents, err := queryEvents(ctx, r, nostr.Filter{ IDs: events, }) if err != nil { - return nil, errorx.Withf(err, "failed to fetch original posts for replies %#v from %v", events, relayUrl) + return nil, errors.Wrapf(err, "failed to fetch original posts for replies %#v from %v", events, relayUrl) } return fetchedEvents, err } @@ -264,7 +298,67 @@ func (f *fetcher) fetchPost(ctx context.Context, events []string, relayUrl strin func queryEvents(ctx context.Context, r *nostr.Relay, filter nostr.Filter) (chan *nostr.Event, error) { fetchedEvents, err := r.QueryEvents(ctx, filter) if err != nil { - return fetchedEvents, errorx.Withf(err, "failed to query events from %v", r.URL) + return fetchedEvents, errors.Wrapf(err, "failed to query events from %v", r.URL) } return fetchedEvents, nil } + +func (f *fetcher) populateProfile(ctx context.Context, e *model.Event, privKey string) (bool, error) { + //return false, nil + var parsedContent model.ProfileMetadataContent + if err := json.Unmarshal([]byte(e.Content), &parsedContent); err != nil { + return false, errors.Wrapf(model.ErrWrongEventParams, "nip-01,nip-24: wrong json fields for: %+v", e) + } + updated := false + if parsedContent.Name == "" { + parsedContent.Name = namegenerator.NewGenerator().Generate() + updated = true + } + if parsedContent.About == "" { + parsedContent.About = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." + updated = true + } + if parsedContent.Picture == "" { + var err error + if parsedContent.Picture, err = f.generateProfilePhoto(ctx, parsedContent.Name); err != nil { + return false, errors.Wrapf(err, "failed to gen random photo") + } + } + if updated { + b, err := json.Marshal(parsedContent) + if err != nil { + return false, errors.Wrapf(err, "failed to populate profile with random data") + } + e.Content = string(b) + pubKey, _ := nostr.GetPublicKey(privKey) + fmt.Println("RESIGNED ", e.PubKey, "TO ", pubKey) + e.ID = "" + if err = e.Sign(privKey); err != nil { + return false, errors.Wrapf(err, "failed to re-sign profile with random data") + } + } + return updated, nil +} + +func (f *fetcher) updateReaction(ctx context.Context, e *model.Event, profileEvent *model.Event, privKey *string) error { + *privKey = nostr.GeneratePrivateKey() + reaction := e.Content + e.Content = "+" + if err := e.Sign(*privKey); err != nil { + return errors.Wrapf(err, "failed to sign event with updated reaction") + } + if profileEvent == nil { + *profileEvent = model.Event{Event: nostr.Event{ + CreatedAt: nostr.Now(), + Kind: nostr.KindProfileMetadata, + Content: "{}", + }} + if _, err := f.populateProfile(ctx, profileEvent, *privKey); err == nil { + if err = f.AcceptEvent(ctx, profileEvent); err != nil { + return errors.Wrapf(err, "failed to accept event with author of updated reaction") + } + fmt.Printf("UPDATED REACTION %v TO %v", reaction, e.Content) + } + } + return nil +} diff --git a/cmd/seeder/images.go b/cmd/seeder/images.go new file mode 100644 index 0000000..9086b61 --- /dev/null +++ b/cmd/seeder/images.go @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: ice License 1.0 + +package main + +import ( + "context" + "io" + "net/http" + "sync/atomic" + + imgbb "github.com/JohnNON/ImgBB" + "github.com/davidbyttow/govips/v2/vips" + "github.com/pkg/errors" +) + +var images []string = []string{ + "https://i.ibb.co/jJYm4Nz/rena2019.webp", + "https://i.ibb.co/dcCfp6j/mantanweb-rss-bot.webp", + "https://i.ibb.co/sFbNpww/China-s-Reevaluation-of-Taiwan-Seizure-Plans-After-Iran-s-Failed-Attack-on-Israel.webp", + "https://i.ibb.co/k60YSCN/dfs.webp", + "https://i.ibb.co/thS82gL/Discovering-America-s-Hidden-Gems-Where-to-Mine-Diamonds-and-Gemstones.webp", + "https://i.ibb.co/5hJcD1g/ASML-s-Disappointing-Results-Cause-Tech-Stocks-to-Slump-in-Europe.webp", + "https://i.ibb.co/F7xk7ks/Solliday-Teichmann.webp", + "https://i.ibb.co/ZJ0NJTM/Lady-Gaga.webp", + "https://i.ibb.co/9yNxF37/Tamarra-Maillet.webp", + "https://i.ibb.co/vqwMGrf/Noob.webp", + "https://i.ibb.co/09PTcf1/Khush.webp", + "https://i.ibb.co/mysnWys/ljq8888001.webp", + "https://i.ibb.co/j8pwLZ4/Philip-Gouda-alias.webp", + "https://i.ibb.co/KXD02Km/Air.webp", + "https://i.ibb.co/3pGgHYj/11planning.webp", + "https://i.ibb.co/3FRHNRG/Josianebih.webp", + "https://i.ibb.co/vV7Bvsn/sms.webp", + "https://i.ibb.co/QrpYWS3/Colin.webp", + "https://i.ibb.co/T25ppGB/10-minute-bitcoin-fee-bot.webp", + "https://i.ibb.co/xKvd726/SandRock.webp", + "https://i.ibb.co/FKGRZpZ/image.webp", + "https://i.ibb.co/xYj14wF/AUD-Exchange-Rate-Reacts-to-US-Inflation-Data-Australian-Unemployment-Forecast-and-PMIs.webp", + "https://i.ibb.co/nLYBkCN/drikkes.webp", + "https://i.ibb.co/VCc7Bng/Asian-Stocks-Rise-Despite-Concerns-Over-US-Economy.webp", + "https://i.ibb.co/n6hz8nT/Lelouch-VI-Britania.webp", + "https://i.ibb.co/LZrHc8y/5-minute-bitcoin-fee-bot.webp", + "https://i.ibb.co/3SVpZTj/Varian-Thode.webp", + "https://i.ibb.co/wSWz2kN/Discovering-America-s-Hidden-Gems-Where-to-Mine-Diamonds-and-Gemstones.webp", + "https://i.ibb.co/drf8h9B/China-s-Reevaluation-of-Taiwan-Seizure-Plans-After-Iran-s-Failed-Attack-on-Israel.webp", + "https://i.ibb.co/TBL6xn6/ASML-s-Disappointing-Results-Cause-Tech-Stocks-to-Slump-in-Europe.webp", + "https://i.ibb.co/pyQBzgN/dfs.webp", + "https://i.ibb.co/zZJrqnX/Demaris-Sindoni.webp", + "https://i.ibb.co/X344Tvf/Lady-Gaga.webp", + "https://i.ibb.co/HPg2zcS/Szekely-Gigliotti.webp", + "https://i.ibb.co/GHGqL84/image.webp", + "https://i.ibb.co/n8cTZrm/Noob.webp", + "https://i.ibb.co/CV0Pk1t/Khush.webp", + "https://i.ibb.co/MkdRCNB/ljq8888001.webp", + "https://i.ibb.co/FK5cvVS/Philip-Gouda-alias.webp", + "https://i.ibb.co/2sVZ6LS/Air.webp", + "https://i.ibb.co/C78cMhW/11planning.webp", + "https://i.ibb.co/mRDKN01/sms.webp", + "https://i.ibb.co/tPk149t/Josianebih.webp", + "https://i.ibb.co/4mQ6HMY/Colin.webp", + "https://i.ibb.co/VpBR6p2/Vlado-Stoll.webp", + "https://i.ibb.co/Dpj0T8s/10-minute-bitcoin-fee-bot.webp", + "https://i.ibb.co/YfBzMDc/AUD-Exchange-Rate-Reacts-to-US-Inflation-Data-Australian-Unemployment-Forecast-and-PMIs.webp", + "https://i.ibb.co/0f2Bh1d/Asian-Stocks-Rise-Despite-Concerns-Over-US-Economy.webp", + "https://i.ibb.co/BZQCgDZ/5-minute-bitcoin-fee-bot.webp", + "https://i.ibb.co/8KMQBsG/Uhlir-Bloodsworth.webp", + "https://i.ibb.co/6NK7K8H/Waichi-Hatcher.webp", + "https://i.ibb.co/Kzdn6rW/Golub-Cafaro.webp", + "https://i.ibb.co/FgBNXR5/Culbert-Woodby.webp", + "https://i.ibb.co/LpCHCbW/Loper-Kuennen.webp", + "https://i.ibb.co/zs0m9DQ/Pickerill-Merla.webp", + "https://i.ibb.co/x89zprb/Ringley-Asche.webp", + "https://i.ibb.co/0Qn2fMg/Marloes-Varvel.webp", + "https://i.ibb.co/TWGRKrR/Marchione-Leonhard.webp", + "https://i.ibb.co/0tCRzfx/Psencik-Gretal.webp", + "https://i.ibb.co/BzdzCvN/Kading-Goerke.webp", + "https://i.ibb.co/wwZqcK6/Womac-Poehlman.webp", + "https://i.ibb.co/Q8XR3zh/Balash-Badeaux.webp", + "https://i.ibb.co/NprRrp0/Steinfeld-Katerina.webp", + "https://i.ibb.co/txJLnCx/Pizarro-Bumpas.webp", + "https://i.ibb.co/qjTL6Zn/Huerta-Aimil.webp", + "https://i.ibb.co/v1wRxLv/Lienhard-Scotten.webp", + "https://i.ibb.co/g6sBxS2/Majure-Rickson.webp", + "https://i.ibb.co/t8hqP9G/Carringer-Trude.webp", + "https://i.ibb.co/dWY0L0Y/Bruck-Billeter.webp", + "https://i.ibb.co/Gd037zy/Precht-Hughette.webp", + "https://i.ibb.co/s5wxjvj/Malczewski-Boecker.webp", + "https://i.ibb.co/2y4BpZH/Peckenpaugh-Heddi.webp", + "https://i.ibb.co/qkSD52B/Tay-Gleave.webp", + "https://i.ibb.co/FXVgS14/Deitz-Crotteau.webp", + "https://i.ibb.co/VCFz0H0/Vin-Hazelton.webp", + "https://i.ibb.co/mv1sM62/Liberato-Sistare.webp", + "https://i.ibb.co/HzZGLdF/Parrot-Saindon.webp", + "https://i.ibb.co/ydjncGG/Jessup-Ibarra.webp", + "https://i.ibb.co/GWYVb2H/Vanosdol-Blau.webp", + "https://i.ibb.co/jDHnTKc/Fujimoto-Forsell.webp", + "https://i.ibb.co/jTsT5dn/Lupa-Saurer.webp", + "https://i.ibb.co/VpzzMmD/Bustard-Poquette.webp", + "https://i.ibb.co/59K14M0/Hink-Crago.webp", + "https://i.ibb.co/QvCdGgg/Pawlak-Dobbs.webp", + "https://i.ibb.co/s6RQPCH/Sewall-Kokoszka.webp", + "https://i.ibb.co/v17yrNY/Serino-Frels.webp", + "https://i.ibb.co/7YYyfnW/Semple-Frisina.webp", + "https://i.ibb.co/R3Znjf1/Rumpel-Stefanic.webp", + "https://i.ibb.co/Lhr0TR5/Radford-Simmons.webp", + "https://i.ibb.co/nnThhjL/Wind-Pinkos.webp", + "https://i.ibb.co/5GcR8vs/Heard-Halperin.webp", + "https://i.ibb.co/y5tWmvY/Reeds-Porth.webp", + "https://i.ibb.co/qFNT9bc/Roode-Muckenfuss.webp", + "https://i.ibb.co/tXJ0Z3K/Koehn-Hertlein.webp", + "https://i.ibb.co/y4V0WMq/Cristen-Leitz.webp", + "https://i.ibb.co/s3CKrfL/Valverde-Tribe.webp", + "https://i.ibb.co/swYdYwT/Earll-Abrahamian.webp", + "https://i.ibb.co/TrXX6nM/Tani-Reddoch.webp", + "https://i.ibb.co/Qj5NpMx/Lenoir-Roseanna.webp", + "https://i.ibb.co/NSPPRCP/Zenger-Slaten.webp", + "https://i.ibb.co/Kw3zzY7/Ferg-Whiten.webp", + "https://i.ibb.co/23Lp9ZY/Storck-Timmer.webp", + "https://i.ibb.co/C1k8jbG/Chappel-Clouser.webp", + "https://i.ibb.co/dfsShW2/Lennard-Audwin.webp", + "https://i.ibb.co/H7DYhcR/Mavra-Rosin.webp", + "https://i.ibb.co/sRpNdJY/Lukasik-Zenas.webp", + "https://i.ibb.co/Yh46yHb/Petrucelli-Stallard.webp", + "https://i.ibb.co/sCzwjBw/Shelstad-Bellinger.webp", + "https://i.ibb.co/d4z7KMX/Salmela-Rolando.webp", + "https://i.ibb.co/NFdFmpR/Iida-Sage.webp", + "https://i.ibb.co/27gSnwY/Mctague-Joly.webp", + "https://i.ibb.co/R2mXsLW/Linsky-Valasek.webp", + "https://i.ibb.co/GQqpxxY/Mobbs-Drum.webp", + "https://i.ibb.co/ZS2Hdp0/Rogacki-Piraino.webp", + "https://i.ibb.co/fNfznX7/Yuhasz-Speckman.webp", + "https://i.ibb.co/zskcnrv/Engelke-Kurilla.webp", + "https://i.ibb.co/hWPyZHG/Rundquist-Dzik.webp", + "https://i.ibb.co/gV53bzN/Novelia-Kazarian.webp", + "https://i.ibb.co/vXmfTKz/Vayda-Scarpulla.webp", + "https://i.ibb.co/jwtrX5j/Amer-Younkins.webp", + "https://i.ibb.co/5BhGmwd/Digiacomo-Coley.webp", + "https://i.ibb.co/qgnzxQc/Covault-Oyster.webp", + "https://i.ibb.co/V9sm0bp/Hephzibah-Ritson.webp", + "https://i.ibb.co/d2FwwYM/Nial-Zuchowski.webp", + "https://i.ibb.co/VmRzrMJ/Stringham-Lerner.webp", + "https://i.ibb.co/M6n6vdW/Nesbitt-Deschene.webp", + "https://i.ibb.co/yWqbhGG/Osaki-Eberhardt.webp", + "https://i.ibb.co/SQk1gdV/Linderman-Strom.webp", +} + +func (f *fetcher) generateProfilePhoto(ctx context.Context, name string) (string, error) { + if f.uploadKey == "" { + idx := atomic.AddUint64(&f.imgsLBIndex, 1) % uint64(len(images)) + return images[idx], nil + } + req, err := http.NewRequestWithContext(ctx, "GET", "https://thispersondoesnotexist.com/", nil) + if err != nil { + return "", errors.Wrapf(err, "failed to generate random photo") + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", errors.Wrapf(err, "failed to generate random photo") + } + if resp.StatusCode != http.StatusOK { + return "", errors.Errorf("status %v on getting random photo", resp.StatusCode) + } + defer resp.Body.Close() + jpeg, err := io.ReadAll(resp.Body) + if err != nil { + return "", errors.Wrapf(err, "failed to read random photo") + } + im, err := vips.NewImageFromBuffer(jpeg) + if err != nil { + return "", errors.Wrapf(err, "failed to load random photo") + } + webpData, _, err := im.ExportWebp(&vips.WebpExportParams{ + StripMetadata: true, + Quality: 80, + Lossless: false, + }) + if err != nil { + return "", errors.Wrapf(err, "failed to convert random photo to webp") + } + img, _ := imgbb.NewImageFromFile(name, 3*30*24*60, webpData) + uplResp, err := f.webpUploadClient.Upload(ctx, img) + if err != nil { + return "", errors.Wrapf(err, "failed to upload image") + } + if uplResp.Success { + return uplResp.Data.URL, nil + } else { + return "", errors.Errorf("failed to upload image: %v", uplResp.StatusCode) + } +} diff --git a/cmd/seeder/seeder.go b/cmd/seeder/seeder.go index ac6821d..9554760 100644 --- a/cmd/seeder/seeder.go +++ b/cmd/seeder/seeder.go @@ -6,6 +6,7 @@ import ( "context" "log" + "github.com/davidbyttow/govips/v2/vips" "github.com/spf13/cobra" ) @@ -15,13 +16,18 @@ var ( threads int relays []string outputRelay string + uploadKey string seeder = &cobra.Command{ Use: "seeder", Short: "seeder", Run: func(_ *cobra.Command, args []string) { ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - f := NewFetcher(ctx, relays, threads, profilesCount, perUser, outputRelay) + defer func() { + cancel() + vips.Shutdown() + }() + vips.Startup(&vips.Config{}) + f := NewFetcher(ctx, relays, threads, profilesCount, perUser, outputRelay, uploadKey) f.StartFetching(ctx) }, } @@ -31,6 +37,7 @@ var ( seeder.Flags().IntVar(&threads, "threads", profilesCount, "threads to import = profilesCount by default") seeder.Flags().StringArrayVar(&relays, "relays", make([]string, 0), "relays to fetch data from") seeder.Flags().StringVar(&outputRelay, "outputRelay", "", "relay to write data") + seeder.Flags().StringVar(&uploadKey, "uploadKey", "", "key to upload webp generated photo if user is miss ont") if err := seeder.MarkFlagRequired("outputRelay"); err != nil { log.Fatal(err) } diff --git a/database/query/query.go b/database/query/query.go index a52fb8a..18a2236 100644 --- a/database/query/query.go +++ b/database/query/query.go @@ -60,36 +60,6 @@ func (db *dbClient) AcceptEvent(ctx context.Context, event *model.Event) error { return db.saveEvent(ctx, event) } -func getReactionTargetEvent(ctx context.Context, db *dbClient, event *model.Event) (res *model.Event, err error) { - refs, err := model.ParseEventReference(event.Tags) - if err != nil { - return nil, errors.Wrap(err, "failed to detect events for delete") - } - filters := model.Filters{} - for _, r := range refs { - filters = append(filters, r.Filter()) - } - eLastTag := event.Tags.GetLast([]string{"e"}) - pLastTag := event.Tags.GetLast([]string{"p"}) - aTag := event.Tags.GetFirst([]string{"a"}) - kTag := event.Tags.GetFirst([]string{"k"}) - for ev, evErr := range db.SelectEvents(ctx, &model.Subscription{Filters: filters}) { - if evErr != nil { - return nil, errors.Wrapf(evErr, "can't select reaction events for:%+v", ev) - } - if ev == nil || (ev.IsReplaceable() && aTag.Value() != fmt.Sprintf("%v:%v:%v", ev.Kind, ev.PubKey, ev.Tags.GetD())) { - continue - } - if ev.ID != eLastTag.Value() || ev.PubKey != pLastTag.Value() || (kTag != nil && kTag.Value() != fmt.Sprint(ev.Kind)) { - continue - } - - return ev, nil - } - - return -} - func (db *dbClient) saveEvent(ctx context.Context, event *model.Event) error { const stmt = `insert or replace into events (kind, created_at, system_created_at, id, pubkey, sig, content, tags, d_tag, reference_id) diff --git a/database/query/query_test.go b/database/query/query_test.go index e42c74a..9e24e41 100644 --- a/database/query/query_test.go +++ b/database/query/query_test.go @@ -535,131 +535,6 @@ func TestNIP25ReactionEvents(t *testing.T) { require.NoError(t, err) require.Len(t, stored, 1) }) - t.Run("invalid: reaction to normal event e tag", func(t *testing.T) { - db := helperNewDatabase(t) - defer db.Close() - publishedEvent := &model.Event{ - Event: nostr.Event{ - ID: "normal" + uuid.NewString(), - PubKey: "bogus" + uuid.NewString(), - CreatedAt: nostr.Timestamp(time.Now().Unix()), - Kind: nostr.KindTextNote, - Tags: model.Tags{}, - Content: "bogus" + uuid.NewString(), - Sig: "bogus" + uuid.NewString(), - }, - } - require.NoError(t, db.AcceptEvent(ctx, publishedEvent)) - stored, err := helperGetStoredEventsAll(t, db, ctx, helperNewFilterSubscription(func(apply *model.Filter) { - apply.Kinds = []int{nostr.KindTextNote} - })) - require.NoError(t, err) - require.Len(t, stored, 1) - require.Contains(t, stored, publishedEvent) - var tags nostr.Tags - tags = append(tags, nostr.Tag{"e", publishedEvent.ID}, nostr.Tag{"e", "first"}, nostr.Tag{"e", "second"}) - tags = append(tags, nostr.Tag{"p", "first"}, nostr.Tag{"p", "second"}, nostr.Tag{"p", publishedEvent.PubKey}) - require.Error(t, db.AcceptEvent(ctx, &model.Event{ - Event: nostr.Event{ - ID: "reaction event" + uuid.NewString(), - PubKey: publishedEvent.PubKey, - CreatedAt: nostr.Timestamp(time.Now().Unix()), - Kind: nostr.KindReaction, - Tags: tags, - Content: "+", - Sig: "bogus" + uuid.NewString(), - }, - })) - stored, err = helperGetStoredEventsAll(t, db, ctx, helperNewFilterSubscription(func(apply *model.Filter) { - apply.Kinds = []int{nostr.KindReaction} - })) - require.NoError(t, err) - require.Empty(t, stored) - }) - t.Run("invalid: reaction to normal event p tag", func(t *testing.T) { - db := helperNewDatabase(t) - defer db.Close() - publishedEvent := &model.Event{ - Event: nostr.Event{ - ID: "normal" + uuid.NewString(), - PubKey: "bogus" + uuid.NewString(), - CreatedAt: nostr.Timestamp(time.Now().Unix()), - Kind: nostr.KindTextNote, - Tags: model.Tags{}, - Content: "bogus" + uuid.NewString(), - Sig: "bogus" + uuid.NewString(), - }, - } - require.NoError(t, db.AcceptEvent(ctx, publishedEvent)) - stored, err := helperGetStoredEventsAll(t, db, ctx, helperNewFilterSubscription(func(apply *model.Filter) { - apply.Kinds = []int{nostr.KindTextNote} - })) - require.NoError(t, err) - require.Len(t, stored, 1) - require.Contains(t, stored, publishedEvent) - var tags nostr.Tags - tags = append(tags, nostr.Tag{"e", "first"}, nostr.Tag{"e", "second"}, nostr.Tag{"e", publishedEvent.ID}) - tags = append(tags, nostr.Tag{"p", publishedEvent.PubKey}, nostr.Tag{"p", "first"}, nostr.Tag{"p", "second"}) - require.Error(t, db.AcceptEvent(ctx, &model.Event{ - Event: nostr.Event{ - ID: "reaction event" + uuid.NewString(), - PubKey: publishedEvent.PubKey, - CreatedAt: nostr.Timestamp(time.Now().Unix()), - Kind: nostr.KindReaction, - Tags: tags, - Content: "+", - Sig: "bogus" + uuid.NewString(), - }, - })) - stored, err = helperGetStoredEventsAll(t, db, ctx, helperNewFilterSubscription(func(apply *model.Filter) { - apply.Kinds = []int{nostr.KindReaction} - })) - require.NoError(t, err) - require.Empty(t, stored) - }) - t.Run("invalid: reaction to replaceable event with wrong a tag", func(t *testing.T) { - db := helperNewDatabase(t) - defer db.Close() - dTag := "dummy" - publishedEvent := &model.Event{ - Event: nostr.Event{ - ID: "normal" + uuid.NewString(), - PubKey: "bogus" + uuid.NewString(), - CreatedAt: nostr.Timestamp(time.Now().Unix()), - Kind: nostr.KindProfileMetadata, - Tags: model.Tags{}.AppendUnique(nostr.Tag{"d", dTag}), - Content: "bogus" + uuid.NewString(), - Sig: "bogus" + uuid.NewString(), - }, - } - require.NoError(t, db.AcceptEvent(ctx, publishedEvent)) - stored, err := helperGetStoredEventsAll(t, db, ctx, helperNewFilterSubscription(func(apply *model.Filter) { - apply.Kinds = []int{nostr.KindProfileMetadata} - })) - require.NoError(t, err) - require.Len(t, stored, 1) - require.Contains(t, stored, publishedEvent) - var tags nostr.Tags - tags = append(tags, nostr.Tag{"e", "first"}, nostr.Tag{"e", "second"}, nostr.Tag{"e", publishedEvent.ID}) - tags = append(tags, nostr.Tag{"p", "first"}, nostr.Tag{"p", "second"}, nostr.Tag{"p", publishedEvent.PubKey}) - tags = append(tags, nostr.Tag{"a", fmt.Sprintf("%v:%v:%v", nostr.KindProfileMetadata, publishedEvent.PubKey, "wrong d tag")}) - require.Error(t, db.AcceptEvent(ctx, &model.Event{ - Event: nostr.Event{ - ID: "reaction event" + uuid.NewString(), - PubKey: publishedEvent.PubKey, - CreatedAt: nostr.Timestamp(time.Now().Unix()), - Kind: nostr.KindReaction, - Tags: tags, - Content: "+", - Sig: "bogus" + uuid.NewString(), - }, - })) - stored, err = helperGetStoredEventsAll(t, db, ctx, helperNewFilterSubscription(func(apply *model.Filter) { - apply.Kinds = []int{nostr.KindReaction} - })) - require.NoError(t, err) - require.Empty(t, stored) - }) } func helperNewFilter(f func(apply *model.Filter)) model.Filter { diff --git a/go.mod b/go.mod index 30a5477..13075af 100644 --- a/go.mod +++ b/go.mod @@ -5,18 +5,22 @@ go 1.23.0 replace filippo.io/mkcert => github.com/kixelated/mkcert v1.4.4-days require ( + github.com/0x6flab/namegenerator v1.4.0 + github.com/JohnNON/ImgBB v1.0.2 github.com/alitto/pond v1.9.2 + github.com/cockroachdb/errors v1.11.3 + github.com/davidbyttow/govips/v2 v2.15.0 github.com/gin-contrib/cors v1.7.2 github.com/gin-gonic/gin v1.10.0 github.com/gobwas/httphead v0.1.0 github.com/gobwas/ws v1.4.0 github.com/google/uuid v1.6.0 - github.com/gookit/goutil v0.6.17 github.com/hashicorp/go-multierror v1.1.1 github.com/ice-blockchain/go/src v0.0.0-20240529122316-8d9458949bdd github.com/jamiealquiza/tachymeter v2.0.0+incompatible github.com/jmoiron/sqlx v1.4.0 github.com/mattn/go-sqlite3 v1.14.24 + github.com/mxschmitt/golang-combinations v1.2.0 github.com/nbd-wtf/go-nostr v0.38.2 github.com/pkg/errors v0.9.1 github.com/quic-go/quic-go v0.47.0 @@ -35,10 +39,13 @@ require ( github.com/bytedance/sonic/loader v0.2.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/getsentry/sentry-go v0.29.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -46,12 +53,14 @@ require ( github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/goccy/go-json v0.10.3 // indirect - github.com/google/pprof v0.0.0-20241008150032-332c0e1a4a34 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/pprof v0.0.0-20241009165004-a3522334989c // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -65,6 +74,7 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect @@ -74,7 +84,8 @@ require ( go.uber.org/mock v0.4.0 // indirect golang.org/x/arch v0.11.0 // indirect golang.org/x/crypto v0.28.0 // indirect - golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 // indirect + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + golang.org/x/image v0.21.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.30.0 // indirect golang.org/x/sync v0.8.0 // indirect diff --git a/go.sum b/go.sum index d3c2021..bf3b296 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/0x6flab/namegenerator v1.4.0 h1:QnkI813SZsI/hYnKD9pg3mkIlcYzCx0N4hnzb0YYME4= +github.com/0x6flab/namegenerator v1.4.0/go.mod h1:2sQzXuS6dX/KEwWtB6GJU729O3m4gBdD5oAU8hd0SyY= +github.com/JohnNON/ImgBB v1.0.2 h1:2FhbOAgelhzD4Pmk6sPxOTLiIFVXi9DWBYKxreLxSIc= +github.com/JohnNON/ImgBB v1.0.2/go.mod h1:mF5JpiFy6XV4tASLNj9wQK5/70bc+7/Hff2l/1noyRI= github.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs= github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= @@ -17,12 +21,20 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidbyttow/govips/v2 v2.15.0 h1:h3lF+rQElBzGXbQSSPqmE3XGySPhcQo2x3t5l/dZ+pU= +github.com/davidbyttow/govips/v2 v2.15.0/go.mod h1:3OQCHj0nf5Mnrplh5VlNvmx3IhJXyxbAoTJZPflUjmM= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= @@ -31,12 +43,16 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/getsentry/sentry-go v0.29.0 h1:YtWluuCFg9OfcqnaujpY918N/AhCCwarIDWOYSBAjCA= +github.com/getsentry/sentry-go v0.29.0/go.mod h1:jhPesDAL0Q0W2+2YEuVOvdWmVtdsr1+jtBrlDEVWwLY= github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -59,17 +75,15 @@ github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241008150032-332c0e1a4a34 h1:4iExbL0TFWhkSCZx6nfKwjM+CbnBySx18KssYmdL1fc= -github.com/google/pprof v0.0.0-20241008150032-332c0e1a4a34/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241009165004-a3522334989c h1:NDovD0SMpBYXlE1zJmS1q55vWB/fUQBcPAqAboZSccA= +github.com/google/pprof v0.0.0-20241009165004-a3522334989c/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= -github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= -github.com/gookit/goutil v0.6.17 h1:SxmbDz2sn2V+O+xJjJhJT/sq1/kQh6rCJ7vLBiRPZjI= -github.com/gookit/goutil v0.6.17/go.mod h1:rSw1LchE1I3TDWITZvefoAC9tS09SFu3lHXLCV7EaEY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -87,12 +101,16 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -115,14 +133,20 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mxschmitt/golang-combinations v1.2.0 h1:V5E7MncIK8Yr1SL/SpdqMuSquFsfoIs5auI7Y3n8z14= +github.com/mxschmitt/golang-combinations v1.2.0/go.mod h1:RCm5eR03B+JrBOMRDLsKZWShluXdrHu+qwhPEJ0miBM= github.com/nbd-wtf/go-nostr v0.38.2 h1:8PP+U8dx81jVEL89k/xMAejAlDeSDJ9ywNiyOj82so8= github.com/nbd-wtf/go-nostr v0.38.2/go.mod h1:TGKGj00BmJRXvRe0LlpDN3KKbELhhPXgBwUEhzu3Oq0= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -138,8 +162,9 @@ github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/schollz/progressbar/v3 v3.16.1 h1:RnF1neWZFzLCoGx8yp1yF7SDl4AzNDI5y4I0aUJRrZQ= github.com/schollz/progressbar/v3 v3.16.1/go.mod h1:I2ILR76gz5VXqYMIY/LdLecvMHDPVcQm3W/MSKi1TME= @@ -151,6 +176,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -170,39 +196,102 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4= golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw= -golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +golang.org/x/image v0.10.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0= +golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= +golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/server/ws/subscriptions_test.go b/server/ws/subscriptions_test.go index db86053..d163494 100644 --- a/server/ws/subscriptions_test.go +++ b/server/ws/subscriptions_test.go @@ -625,6 +625,40 @@ func TestPublishingNIP09Events(t *testing.T) { require.Equal(t, []*model.Event{validEventNIP09WithEKTags, validEventNIP09AllTags}, storedEvents) } +func TestPublishingNip27Event(t *testing.T) { + privkey := nostr.GeneratePrivateKey() + storedEvents := []*model.Event{} + RegisterWSEventListener(func(ctx context.Context, event *model.Event) error { + for _, sEvent := range storedEvents { + if sEvent.ID == event.ID { + return model.ErrDuplicate + } + } + assert.False(t, event.IsEphemeral()) + storedEvents = append(storedEvents, event) + return nil + }) + pubsubServer.Reset() + ctx, cancel := context.WithTimeout(context.Background(), testDeadline) + defer cancel() + relay, err := fixture.NewRelayClient(ctx, "wss://localhost:9998") + if err != nil { + log.Panic(err) + } + t.Run("kind 1 (NIP-27): p tag usage: no e tags", func(t *testing.T) { + validKind01Event := &model.Event{Event: nostr.Event{ + CreatedAt: nostr.Timestamp(time.Now().Unix()), + Kind: nostr.KindTextNote, + Tags: nostr.Tags{[]string{"p", "pubkey1", "pubkey2"}}, + }} + validKind01Event.SetExtra("extra", uuid.NewString()) + require.NoError(t, validKind01Event.Sign(privkey)) + require.NoError(t, validKind01Event.GenerateNIP13(ctx, NIP13MinLeadingZeroBits)) + require.NoError(t, validKind01Event.Sign(privkey)) + require.NoError(t, relay.Publish(ctx, validKind01Event.Event)) + }) +} + func TestPublishingNIP10Events(t *testing.T) { privkey := nostr.GeneratePrivateKey() storedEvents := []*model.Event{} @@ -671,18 +705,6 @@ func TestPublishingNIP10Events(t *testing.T) { require.NoError(t, inValidKind01Event.Sign(privkey)) require.Error(t, relay.Publish(ctx, inValidKind01Event.Event)) }) - t.Run("kind 1 (NIP-10): invalid p tag usage: no e tags", func(t *testing.T) { - inValidKind01Event := &model.Event{Event: nostr.Event{ - CreatedAt: nostr.Timestamp(time.Now().Unix()), - Kind: nostr.KindTextNote, - Tags: nostr.Tags{[]string{"p", "pubkey1", "pubkey2"}}, - }} - inValidKind01Event.SetExtra("extra", uuid.NewString()) - require.NoError(t, inValidKind01Event.Sign(privkey)) - require.NoError(t, inValidKind01Event.GenerateNIP13(ctx, NIP13MinLeadingZeroBits)) - require.NoError(t, inValidKind01Event.Sign(privkey)) - require.Error(t, relay.Publish(ctx, inValidKind01Event.Event)) - }) t.Run("kind 1 (NIP-10): invalid p tag usage: empty tag values", func(t *testing.T) { inValidKind01Event := &model.Event{Event: nostr.Event{ CreatedAt: nostr.Timestamp(time.Now().Unix()),