Files
lndhub.go/lib/service/webhook.go
2023-04-01 14:13:20 +02:00

133 lines
4.4 KiB
Go

package service
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"time"
"github.com/getAlby/lndhub.go/common"
"github.com/getAlby/lndhub.go/db/models"
)
func (svc *LndhubService) StartWebhookSubscription(ctx context.Context, url string) {
svc.Logger.Infof("Starting webhook subscription with webhook url %s", svc.Config.WebhookUrl)
incomingInvoices, outgoingInvoices, err := svc.SubscribeIncomingOutgoingInvoices()
if err != nil {
svc.Logger.Error(err)
}
for {
select {
case <-ctx.Done():
return
case incoming := <-incomingInvoices:
svc.postToWebhook(incoming, url)
case outgoing := <-outgoingInvoices:
svc.postToWebhook(outgoing, url)
}
}
}
func (svc *LndhubService) postToWebhook(invoice models.Invoice, url string) {
//Look up the user's login to add it to the invoice
user, err := svc.FindUser(context.Background(), invoice.UserID)
if err != nil {
svc.Logger.Error(err)
return
}
payload := new(bytes.Buffer)
err = json.NewEncoder(payload).Encode(ConvertPayload(invoice, user))
if err != nil {
svc.Logger.Error(err)
return
}
resp, err := http.Post(svc.Config.WebhookUrl, "application/json", payload)
if err != nil {
svc.Logger.Error(err)
return
}
if resp.StatusCode != http.StatusOK {
msg, err := io.ReadAll(resp.Body)
if err != nil {
svc.Logger.Error(err)
}
svc.Logger.Errorf("Webhook status code was %d, body: %s", resp.StatusCode, msg)
}
}
type WebhookInvoicePayload struct {
ID int64 `json:"id"`
Type string `json:"type"`
UserLogin string `json:"user_login"`
Amount int64 `json:"amount"`
Fee int64 `json:"fee"`
Memo string `json:"memo"`
DescriptionHash string `json:"description_hash,omitempty"`
PaymentRequest string `json:"payment_request"`
DestinationPubkeyHex string `json:"destination_pubkey_hex"`
DestinationCustomRecords map[uint64][]byte `json:"custom_records,omitempty"`
RHash string `json:"r_hash"`
Preimage string `json:"preimage"`
Keysend bool `json:"keysend"`
State string `json:"state"`
ErrorMessage string `json:"error_message,omitempty"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
UpdatedAt time.Time `json:"updated_at"`
SettledAt time.Time `json:"settled_at"`
}
func (svc *LndhubService) SubscribeIncomingOutgoingInvoices() (incoming, outgoing chan models.Invoice, err error) {
incomingInvoices, _, err := svc.InvoicePubSub.Subscribe(common.InvoiceTypeIncoming)
if err != nil {
return nil, nil, err
}
outgoingInvoices, _, err := svc.InvoicePubSub.Subscribe(common.InvoiceTypeOutgoing)
if err != nil {
return nil, nil, err
}
return incomingInvoices, outgoingInvoices, nil
}
func (svc *LndhubService) EncodeInvoiceWithUserLogin(ctx context.Context, w io.Writer, invoice models.Invoice) error {
user, err := svc.FindUser(ctx, invoice.UserID)
if err != nil {
return err
}
err = json.NewEncoder(w).Encode(ConvertPayload(invoice, user))
if err != nil {
return err
}
return nil
}
func ConvertPayload(invoice models.Invoice, user *models.User) (result WebhookInvoicePayload) {
return WebhookInvoicePayload{
ID: invoice.ID,
Type: invoice.Type,
UserLogin: user.Login,
Amount: invoice.Amount,
Fee: invoice.Fee,
Memo: invoice.Memo,
DescriptionHash: invoice.DescriptionHash,
PaymentRequest: invoice.PaymentRequest,
DestinationPubkeyHex: invoice.DestinationPubkeyHex,
DestinationCustomRecords: invoice.DestinationCustomRecords,
RHash: invoice.RHash,
Preimage: invoice.Preimage,
Keysend: invoice.Keysend,
State: invoice.State,
ErrorMessage: invoice.ErrorMessage,
CreatedAt: invoice.CreatedAt,
ExpiresAt: invoice.ExpiresAt.Time,
UpdatedAt: invoice.UpdatedAt.Time,
SettledAt: invoice.SettledAt.Time,
}
}