mirror of
https://github.com/getAlby/hub.git
synced 2026-08-13 12:33:39 +02:00
133 lines
5.5 KiB
Go
133 lines
5.5 KiB
Go
package nip47
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/getAlby/go-nostr"
|
|
"github.com/getAlby/hub/alby"
|
|
"github.com/getAlby/hub/apps"
|
|
"github.com/getAlby/hub/config"
|
|
"github.com/getAlby/hub/events"
|
|
"github.com/getAlby/hub/lnclient"
|
|
"github.com/getAlby/hub/logger"
|
|
"github.com/getAlby/hub/nip47/cipher"
|
|
"github.com/getAlby/hub/nip47/notifications"
|
|
"github.com/getAlby/hub/nip47/permissions"
|
|
nostrmodels "github.com/getAlby/hub/nostr/models"
|
|
"github.com/getAlby/hub/service/keys"
|
|
"github.com/getAlby/hub/transactions"
|
|
"github.com/sirupsen/logrus"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type nip47Service struct {
|
|
permissionsService permissions.PermissionsService
|
|
transactionsService transactions.TransactionsService
|
|
appsService apps.AppsService
|
|
albyOAuthSvc alby.AlbyOAuthService
|
|
nip47NotificationQueue notifications.Nip47NotificationQueue
|
|
nip47InfoPublishQueue *nip47InfoPublishQueue
|
|
cfg config.Config
|
|
keys keys.Keys
|
|
db *gorm.DB
|
|
eventPublisher events.EventPublisher
|
|
}
|
|
|
|
type Nip47Service interface {
|
|
events.EventSubscriber
|
|
StartNotifier(ctx context.Context, pool *nostr.SimplePool)
|
|
StartNip47InfoPublisher(ctx context.Context, pool *nostr.SimplePool, lnClient lnclient.LNClient)
|
|
HandleEvent(ctx context.Context, pool nostrmodels.SimplePool, event *nostr.Event, lnClient lnclient.LNClient)
|
|
GetNip47Info(ctx context.Context, pool nostrmodels.SimplePool, appWalletPubKey string) (*nostr.Event, error)
|
|
PublishNip47Info(ctx context.Context, pool nostrmodels.SimplePool, appId uint, appWalletPubKey string, appWalletPrivKey string, relayUrl string, lnClient lnclient.LNClient) (*nostr.Event, error)
|
|
PublishNip47InfoDeletion(ctx context.Context, pool nostrmodels.SimplePool, appWalletPubKey string, appWalletPrivKey string, infoEventId string) error
|
|
CreateResponse(initialEvent *nostr.Event, content interface{}, tags nostr.Tags, cipher *cipher.Nip47Cipher, walletPrivKey string) (result *nostr.Event, err error)
|
|
EnqueueNip47InfoPublishRequest(appId uint, appWalletPubKey, appWalletPrivKey, relayUrl string)
|
|
}
|
|
|
|
func NewNip47Service(db *gorm.DB, cfg config.Config, keys keys.Keys, eventPublisher events.EventPublisher, albyOAuthSvc alby.AlbyOAuthService) *nip47Service {
|
|
return &nip47Service{
|
|
nip47NotificationQueue: notifications.NewNip47NotificationQueue(),
|
|
nip47InfoPublishQueue: NewNip47InfoPublishQueue(),
|
|
cfg: cfg,
|
|
db: db,
|
|
permissionsService: permissions.NewPermissionsService(db, eventPublisher),
|
|
transactionsService: transactions.NewTransactionsService(db, eventPublisher),
|
|
appsService: apps.NewAppsService(db, eventPublisher, keys, cfg),
|
|
eventPublisher: eventPublisher,
|
|
keys: keys,
|
|
albyOAuthSvc: albyOAuthSvc,
|
|
}
|
|
}
|
|
|
|
func (svc *nip47Service) ConsumeEvent(ctx context.Context, event *events.Event, globalProperties map[string]interface{}) {
|
|
svc.nip47NotificationQueue.AddToQueue(event)
|
|
}
|
|
|
|
// The notifier is decoupled from the notification queue
|
|
// so that if Alby Hub disconnects from the relay, it will wait to reconnect
|
|
// to send notifications rather than dropping them
|
|
func (svc *nip47Service) StartNotifier(ctx context.Context, pool *nostr.SimplePool) {
|
|
nip47Notifier := notifications.NewNip47Notifier(pool, svc.db, svc.cfg, svc.keys, svc.permissionsService)
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
// app exited
|
|
return
|
|
case event := <-svc.nip47NotificationQueue.Channel():
|
|
logger.Logger.WithField("event", event).Debug("Consuming event from notification queue")
|
|
err := nip47Notifier.ConsumeEvent(ctx, event)
|
|
if err != nil {
|
|
logger.Logger.WithError(err).WithField("event", event).Error("Failed to consume event from notification queue")
|
|
// wait and then re-add the item to the queue
|
|
time.Sleep(5 * time.Second)
|
|
svc.nip47NotificationQueue.AddToQueue(event)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (svc *nip47Service) EnqueueNip47InfoPublishRequest(appId uint, appWalletPubKey, appWalletPrivKey, relayUrl string) {
|
|
svc.enqueueNip47InfoPublishRequestWithAttempt(appId, appWalletPubKey, appWalletPrivKey, relayUrl, 0)
|
|
}
|
|
|
|
func (svc *nip47Service) enqueueNip47InfoPublishRequestWithAttempt(appId uint, appWalletPubKey, appWalletPrivKey, relayUrl string, attempt uint32) {
|
|
svc.nip47InfoPublishQueue.AddToQueue(&Nip47InfoPublishRequest{
|
|
AppId: appId,
|
|
AppWalletPubKey: appWalletPubKey,
|
|
AppWalletPrivKey: appWalletPrivKey,
|
|
RelayUrl: relayUrl,
|
|
Attempt: attempt,
|
|
})
|
|
}
|
|
|
|
func (svc *nip47Service) StartNip47InfoPublisher(ctx context.Context, pool *nostr.SimplePool, lnClient lnclient.LNClient) {
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
// relay disconnected
|
|
return
|
|
case req := <-svc.nip47InfoPublishQueue.Channel():
|
|
_, err := svc.PublishNip47Info(ctx, pool, req.AppId, req.AppWalletPubKey, req.AppWalletPrivKey, req.RelayUrl, lnClient)
|
|
if err != nil {
|
|
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
|
"wallet_pubkey": req.AppWalletPubKey,
|
|
"relay_url": req.RelayUrl,
|
|
}).Error("Failed to publish NIP47 info from queue")
|
|
|
|
// wait and then re-add the item to the queue
|
|
// done async to ensure an offline relay does not delay
|
|
// the publishing of newly created app connections
|
|
go func() {
|
|
time.Sleep((5 * time.Duration(req.Attempt+1)) * time.Second)
|
|
svc.enqueueNip47InfoPublishRequestWithAttempt(req.AppId, req.AppWalletPubKey, req.AppWalletPrivKey, req.RelayUrl, req.Attempt+1)
|
|
}()
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|