From e71645a95c184ba0b6b4622165090af20985e975 Mon Sep 17 00:00:00 2001 From: Daniel Cadenas Date: Fri, 11 Oct 2024 13:18:20 -0300 Subject: [PATCH 1/2] Subscribe to vanish_requests stream for deletion --- Makefile | 10 +- README.md | 6 +- cmd/notification-service/di/service.go | 9 ++ cmd/notification-service/di/wire.go | 6 + cmd/notification-service/di/wire_gen.go | 11 +- compose.yml | 26 ++++ docker-compose-integration.yml | 8 -- go.mod | 2 + go.sum | 4 + .../adapters/firestore/repository_event.go | 40 ++++++ .../firestore/repository_public_keys.go | 27 ++++ service/app/app.go | 2 + service/app/vanish_subscriber.go | 136 ++++++++++++++++++ 13 files changed, 268 insertions(+), 19 deletions(-) create mode 100644 compose.yml delete mode 100644 docker-compose-integration.yml create mode 100644 service/app/vanish_subscriber.go diff --git a/Makefile b/Makefile index ae53eaf..c328641 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ ci: tools test lint generate fmt tidy check_repository_unchanged .PHONY: check_repository_unchanged -check_repository_unchanged: +check_repository_unchanged: _tools/check_repository_unchanged.sh .PHONY: generate @@ -17,10 +17,10 @@ fmt: test: go test -race ./... -.PHONY: recreate-emulator -recreate-emulator: - docker compose -f ./docker-compose-integration.yml rm -f -s -v - docker compose -f ./docker-compose-integration.yml up -d +.PHONY: start-services +start-services: + docker compose rm -f -s -v + docker compose up -d .PHONY: test-integration test-integration: diff --git a/README.md b/README.md index 705ada8..cf45ddc 100644 --- a/README.md +++ b/README.md @@ -124,10 +124,10 @@ You may not be able to build it using older compilers. You have two options when it comes to using Firestore: a local emulator using Docker or a real Firestore project that we setup for development. -##### Using Firestore emulator +##### Using Firestore emulator, nosrelay and Redis 1. Start the docker daemon. -2. Run `make recreate-emulator` to start the Firestore emulator using Docker compose. +2. Run `make start-services` to start the Firestore emulator, nosrelay and Redis using Docker compose. 3. Run the following command changing `NOTIFICATIONS_APNS_CERTIFICATE_PATH` and `NOTIFICATIONS_APNS_CERTIFICATE_PASSWORD`: ``` @@ -137,6 +137,7 @@ FIRESTORE_EMULATOR_HOST=localhost:8200 \ NOTIFICATIONS_FIRESTORE_PROJECT_ID=test-project-id \ NOTIFICATIONS_APNS_TOPIC=com.verse.Nos \ NOTIFICATIONS_ENVIRONMENT=DEVELOPMENT \ +REDIS_URL=redis://localhost:6379 \ go run ./cmd/notification-service ``` @@ -152,6 +153,7 @@ NOTIFICATIONS_FIRESTORE_CREDENTIALS_JSON_PATH="/path/to/your/credentials/file.js NOTIFICATIONS_FIRESTORE_PROJECT_ID="nos-notification-service-dev" \ NOTIFICATIONS_APNS_TOPIC=com.verse.Nos \ NOTIFICATIONS_ENVIRONMENT=DEVELOPMENT \ +REDIS_URL=redis://localhost:6379 \ go run ./cmd/notification-service ``` diff --git a/cmd/notification-service/di/service.go b/cmd/notification-service/di/service.go index 7d4a1fd..5a48cb5 100644 --- a/cmd/notification-service/di/service.go +++ b/cmd/notification-service/di/service.go @@ -18,6 +18,7 @@ type Service struct { metricsServer http.MetricsServer downloader *app.Downloader followChangePuller *app.FollowChangePuller + vanishSubscriber *app.VanishSubscriber receivedEventSubscriber *memorypubsub.ReceivedEventSubscriber externalFollowChangeSubscriber app.ExternalFollowChangeSubscriber eventSavedSubscriber *firestorepubsub.EventSavedSubscriber @@ -30,6 +31,7 @@ func NewService( metricsServer http.MetricsServer, downloader *app.Downloader, followChangePuller *app.FollowChangePuller, + vanishSubscriber *app.VanishSubscriber, receivedEventSubscriber *memorypubsub.ReceivedEventSubscriber, externalFollowChangeSubscriber app.ExternalFollowChangeSubscriber, eventSavedSubscriber *firestorepubsub.EventSavedSubscriber, @@ -41,6 +43,7 @@ func NewService( metricsServer: metricsServer, downloader: downloader, followChangePuller: followChangePuller, + vanishSubscriber: vanishSubscriber, receivedEventSubscriber: receivedEventSubscriber, externalFollowChangeSubscriber: externalFollowChangeSubscriber, eventSavedSubscriber: eventSavedSubscriber, @@ -79,10 +82,16 @@ func (s Service) Run(ctx context.Context) error { errCh <- errors.Wrap(s.receivedEventSubscriber.Run(ctx), "received event subscriber error") }() + runners++ go func() { errCh <- errors.Wrap(s.followChangePuller.Run(ctx), "follow change subscriber error") }() + runners++ + go func() { + errCh <- errors.Wrap(s.vanishSubscriber.Run(ctx), "vanish subscriber error") + }() + runners++ go func() { errCh <- errors.Wrap(s.eventSavedSubscriber.Run(ctx), "event saved subscriber error") diff --git a/cmd/notification-service/di/wire.go b/cmd/notification-service/di/wire.go index 4ec77fa..183884e 100644 --- a/cmd/notification-service/di/wire.go +++ b/cmd/notification-service/di/wire.go @@ -28,6 +28,7 @@ func BuildService(context.Context, config.Config) (Service, func(), error) { loggingSet, adaptersSet, followChangePullerSet, + vanishSubscriberSet, ) return Service{}, nil, nil } @@ -49,6 +50,7 @@ func BuildIntegrationService(context.Context, config.Config) (IntegrationService firestoreAdaptersSet, downloaderSet, followChangePullerSet, + vanishSubscriberSet, generatorSet, pubsubSet, loggingSet, @@ -80,6 +82,10 @@ var followChangePullerSet = wire.NewSet( app.NewFollowChangePuller, ) +var vanishSubscriberSet = wire.NewSet( + app.NewVanishSubscriber, +) + var generatorSet = wire.NewSet( notifications.NewGenerator, ) diff --git a/cmd/notification-service/di/wire_gen.go b/cmd/notification-service/di/wire_gen.go index c8e5292..582aab9 100644 --- a/cmd/notification-service/di/wire_gen.go +++ b/cmd/notification-service/di/wire_gen.go @@ -7,9 +7,8 @@ package di import ( - "context" - firestore2 "cloud.google.com/go/firestore" + "context" "github.com/ThreeDotsLabs/watermill" "github.com/google/wire" "github.com/planetary-social/go-notification-service/internal/logging" @@ -86,6 +85,7 @@ func BuildService(contextContext context.Context, configConfig config.Config) (S return Service{}, nil, err } followChangePuller := app.NewFollowChangePuller(externalFollowChangeSubscriber, apnsAPNS, queries, logger, prometheusPrometheus) + vanishSubscriber := app.NewVanishSubscriber(transactionProvider, queries, logger) receivedEventSubscriber := memorypubsub.NewReceivedEventSubscriber(receivedEventPubSub, saveReceivedEventHandler, logger) subscriber, err := firestore.NewWatermillSubscriber(client, watermillAdapter) if err != nil { @@ -100,7 +100,7 @@ func BuildService(contextContext context.Context, configConfig config.Config) (S } processSavedEventHandler := app.NewProcessSavedEventHandler(transactionProvider, generator, apnsAPNS, logger, prometheusPrometheus, externalEventPublisher) eventSavedSubscriber := firestorepubsub.NewEventSavedSubscriber(subscriber, processSavedEventHandler, prometheusPrometheus, logger) - service := NewService(application, server, metricsServer, downloader, followChangePuller, receivedEventSubscriber, externalFollowChangeSubscriber, eventSavedSubscriber, memoryEventWasAlreadySavedCache) + service := NewService(application, server, metricsServer, downloader, followChangePuller, vanishSubscriber, receivedEventSubscriber, externalFollowChangeSubscriber, eventSavedSubscriber, memoryEventWasAlreadySavedCache) return service, func() { cleanup() }, nil @@ -164,6 +164,7 @@ func BuildIntegrationService(contextContext context.Context, configConfig config return IntegrationService{}, nil, err } followChangePuller := app.NewFollowChangePuller(externalFollowChangeSubscriber, apnsMock, queries, logger, prometheusPrometheus) + vanishSubscriber := app.NewVanishSubscriber(transactionProvider, queries, logger) receivedEventSubscriber := memorypubsub.NewReceivedEventSubscriber(receivedEventPubSub, saveReceivedEventHandler, logger) subscriber, err := firestore.NewWatermillSubscriber(client, watermillAdapter) if err != nil { @@ -178,7 +179,7 @@ func BuildIntegrationService(contextContext context.Context, configConfig config } processSavedEventHandler := app.NewProcessSavedEventHandler(transactionProvider, generator, apnsMock, logger, prometheusPrometheus, externalEventPublisher) eventSavedSubscriber := firestorepubsub.NewEventSavedSubscriber(subscriber, processSavedEventHandler, prometheusPrometheus, logger) - service := NewService(application, server, metricsServer, downloader, followChangePuller, receivedEventSubscriber, externalFollowChangeSubscriber, eventSavedSubscriber, memoryEventWasAlreadySavedCache) + service := NewService(application, server, metricsServer, downloader, followChangePuller, vanishSubscriber, receivedEventSubscriber, externalFollowChangeSubscriber, eventSavedSubscriber, memoryEventWasAlreadySavedCache) integrationService := IntegrationService{ Service: service, MockAPNS: apnsMock, @@ -227,4 +228,6 @@ var downloaderSet = wire.NewSet(app.NewDownloader) var followChangePullerSet = wire.NewSet(app.NewFollowChangePuller) +var vanishSubscriberSet = wire.NewSet(app.NewVanishSubscriber) + var generatorSet = wire.NewSet(notifications.NewGenerator) diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..8b7fb16 --- /dev/null +++ b/compose.yml @@ -0,0 +1,26 @@ +services: + firestore_emulator: + platform: linux/amd64 + image: mtlynch/firestore-emulator + environment: + - FIRESTORE_PROJECT_ID=test-project-id + - PORT=8200 + ports: + - 8200:8200 + + redis: + platform: linux/amd64 + image: redis:latest + ports: + - 6379:6379 + + relay: + platform: linux/amd64 + image: ghcr.io/planetary-social/nosrelay:latest + ports: + - "7777:7777" + environment: + - RELAY_URL=wss://example.com + - REDIS_URL=redis://redis:6379 + depends_on: + - redis \ No newline at end of file diff --git a/docker-compose-integration.yml b/docker-compose-integration.yml deleted file mode 100644 index fcad93c..0000000 --- a/docker-compose-integration.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - firestore_emulator: - image: mtlynch/firestore-emulator - environment: - - FIRESTORE_PROJECT_ID=test-project-id - - PORT=8200 - ports: - - 8200:8200 diff --git a/go.mod b/go.mod index 1cf373d..c54e840 100644 --- a/go.mod +++ b/go.mod @@ -40,6 +40,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect @@ -67,6 +68,7 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect + github.com/redis/go-redis/v9 v9.6.1 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/tidwall/gjson v1.17.0 // indirect github.com/tidwall/match v1.1.1 // indirect diff --git a/go.sum b/go.sum index 0364683..63ea5ab 100644 --- a/go.sum +++ b/go.sum @@ -98,6 +98,8 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -263,6 +265,8 @@ github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+Pymzi github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= diff --git a/service/adapters/firestore/repository_event.go b/service/adapters/firestore/repository_event.go index 1eb3c95..1ba7849 100644 --- a/service/adapters/firestore/repository_event.go +++ b/service/adapters/firestore/repository_event.go @@ -126,6 +126,46 @@ func (e *EventRepository) saveUnderEvents(event domain.Event) error { return nil } +// DeleteByPublicKey deletes all events and associated notifications for a given public key. +func (e *EventRepository) DeleteByPublicKey(ctx context.Context, pubkey domain.PublicKey) error { + eventsQuery := e.client.Collection(collectionEvents).Where(eventFieldPublicKey, "==", pubkey.Hex()) + + eventsDocs := e.tx.Documents(eventsQuery) + + for { + eventDoc, err := eventsDocs.Next() + if err == iterator.Done { + break + } + if err != nil { + return errors.Wrap(err, "error fetching event document") + } + + notificationsCollection := eventDoc.Ref.Collection(collectionEventsNotifications) + notificationsDocs := e.tx.Documents(notificationsCollection) + + for { + notificationDoc, err := notificationsDocs.Next() + if err == iterator.Done { + break + } + if err != nil { + return errors.Wrap(err, "error fetching notification document") + } + + if err := e.tx.Delete(notificationDoc.Ref); err != nil { + return errors.Wrap(err, "error deleting notification document") + } + } + + if err := e.tx.Delete(eventDoc.Ref); err != nil { + return errors.Wrap(err, "error deleting event document") + } + } + + return nil +} + func (e *EventRepository) GetEvents(ctx context.Context, filters domain.Filters) <-chan app.EventOrError { ch := make(chan app.EventOrError) go e.getEvents(ctx, filters, ch) diff --git a/service/adapters/firestore/repository_public_keys.go b/service/adapters/firestore/repository_public_keys.go index 06bc4f1..5543cc9 100644 --- a/service/adapters/firestore/repository_public_keys.go +++ b/service/adapters/firestore/repository_public_keys.go @@ -49,6 +49,33 @@ func (r *PublicKeyRepository) Save(registration domain.Registration) error { return nil } +// DeleteByPublicKey deletes a public key and all its associated APNS tokens +func (r *PublicKeyRepository) DeleteByPublicKey(ctx context.Context, publicKey domain.PublicKey) error { + pubKeyDocRef := r.client.Collection(collectionPublicKeys).Doc(publicKey.Hex()) + apnsTokensCollection := pubKeyDocRef.Collection(collectionPublicKeysAPNSTokens) + apnsDocs := r.tx.Documents(apnsTokensCollection) + + for { + doc, err := apnsDocs.Next() + if err == iterator.Done { + break + } + if err != nil { + return errors.Wrap(err, "error fetching APNS token document") + } + + if err := r.tx.Delete(doc.Ref); err != nil { + return errors.Wrap(err, "error deleting APNS token document") + } + } + + if err := r.tx.Delete(pubKeyDocRef); err != nil { + return errors.Wrap(err, "error deleting the public key document") + } + + return nil +} + func (r *PublicKeyRepository) GetAPNSTokens(ctx context.Context, publicKey domain.PublicKey, savedAfter time.Time) ([]domain.APNSToken, error) { docs := r.tx.Documents( r.client. diff --git a/service/app/app.go b/service/app/app.go index 77eaf5d..1880b6b 100644 --- a/service/app/app.go +++ b/service/app/app.go @@ -32,11 +32,13 @@ type RelayRepository interface { } type PublicKeyRepository interface { + DeleteByPublicKey(ctx context.Context, publicKey domain.PublicKey) error GetAPNSTokens(ctx context.Context, publicKey domain.PublicKey, savedAfter time.Time) ([]domain.APNSToken, error) } type EventRepository interface { Save(event domain.Event) error + DeleteByPublicKey(ctx context.Context, publicKey domain.PublicKey) error Get(ctx context.Context, id domain.EventId) (domain.Event, error) Exists(ctx context.Context, id domain.EventId) (bool, error) GetEvents(ctx context.Context, filters domain.Filters) <-chan EventOrError diff --git a/service/app/vanish_subscriber.go b/service/app/vanish_subscriber.go new file mode 100644 index 0000000..3b2fe30 --- /dev/null +++ b/service/app/vanish_subscriber.go @@ -0,0 +1,136 @@ +package app + +import ( + "context" + "os" + "time" + + "github.com/planetary-social/go-notification-service/internal/logging" + "github.com/planetary-social/go-notification-service/service/domain" + "github.com/redis/go-redis/v9" +) + +type VanishSubscriber struct { + rdb *redis.Client + transactionProvider TransactionProvider + queries Queries + logger logging.Logger +} + +func NewVanishSubscriber( + transactionProvider TransactionProvider, + queries Queries, + logger logging.Logger, +) *VanishSubscriber { + log := logger.New("vanishSubscriber") + redisURL := os.Getenv("REDIS_URL") + + options, err := redis.ParseURL(redisURL) + if err != nil { + log.Error().Message("Error parsing REDIS_URL") + } + + rdb := redis.NewClient(options) + + return &VanishSubscriber{ + rdb: rdb, + transactionProvider: transactionProvider, + queries: queries, + logger: log, + } +} + +// Processes messages from the vanish_requests stream and updates the last_id when done +func (f *VanishSubscriber) Run(ctx context.Context) error { + streamName := "vanish_requests" + lastProcessedIDKey := "vanish_requests:notification_service:last_id" + + lastProcessedID, err := f.rdb.Get(ctx, lastProcessedIDKey).Result() + if err == redis.Nil { + lastProcessedID = "0-0" + } else if err != nil { + f.logger.Error().Message("Error fetching last processed ID") + return err + } + + f.logger.Debug().WithField("lastProcessedID", lastProcessedID).Message("Starting VanishSubscriber") + + for { + select { + case <-ctx.Done(): + f.logger.Debug().Message("context canceled, shutting down VanishSubscriber") + return nil + + default: + streamEntries, err := f.rdb.XRead(ctx, &redis.XReadArgs{ + Streams: []string{streamName, lastProcessedID}, + Count: 1, + Block: 5 * time.Second, + }).Result() + + if err == redis.Nil { + // No new messages in the stream within the block time, continue the loop + continue + } else if err != nil { + f.logger.Error().Message("Error reading from stream") + return err + } + + for _, stream := range streamEntries { + for _, entry := range stream.Messages { + streamID := entry.ID + f.logger.Debug().WithField("streamId", streamID).Message("Processing stream ID") + + pubkey, err := domain.NewPublicKeyFromHex(entry.Values["pubkey"].(string)) + + if err != nil { + f.logger.Error().Message("Error parsing pubkey") + break + } + + err = f.removePubkeyInfo(ctx, pubkey) + if err != nil { + f.logger.Error().WithField("streamId", streamID).Message("Failed to process entry") + continue + } + + err = f.rdb.Set(ctx, lastProcessedIDKey, streamID, 0).Err() + if err != nil { + f.logger.Error().Message("Error saving last processed ID") + return err + } + + lastProcessedID = streamID + f.logger.Debug().WithField("lastProcessedID", lastProcessedID).Message("Updated last processed ID") + } + } + } + } +} + +// Deletes the public key and associated tokens, events, and notifications +func (f *VanishSubscriber) removePubkeyInfo(ctx context.Context, pubkey domain.PublicKey) error { + err := f.transactionProvider.Transact(ctx, func(ctx context.Context, adapters Adapters) error { + if err := adapters.PublicKeys.DeleteByPublicKey(ctx, pubkey); err != nil { + f.logger.Error().WithField("pubkey", pubkey.Hex()).WithError(err).Message("Error deleting public key") + return err + } + + f.logger.Debug().WithField("pubkey", pubkey.Hex()).Message("Successfully deleted public key and associated tokens") + return nil + }) + + if err != nil { + return err + } + + return f.transactionProvider.Transact(ctx, func(ctx context.Context, adapters Adapters) error { + if err := adapters.Events.DeleteByPublicKey(ctx, pubkey); err != nil { + f.logger.Error().WithField("pubkey", pubkey.Hex()).WithError(err).Message("Error deleting events and notifications for public key") + return err + } + + f.logger.Debug().WithField("pubkey", pubkey.Hex()).Message("Successfully deleted events and notifications for public key") + return nil + }) +} From dc1af70c8487be728db2accdab0cecbb7f30f0f7 Mon Sep 17 00:00:00 2001 From: Daniel Cadenas Date: Fri, 11 Oct 2024 18:18:58 -0300 Subject: [PATCH 2/2] Update deps --- cmd/notification-service/di/wire_gen.go | 3 ++- go.mod | 2 +- go.sum | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/notification-service/di/wire_gen.go b/cmd/notification-service/di/wire_gen.go index 582aab9..24050a4 100644 --- a/cmd/notification-service/di/wire_gen.go +++ b/cmd/notification-service/di/wire_gen.go @@ -7,8 +7,9 @@ package di import ( - firestore2 "cloud.google.com/go/firestore" "context" + + firestore2 "cloud.google.com/go/firestore" "github.com/ThreeDotsLabs/watermill" "github.com/google/wire" "github.com/planetary-social/go-notification-service/internal/logging" diff --git a/go.mod b/go.mod index c54e840..8be7b8e 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/nbd-wtf/go-nostr v0.25.7 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.16.0 + github.com/redis/go-redis/v9 v9.6.1 github.com/rs/zerolog v1.29.1 github.com/sideshow/apns2 v0.23.0 github.com/sirupsen/logrus v1.9.3 @@ -68,7 +69,6 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect - github.com/redis/go-redis/v9 v9.6.1 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/tidwall/gjson v1.17.0 // indirect github.com/tidwall/match v1.1.1 // indirect diff --git a/go.sum b/go.sum index 63ea5ab..8aa69cd 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/boreq/errors v0.1.0 h1:aJIXv9JnyR5KtxFpQ8/AiblH3nfYmr1e1yoTze/5A1k= github.com/boreq/errors v0.1.0/go.mod h1:B3dsXzhYvfgUXp7ViU/moPYM4PojgQ9MiQ21uvY6qqQ= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=