mirror of
https://github.com/getAlby/lndhub.go.git
synced 2025-12-22 07:04:56 +01:00
resolve merge conflicts
This commit is contained in:
11
.github/workflows/integration_tests.yaml
vendored
11
.github/workflows/integration_tests.yaml
vendored
@@ -25,6 +25,14 @@ jobs:
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
rabbitmq:
|
||||
image: rabbitmq:3.11.8
|
||||
ports:
|
||||
- 5672:5672
|
||||
env:
|
||||
RABBITMQ_DEFAULT_USER: "root"
|
||||
RABBITMQ_DEFAULT_PASS: "password"
|
||||
options: --health-cmd "rabbitmqctl node_health_check" --health-interval 10s --health-timeout 5s --health-retries 5
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
@@ -34,3 +42,6 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Run tests
|
||||
run: go test -p 1 -v -cover -coverpkg=./... ./...
|
||||
env:
|
||||
RABBITMQ_URI: amqp://root:password@localhost:5672
|
||||
|
||||
|
||||
24
go.mod
24
go.mod
@@ -14,6 +14,7 @@ require (
|
||||
github.com/labstack/echo/v4 v4.10.0
|
||||
github.com/labstack/gommon v0.4.0
|
||||
github.com/lightningnetwork/lnd v0.15.5-beta.rc2
|
||||
github.com/rabbitmq/amqp091-go v1.6.1
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/uptrace/bun v1.1.10
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.1.10
|
||||
@@ -31,7 +32,7 @@ require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||
github.com/aead/siphash v1.0.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/btcsuite/btcd/btcutil v1.1.3 // indirect
|
||||
github.com/btcsuite/btcd/btcutil/psbt v1.1.6 // indirect
|
||||
@@ -54,12 +55,10 @@ require (
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/decred/dcrd/lru v1.1.1 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fergusstrange/embedded-postgres v1.19.0 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@@ -92,17 +91,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/jrick/logrotate v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/juju/clock v0.0.0-20220203021603-d9deb868a28a // indirect
|
||||
github.com/juju/collections v0.0.0-20220203020748-febd7cad8a7a // indirect
|
||||
github.com/juju/errors v0.0.0-20220331221717-b38fca44723b // indirect
|
||||
github.com/juju/loggo v1.0.0 // indirect
|
||||
github.com/juju/mgo/v2 v2.0.0-20220111072304-f200228f1090 // indirect
|
||||
github.com/juju/retry v0.0.0-20220204093819-62423bf33287 // indirect
|
||||
github.com/juju/utils/v3 v3.0.0-20220203023959-c3fbc78a33b0 // indirect
|
||||
github.com/juju/version/v2 v2.0.0-20220204124744-fc9915e3d935 // indirect
|
||||
github.com/kkdai/bstream v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.15.14 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lib/pq v1.10.7 // indirect
|
||||
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // indirect
|
||||
@@ -120,12 +109,9 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.1 // indirect
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
@@ -141,7 +127,6 @@ require (
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
|
||||
@@ -156,18 +141,13 @@ require (
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.6 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.6 // indirect
|
||||
go.etcd.io/etcd/server/v3 v3.5.6 // indirect
|
||||
go.opentelemetry.io/contrib v1.12.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.37.0 // indirect
|
||||
go.opentelemetry.io/otel v1.11.2 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.2 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.2 // indirect
|
||||
go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.34.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.11.2 // indirect
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.28.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v0.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.11.2 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
|
||||
164
integration_tests/rabbitmq_test.go
Normal file
164
integration_tests/rabbitmq_test.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package integration_tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/getAlby/lndhub.go/common"
|
||||
"github.com/getAlby/lndhub.go/controllers"
|
||||
"github.com/getAlby/lndhub.go/db/models"
|
||||
"github.com/getAlby/lndhub.go/lib"
|
||||
"github.com/getAlby/lndhub.go/lib/responses"
|
||||
"github.com/getAlby/lndhub.go/lib/service"
|
||||
"github.com/getAlby/lndhub.go/lib/tokens"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type RabbitMQTestSuite struct {
|
||||
TestSuite
|
||||
mlnd *MockLND
|
||||
externalLnd *MockLND
|
||||
invoiceUpdateSubCancelFn context.CancelFunc
|
||||
userToken string
|
||||
svc *service.LndhubService
|
||||
testQueueName string
|
||||
}
|
||||
|
||||
func (suite *RabbitMQTestSuite) SetupSuite() {
|
||||
mlnd := newDefaultMockLND()
|
||||
//needs different pubkey
|
||||
//to allow for "external" payments
|
||||
externalLnd, err := NewMockLND("1234567890abcdef1234", 0, make(chan (*lnrpc.Invoice)))
|
||||
assert.NoError(suite.T(), err)
|
||||
svc, err := LndHubTestServiceInit(mlnd)
|
||||
if err != nil {
|
||||
log.Fatalf("could not initialize test service: %v", err)
|
||||
}
|
||||
|
||||
suite.mlnd = mlnd
|
||||
suite.externalLnd = externalLnd
|
||||
suite.testQueueName = "test_invoice"
|
||||
|
||||
_, userTokens, err := createUsers(svc, 1)
|
||||
if err != nil {
|
||||
log.Fatalf("error creating test users: %v", err)
|
||||
}
|
||||
suite.userToken = userTokens[0]
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
suite.invoiceUpdateSubCancelFn = cancel
|
||||
go svc.InvoiceUpdateSubscription(ctx)
|
||||
suite.svc = svc
|
||||
|
||||
e := echo.New()
|
||||
e.HTTPErrorHandler = responses.HTTPErrorHandler
|
||||
e.Validator = &lib.CustomValidator{Validator: validator.New()}
|
||||
|
||||
suite.echo = e
|
||||
suite.echo.Use(tokens.Middleware(suite.svc.Config.JWTSecret))
|
||||
suite.echo.POST("/addinvoice", controllers.NewAddInvoiceController(suite.svc).AddInvoice)
|
||||
suite.echo.POST("/payinvoice", controllers.NewPayInvoiceController(suite.svc).PayInvoice)
|
||||
go func() {
|
||||
err = svc.StartRabbitMqPublisher(ctx)
|
||||
assert.NoError(suite.T(), err)
|
||||
}()
|
||||
}
|
||||
|
||||
func (suite *RabbitMQTestSuite) TestPublishInvoice() {
|
||||
conn, err := amqp.Dial(suite.svc.Config.RabbitMQUri)
|
||||
assert.NoError(suite.T(), err)
|
||||
defer conn.Close()
|
||||
|
||||
ch, err := conn.Channel()
|
||||
assert.NoError(suite.T(), err)
|
||||
defer ch.Close()
|
||||
|
||||
q, err := ch.QueueDeclare(
|
||||
suite.testQueueName,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
err = ch.QueueBind(q.Name, "#", suite.svc.Config.RabbitMQInvoiceExchange, false, nil)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
invoice := suite.createAddInvoiceReq(1000, "integration test rabbitmq", suite.userToken)
|
||||
err = suite.mlnd.mockPaidInvoice(invoice, 0, false, nil)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
m, err := ch.Consume(
|
||||
q.Name,
|
||||
"invoice.*.*",
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
msg := <-m
|
||||
|
||||
var receivedInvoice models.Invoice
|
||||
r := bytes.NewReader(msg.Body)
|
||||
err = json.NewDecoder(r).Decode(&receivedInvoice)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
assert.Equal(suite.T(), invoice.RHash, receivedInvoice.RHash)
|
||||
assert.Equal(suite.T(), common.InvoiceTypeIncoming, receivedInvoice.Type)
|
||||
|
||||
//check if outgoing invoices also get published
|
||||
outgoingInvoiceValue := 500
|
||||
outgoingInvoiceDescription := "test rabbit outgoing invoice"
|
||||
preimage, err := makePreimageHex()
|
||||
assert.NoError(suite.T(), err)
|
||||
outgoingInv, err := suite.externalLnd.AddInvoice(context.Background(), &lnrpc.Invoice{Value: int64(outgoingInvoiceValue), Memo: outgoingInvoiceDescription, RPreimage: preimage})
|
||||
assert.NoError(suite.T(), err)
|
||||
//pay invoice
|
||||
suite.createPayInvoiceReq(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: outgoingInv.PaymentRequest,
|
||||
}, suite.userToken)
|
||||
msg = <-m
|
||||
|
||||
var receivedPayment models.Invoice
|
||||
r = bytes.NewReader(msg.Body)
|
||||
err = json.NewDecoder(r).Decode(&receivedPayment)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
assert.Equal(suite.T(), common.InvoiceTypeOutgoing, receivedPayment.Type)
|
||||
assert.Equal(suite.T(), int64(outgoingInvoiceValue), receivedPayment.Amount)
|
||||
assert.Equal(suite.T(), outgoingInvoiceDescription, receivedPayment.Memo)
|
||||
|
||||
}
|
||||
|
||||
func (suite *RabbitMQTestSuite) TearDownSuite() {
|
||||
conn, err := amqp.Dial(suite.svc.Config.RabbitMQUri)
|
||||
assert.NoError(suite.T(), err)
|
||||
defer conn.Close()
|
||||
|
||||
ch, err := conn.Channel()
|
||||
assert.NoError(suite.T(), err)
|
||||
defer ch.Close()
|
||||
|
||||
_, err = ch.QueueDelete(suite.testQueueName, false, false, false)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
err = ch.ExchangeDelete(suite.svc.Config.RabbitMQInvoiceExchange, true, false)
|
||||
assert.NoError(suite.T(), err)
|
||||
}
|
||||
|
||||
func TestRabbitMQTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(RabbitMQTestSuite))
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/getAlby/lndhub.go/db"
|
||||
@@ -56,6 +57,13 @@ func LndHubTestServiceInit(lndClientMock lnd.LightningClientWrapper) (svc *servi
|
||||
LNDAddress: mockLNDAddress,
|
||||
LNDMacaroonHex: mockLNDMacaroonHex,
|
||||
}
|
||||
|
||||
rabbitmqUri, ok := os.LookupEnv("RABBITMQ_URI")
|
||||
if ok {
|
||||
c.RabbitMQUri = rabbitmqUri
|
||||
c.RabbitMQInvoiceExchange = "test_lndhub_invoices"
|
||||
}
|
||||
|
||||
dbConn, err := db.Open(c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to database: %w", err)
|
||||
|
||||
@@ -63,7 +63,7 @@ func (suite *WebHookTestSuite) SetupSuite() {
|
||||
suite.invoiceUpdateSubCancelFn = cancel
|
||||
go svc.InvoiceUpdateSubscription(ctx)
|
||||
|
||||
go svc.StartWebhookSubscribtion(ctx, svc.Config.WebhookUrl)
|
||||
go svc.StartWebhookSubscription(ctx, svc.Config.WebhookUrl)
|
||||
|
||||
suite.service = svc
|
||||
e := echo.New()
|
||||
|
||||
@@ -39,6 +39,8 @@ type Config struct {
|
||||
MaxReceiveAmount int64 `envconfig:"MAX_RECEIVE_AMOUNT" default:"0"`
|
||||
MaxSendAmount int64 `envconfig:"MAX_SEND_AMOUNT" default:"0"`
|
||||
MaxAccountBalance int64 `envconfig:"MAX_ACCOUNT_BALANCE" default:"0"`
|
||||
RabbitMQUri string `envconfig:"RABBITMQ_URI"`
|
||||
RabbitMQInvoiceExchange string `envconfig:"RABBITMQ_INVOICE_EXCHANGE" default:"lndhub_invoice"`
|
||||
Branding BrandingConfig
|
||||
}
|
||||
|
||||
|
||||
113
lib/service/rabbitmq.go
Normal file
113
lib/service/rabbitmq.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/getAlby/lndhub.go/db/models"
|
||||
"github.com/getsentry/sentry-go"
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
)
|
||||
|
||||
var bufPool sync.Pool = sync.Pool{
|
||||
New: func() interface{} { return new(bytes.Buffer) },
|
||||
}
|
||||
|
||||
func (svc *LndhubService) StartRabbitMqPublisher(ctx context.Context) error {
|
||||
// It is recommended that, when possible, publishers and consumers
|
||||
// use separate connections so that consumers are isolated from potential
|
||||
// flow control messures that may be applied to publishing connections.
|
||||
// We therefore start a single publishing connection here instead of storing
|
||||
// one on the service object.
|
||||
conn, err := amqp.Dial(svc.Config.RabbitMQUri)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
ch, err := conn.Channel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ch.Close()
|
||||
|
||||
err = ch.ExchangeDeclare(
|
||||
// For the time being we simply declare a single exchange and start pushing to it.
|
||||
// Towards the future however this might become a more involved setup.
|
||||
svc.Config.RabbitMQInvoiceExchange,
|
||||
// topic is a type of exchange that allows routing messages to different queue's bases on a routing key
|
||||
"topic",
|
||||
// Durable and Non-Auto-Deleted exchanges will survive server restarts and remain
|
||||
// declared when there are no remaining bindings.
|
||||
true,
|
||||
false,
|
||||
// Non-Internal exchange's accept direct publishing
|
||||
false,
|
||||
// Nowait: We set this to false as we want to wait for a server response
|
||||
// to check wether the exchange was created succesfully
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
svc.Logger.Infof("Starting rabbitmq publisher")
|
||||
|
||||
incomingInvoices, outgoingInvoices, err := svc.subscribeIncomingOutgoingInvoices()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return context.Canceled
|
||||
case incoming := <-incomingInvoices:
|
||||
err = svc.publishInvoice(ctx, incoming, ch)
|
||||
if err != nil {
|
||||
svc.Logger.Error(err)
|
||||
sentry.CaptureException(err)
|
||||
}
|
||||
case outgoing := <-outgoingInvoices:
|
||||
err = svc.publishInvoice(ctx, outgoing, ch)
|
||||
if err != nil {
|
||||
svc.Logger.Error(err)
|
||||
sentry.CaptureException(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *LndhubService) publishInvoice(ctx context.Context, invoice models.Invoice, ch *amqp.Channel) error {
|
||||
key := fmt.Sprintf("invoice.%s.%s", invoice.Type, invoice.State)
|
||||
|
||||
user, err := svc.FindUser(context.Background(), invoice.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
payload := bufPool.Get().(*bytes.Buffer)
|
||||
err = json.NewEncoder(payload).Encode(convertPayload(invoice, user))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ch.PublishWithContext(ctx,
|
||||
svc.Config.RabbitMQInvoiceExchange,
|
||||
key,
|
||||
false,
|
||||
false,
|
||||
amqp.Publishing{
|
||||
ContentType: "application/json",
|
||||
Body: payload.Bytes(),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
svc.Logger.Debugf("Succesfully published invoice to rabbitmq with RHash %s", invoice.RHash)
|
||||
return nil
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -12,16 +12,11 @@ import (
|
||||
"github.com/getAlby/lndhub.go/db/models"
|
||||
)
|
||||
|
||||
func (svc *LndhubService) StartWebhookSubscribtion(ctx context.Context, url string) {
|
||||
|
||||
func (svc *LndhubService) StartWebhookSubscription(ctx context.Context, url string) {
|
||||
svc.Logger.Infof("Starting webhook subscription with webhook url %s", svc.Config.WebhookUrl)
|
||||
incomingInvoices, _, err := svc.InvoicePubSub.Subscribe(common.InvoiceTypeIncoming)
|
||||
incomingInvoices, outgoingInvoices, err := svc.subscribeIncomingOutgoingInvoices()
|
||||
if err != nil {
|
||||
svc.Logger.Error(err.Error())
|
||||
}
|
||||
outgoingInvoices, _, err := svc.InvoicePubSub.Subscribe(common.InvoiceTypeOutgoing)
|
||||
if err != nil {
|
||||
svc.Logger.Error(err.Error())
|
||||
svc.Logger.Error(err)
|
||||
}
|
||||
for {
|
||||
select {
|
||||
@@ -44,27 +39,7 @@ func (svc *LndhubService) postToWebhook(invoice models.Invoice, url string) {
|
||||
}
|
||||
|
||||
payload := new(bytes.Buffer)
|
||||
err = json.NewEncoder(payload).Encode(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,
|
||||
})
|
||||
err = json.NewEncoder(payload).Encode(convertPayload(invoice, user))
|
||||
if err != nil {
|
||||
svc.Logger.Error(err)
|
||||
return
|
||||
@@ -76,7 +51,7 @@ func (svc *LndhubService) postToWebhook(invoice models.Invoice, url string) {
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
msg, err := ioutil.ReadAll(resp.Body)
|
||||
msg, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
svc.Logger.Error(err)
|
||||
}
|
||||
@@ -105,3 +80,39 @@ type WebhookInvoicePayload struct {
|
||||
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 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,
|
||||
}
|
||||
}
|
||||
|
||||
15
main.go
15
main.go
@@ -202,11 +202,24 @@ func main() {
|
||||
if svc.Config.WebhookUrl != "" {
|
||||
backgroundWg.Add(1)
|
||||
go func() {
|
||||
svc.StartWebhookSubscribtion(backGroundCtx, svc.Config.WebhookUrl)
|
||||
svc.StartWebhookSubscription(backGroundCtx, svc.Config.WebhookUrl)
|
||||
svc.Logger.Info("Webhook routine done")
|
||||
backgroundWg.Done()
|
||||
}()
|
||||
}
|
||||
//Start rabbit publisher
|
||||
if svc.Config.RabbitMQUri != "" {
|
||||
backgroundWg.Add(1)
|
||||
go func() {
|
||||
err = svc.StartRabbitMqPublisher(backGroundCtx)
|
||||
if err != nil {
|
||||
svc.Logger.Error(err)
|
||||
sentry.CaptureException(err)
|
||||
}
|
||||
svc.Logger.Info("Rabbit routine done")
|
||||
backgroundWg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
var grpcServer *grpc.Server
|
||||
if svc.Config.EnableGRPC {
|
||||
|
||||
Reference in New Issue
Block a user