mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
multi: split out LND connection from rpcProxy
Remove the responsibility of creating an LND connection from the rpcProxy and instead let the main LightningTerminal struct handle it. All the lnd-connection specific functions are also moved into their own file.
This commit is contained in:
parent
116322d72c
commit
37b24d59dd
3 changed files with 104 additions and 93 deletions
85
lnd_connection.go
Normal file
85
lnd_connection.go
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
package terminal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
grpcProxy "github.com/mwitkow/grpc-proxy/proxy"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/backoff"
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
|
"google.golang.org/grpc/test/bufconn"
|
||||||
|
)
|
||||||
|
|
||||||
|
// connectLND sets up LiT's LND connection.
|
||||||
|
func connectLND(cfg *Config, bufListener *bufconn.Listener) (*grpc.ClientConn,
|
||||||
|
error) {
|
||||||
|
|
||||||
|
if cfg.lndRemote {
|
||||||
|
host, _, tlsPath, _, _ := cfg.lndConnectParams()
|
||||||
|
return dialBackend("lnd", host, tlsPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If LND is running in integrated mode, then we use a bufconn to
|
||||||
|
// connect to lnd in integrated mode.
|
||||||
|
return dialBufConnBackend(bufListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialBackend connects to a gRPC backend through the given address and uses the
|
||||||
|
// given TLS certificate to authenticate the connection.
|
||||||
|
func dialBackend(name, dialAddr, tlsCertPath string) (*grpc.ClientConn, error) {
|
||||||
|
tlsConfig, err := credentials.NewClientTLSFromFile(tlsCertPath, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read %s TLS cert %s: %v",
|
||||||
|
name, tlsCertPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := []grpc.DialOption{
|
||||||
|
// From the grpcProxy doc: This codec is *crucial* to the
|
||||||
|
// functioning of the proxy.
|
||||||
|
grpc.WithCodec(grpcProxy.Codec()), // nolint
|
||||||
|
grpc.WithTransportCredentials(tlsConfig),
|
||||||
|
grpc.WithDefaultCallOptions(maxMsgRecvSize),
|
||||||
|
grpc.WithConnectParams(grpc.ConnectParams{
|
||||||
|
Backoff: backoff.DefaultConfig,
|
||||||
|
MinConnectTimeout: defaultConnectTimeout,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Dialing %s gRPC server at %s", name, dialAddr)
|
||||||
|
cc, err := grpc.Dial(dialAddr, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed dialing %s backend: %v", name,
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
return cc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialBufConnBackend dials an in-memory connection to an RPC listener and
|
||||||
|
// ignores any TLS certificate mismatches.
|
||||||
|
func dialBufConnBackend(listener *bufconn.Listener) (*grpc.ClientConn, error) {
|
||||||
|
tlsConfig := credentials.NewTLS(&tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
opts := []grpc.DialOption{
|
||||||
|
grpc.WithContextDialer(
|
||||||
|
func(context.Context, string) (net.Conn, error) {
|
||||||
|
return listener.Dial()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// From the grpcProxy doc: This codec is *crucial* to the
|
||||||
|
// functioning of the proxy.
|
||||||
|
grpc.WithCodec(grpcProxy.Codec()), // nolint
|
||||||
|
grpc.WithTransportCredentials(tlsConfig),
|
||||||
|
grpc.WithDefaultCallOptions(maxMsgRecvSize),
|
||||||
|
grpc.WithConnectParams(grpc.ConnectParams{
|
||||||
|
Backoff: backoff.DefaultConfig,
|
||||||
|
MinConnectTimeout: defaultConnectTimeout,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
return grpc.Dial("", opts...)
|
||||||
|
}
|
||||||
94
rpc_proxy.go
94
rpc_proxy.go
|
|
@ -2,12 +2,10 @@ package terminal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
@ -21,12 +19,9 @@ import (
|
||||||
"github.com/lightningnetwork/lnd/macaroons"
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
grpcProxy "github.com/mwitkow/grpc-proxy/proxy"
|
grpcProxy "github.com/mwitkow/grpc-proxy/proxy"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/backoff"
|
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"google.golang.org/grpc/test/bufconn"
|
|
||||||
"gopkg.in/macaroon.v2"
|
"gopkg.in/macaroon.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -65,7 +60,7 @@ func (e *proxyErr) Unwrap() error {
|
||||||
// component.
|
// component.
|
||||||
func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
|
func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
|
||||||
superMacValidator session.SuperMacaroonValidator,
|
superMacValidator session.SuperMacaroonValidator,
|
||||||
permsMgr *perms.Manager, bufListener *bufconn.Listener) *rpcProxy {
|
permsMgr *perms.Manager) *rpcProxy {
|
||||||
|
|
||||||
// The gRPC web calls are protected by HTTP basic auth which is defined
|
// The gRPC web calls are protected by HTTP basic auth which is defined
|
||||||
// by base64(username:password). Because we only have a password, we
|
// by base64(username:password). Because we only have a password, we
|
||||||
|
|
@ -85,7 +80,6 @@ func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
|
||||||
permsMgr: permsMgr,
|
permsMgr: permsMgr,
|
||||||
macValidator: validator,
|
macValidator: validator,
|
||||||
superMacValidator: superMacValidator,
|
superMacValidator: superMacValidator,
|
||||||
bufListener: bufListener,
|
|
||||||
}
|
}
|
||||||
p.grpcServer = grpc.NewServer(
|
p.grpcServer = grpc.NewServer(
|
||||||
// From the grpxProxy doc: This codec is *crucial* to the
|
// From the grpxProxy doc: This codec is *crucial* to the
|
||||||
|
|
@ -162,7 +156,6 @@ type rpcProxy struct {
|
||||||
|
|
||||||
macValidator macaroons.MacaroonValidator
|
macValidator macaroons.MacaroonValidator
|
||||||
superMacValidator session.SuperMacaroonValidator
|
superMacValidator session.SuperMacaroonValidator
|
||||||
bufListener *bufconn.Listener
|
|
||||||
|
|
||||||
superMacaroon string
|
superMacaroon string
|
||||||
|
|
||||||
|
|
@ -176,21 +169,9 @@ type rpcProxy struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start creates initial connection to lnd.
|
// Start creates initial connection to lnd.
|
||||||
func (p *rpcProxy) Start() error {
|
func (p *rpcProxy) Start(lndConn *grpc.ClientConn) error {
|
||||||
var err error
|
var err error
|
||||||
|
p.lndConn = lndConn
|
||||||
// Setup the connection to lnd.
|
|
||||||
host, _, tlsPath, _, _ := p.cfg.lndConnectParams()
|
|
||||||
|
|
||||||
// We use a bufconn to connect to lnd in integrated mode.
|
|
||||||
if p.cfg.LndMode == ModeIntegrated {
|
|
||||||
p.lndConn, err = dialBufConnBackend(p.bufListener)
|
|
||||||
} else {
|
|
||||||
p.lndConn, err = dialBackend("lnd", host, tlsPath)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not dial lnd: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we can connect to all the daemons that are configured to be
|
// Make sure we can connect to all the daemons that are configured to be
|
||||||
// running in remote mode.
|
// running in remote mode.
|
||||||
|
|
@ -242,13 +223,6 @@ func (p *rpcProxy) hasStarted() bool {
|
||||||
func (p *rpcProxy) Stop() error {
|
func (p *rpcProxy) Stop() error {
|
||||||
p.grpcServer.Stop()
|
p.grpcServer.Stop()
|
||||||
|
|
||||||
if p.lndConn != nil {
|
|
||||||
if err := p.lndConn.Close(); err != nil {
|
|
||||||
log.Errorf("Error closing lnd connection: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.faradayConn != nil {
|
if p.faradayConn != nil {
|
||||||
if err := p.faradayConn.Close(); err != nil {
|
if err := p.faradayConn.Close(); err != nil {
|
||||||
log.Errorf("Error closing faraday connection: %v", err)
|
log.Errorf("Error closing faraday connection: %v", err)
|
||||||
|
|
@ -681,68 +655,6 @@ func (p *rpcProxy) convertSuperMacaroon(ctx context.Context, macHex string,
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// dialBufConnBackend dials an in-memory connection to an RPC listener and
|
|
||||||
// ignores any TLS certificate mismatches.
|
|
||||||
func dialBufConnBackend(listener *bufconn.Listener) (*grpc.ClientConn, error) {
|
|
||||||
tlsConfig := credentials.NewTLS(&tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
})
|
|
||||||
conn, err := grpc.Dial(
|
|
||||||
"",
|
|
||||||
grpc.WithContextDialer(
|
|
||||||
func(context.Context, string) (net.Conn, error) {
|
|
||||||
return listener.Dial()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
grpc.WithTransportCredentials(tlsConfig),
|
|
||||||
|
|
||||||
// From the grpcProxy doc: This codec is *crucial* to the
|
|
||||||
// functioning of the proxy.
|
|
||||||
grpc.WithCodec(grpcProxy.Codec()), // nolint
|
|
||||||
grpc.WithTransportCredentials(tlsConfig),
|
|
||||||
grpc.WithDefaultCallOptions(maxMsgRecvSize),
|
|
||||||
grpc.WithConnectParams(grpc.ConnectParams{
|
|
||||||
Backoff: backoff.DefaultConfig,
|
|
||||||
MinConnectTimeout: defaultConnectTimeout,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// dialBackend connects to a gRPC backend through the given address and uses the
|
|
||||||
// given TLS certificate to authenticate the connection.
|
|
||||||
func dialBackend(name, dialAddr, tlsCertPath string) (*grpc.ClientConn, error) {
|
|
||||||
var opts []grpc.DialOption
|
|
||||||
tlsConfig, err := credentials.NewClientTLSFromFile(tlsCertPath, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not read %s TLS cert %s: %v",
|
|
||||||
name, tlsCertPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts = append(
|
|
||||||
opts,
|
|
||||||
|
|
||||||
// From the grpcProxy doc: This codec is *crucial* to the
|
|
||||||
// functioning of the proxy.
|
|
||||||
grpc.WithCodec(grpcProxy.Codec()), // nolint
|
|
||||||
grpc.WithTransportCredentials(tlsConfig),
|
|
||||||
grpc.WithDefaultCallOptions(maxMsgRecvSize),
|
|
||||||
grpc.WithConnectParams(grpc.ConnectParams{
|
|
||||||
Backoff: backoff.DefaultConfig,
|
|
||||||
MinConnectTimeout: defaultConnectTimeout,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
log.Infof("Dialing %s gRPC server at %s", name, dialAddr)
|
|
||||||
cc, err := grpc.Dial(dialAddr, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed dialing %s backend: %v", name,
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
return cc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// readMacaroon tries to read the macaroon file at the specified path and create
|
// readMacaroon tries to read the macaroon file at the specified path and create
|
||||||
// gRPC dial options from it.
|
// gRPC dial options from it.
|
||||||
func readMacaroon(macPath string) ([]byte, error) {
|
func readMacaroon(macPath string) ([]byte, error) {
|
||||||
|
|
|
||||||
18
terminal.go
18
terminal.go
|
|
@ -160,6 +160,7 @@ type LightningTerminal struct {
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
errQueue *queue.ConcurrentQueue[error]
|
errQueue *queue.ConcurrentQueue[error]
|
||||||
|
|
||||||
|
lndConn *grpc.ClientConn
|
||||||
lndClient *lndclient.GrpcLndServices
|
lndClient *lndclient.GrpcLndServices
|
||||||
basicClient lnrpc.LightningClient
|
basicClient lnrpc.LightningClient
|
||||||
|
|
||||||
|
|
@ -244,7 +245,7 @@ func (g *LightningTerminal) Run() error {
|
||||||
g.loopServer = loopd.New(g.cfg.Loop, nil)
|
g.loopServer = loopd.New(g.cfg.Loop, nil)
|
||||||
g.poolServer = pool.NewServer(g.cfg.Pool)
|
g.poolServer = pool.NewServer(g.cfg.Pool)
|
||||||
g.rpcProxy = newRpcProxy(
|
g.rpcProxy = newRpcProxy(
|
||||||
g.cfg, g, g.validateSuperMacaroon, g.permsMgr, bufRpcListener,
|
g.cfg, g, g.validateSuperMacaroon, g.permsMgr,
|
||||||
)
|
)
|
||||||
g.accountService, err = accounts.NewService(
|
g.accountService, err = accounts.NewService(
|
||||||
filepath.Dir(g.cfg.MacaroonPath), g.errQueue.ChanIn(),
|
filepath.Dir(g.cfg.MacaroonPath), g.errQueue.ChanIn(),
|
||||||
|
|
@ -436,11 +437,17 @@ func (g *LightningTerminal) Run() error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Connect to LND.
|
||||||
|
g.lndConn, err = connectLND(g.cfg, bufRpcListener)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not connect to LND: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Now start the RPC proxy that will handle all incoming gRPC, grpc-web
|
// Now start the RPC proxy that will handle all incoming gRPC, grpc-web
|
||||||
// and REST requests. We also start the main web server that dispatches
|
// and REST requests. We also start the main web server that dispatches
|
||||||
// requests either to the static UI file server or the RPC proxy. This
|
// requests either to the static UI file server or the RPC proxy. This
|
||||||
// makes it possible to unlock lnd through the UI.
|
// makes it possible to unlock lnd through the UI.
|
||||||
if err := g.rpcProxy.Start(); err != nil {
|
if err := g.rpcProxy.Start(g.lndConn); err != nil {
|
||||||
return fmt.Errorf("error starting lnd gRPC proxy server: %v",
|
return fmt.Errorf("error starting lnd gRPC proxy server: %v",
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
@ -1178,6 +1185,13 @@ func (g *LightningTerminal) shutdown() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if g.lndConn != nil {
|
||||||
|
if err := g.lndConn.Close(); err != nil {
|
||||||
|
log.Errorf("Error closing lnd connection: %v", err)
|
||||||
|
returnErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if g.httpServer != nil {
|
if g.httpServer != nil {
|
||||||
if err := g.httpServer.Close(); err != nil {
|
if err := g.httpServer.Close(); err != nil {
|
||||||
log.Errorf("Error stopping UI server: %v", err)
|
log.Errorf("Error stopping UI server: %v", err)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue