resolve merge conflicts

This commit is contained in:
kiwiidb
2023-02-20 17:36:37 +01:00
10 changed files with 371 additions and 665 deletions

View File

@@ -25,6 +25,14 @@ jobs:
--health-interval 10s --health-interval 10s
--health-timeout 5s --health-timeout 5s
--health-retries 5 --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: steps:
- name: Install Go - name: Install Go
uses: actions/setup-go@v1 uses: actions/setup-go@v1
@@ -34,3 +42,6 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Run tests - name: Run tests
run: go test -p 1 -v -cover -coverpkg=./... ./... run: go test -p 1 -v -cover -coverpkg=./... ./...
env:
RABBITMQ_URI: amqp://root:password@localhost:5672

24
go.mod
View File

@@ -14,6 +14,7 @@ require (
github.com/labstack/echo/v4 v4.10.0 github.com/labstack/echo/v4 v4.10.0
github.com/labstack/gommon v0.4.0 github.com/labstack/gommon v0.4.0
github.com/lightningnetwork/lnd v0.15.5-beta.rc2 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/stretchr/testify v1.8.1
github.com/uptrace/bun v1.1.10 github.com/uptrace/bun v1.1.10
github.com/uptrace/bun/dialect/pgdialect 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/KyleBanks/depth v1.2.1 // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/aead/siphash v1.0.1 // 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/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect
github.com/btcsuite/btcd/btcutil/psbt v1.1.6 // 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/crypto/blake256 v1.0.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/decred/dcrd/lru v1.1.1 // 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/dustin/go-humanize v1.0.1 // indirect
github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6 // indirect github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6 // indirect
github.com/fatih/color v1.13.0 // indirect github.com/fatih/color v1.13.0 // indirect
github.com/fergusstrange/embedded-postgres v1.19.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-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // 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/josharian/intern v1.0.0 // indirect
github.com/jrick/logrotate v1.0.0 // indirect github.com/jrick/logrotate v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // 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/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/leodido/go-urn v1.2.1 // indirect
github.com/lib/pq v1.10.7 // indirect github.com/lib/pq v1.10.7 // indirect
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // 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-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-isatty v0.0.17 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // 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/miekg/dns v1.1.50 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // 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/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.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/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // 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/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/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // 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/pkg/v3 v3.5.6 // indirect
go.etcd.io/etcd/raft/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.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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.37.0 // indirect
go.opentelemetry.io/otel v1.11.2 // 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/internal/retry v1.11.2 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace 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/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/metric v0.34.0 // indirect
go.opentelemetry.io/otel/sdk v1.11.2 // 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/otel/trace v1.11.2 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect

624
go.sum

File diff suppressed because it is too large Load Diff

View 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))
}

View File

@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os"
"time" "time"
"github.com/getAlby/lndhub.go/db" "github.com/getAlby/lndhub.go/db"
@@ -56,6 +57,13 @@ func LndHubTestServiceInit(lndClientMock lnd.LightningClientWrapper) (svc *servi
LNDAddress: mockLNDAddress, LNDAddress: mockLNDAddress,
LNDMacaroonHex: mockLNDMacaroonHex, LNDMacaroonHex: mockLNDMacaroonHex,
} }
rabbitmqUri, ok := os.LookupEnv("RABBITMQ_URI")
if ok {
c.RabbitMQUri = rabbitmqUri
c.RabbitMQInvoiceExchange = "test_lndhub_invoices"
}
dbConn, err := db.Open(c) dbConn, err := db.Open(c)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to connect to database: %w", err) return nil, fmt.Errorf("failed to connect to database: %w", err)

View File

@@ -63,7 +63,7 @@ func (suite *WebHookTestSuite) SetupSuite() {
suite.invoiceUpdateSubCancelFn = cancel suite.invoiceUpdateSubCancelFn = cancel
go svc.InvoiceUpdateSubscription(ctx) go svc.InvoiceUpdateSubscription(ctx)
go svc.StartWebhookSubscribtion(ctx, svc.Config.WebhookUrl) go svc.StartWebhookSubscription(ctx, svc.Config.WebhookUrl)
suite.service = svc suite.service = svc
e := echo.New() e := echo.New()

View File

@@ -39,6 +39,8 @@ type Config struct {
MaxReceiveAmount int64 `envconfig:"MAX_RECEIVE_AMOUNT" default:"0"` MaxReceiveAmount int64 `envconfig:"MAX_RECEIVE_AMOUNT" default:"0"`
MaxSendAmount int64 `envconfig:"MAX_SEND_AMOUNT" default:"0"` MaxSendAmount int64 `envconfig:"MAX_SEND_AMOUNT" default:"0"`
MaxAccountBalance int64 `envconfig:"MAX_ACCOUNT_BALANCE" 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 Branding BrandingConfig
} }

113
lib/service/rabbitmq.go Normal file
View 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
}

View File

@@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"io/ioutil" "io"
"net/http" "net/http"
"time" "time"
@@ -12,16 +12,11 @@ import (
"github.com/getAlby/lndhub.go/db/models" "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) 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 { if err != nil {
svc.Logger.Error(err.Error()) svc.Logger.Error(err)
}
outgoingInvoices, _, err := svc.InvoicePubSub.Subscribe(common.InvoiceTypeOutgoing)
if err != nil {
svc.Logger.Error(err.Error())
} }
for { for {
select { select {
@@ -44,27 +39,7 @@ func (svc *LndhubService) postToWebhook(invoice models.Invoice, url string) {
} }
payload := new(bytes.Buffer) payload := new(bytes.Buffer)
err = json.NewEncoder(payload).Encode(WebhookInvoicePayload{ err = json.NewEncoder(payload).Encode(convertPayload(invoice, user))
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,
})
if err != nil { if err != nil {
svc.Logger.Error(err) svc.Logger.Error(err)
return return
@@ -76,7 +51,7 @@ func (svc *LndhubService) postToWebhook(invoice models.Invoice, url string) {
return return
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
msg, err := ioutil.ReadAll(resp.Body) msg, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
svc.Logger.Error(err) svc.Logger.Error(err)
} }
@@ -105,3 +80,39 @@ type WebhookInvoicePayload struct {
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
SettledAt time.Time `json:"settled_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
View File

@@ -202,11 +202,24 @@ func main() {
if svc.Config.WebhookUrl != "" { if svc.Config.WebhookUrl != "" {
backgroundWg.Add(1) backgroundWg.Add(1)
go func() { go func() {
svc.StartWebhookSubscribtion(backGroundCtx, svc.Config.WebhookUrl) svc.StartWebhookSubscription(backGroundCtx, svc.Config.WebhookUrl)
svc.Logger.Info("Webhook routine done") svc.Logger.Info("Webhook routine done")
backgroundWg.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 var grpcServer *grpc.Server
if svc.Config.EnableGRPC { if svc.Config.EnableGRPC {