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 (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
|
@ -21,12 +19,9 @@ import (
|
|||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
grpcProxy "github.com/mwitkow/grpc-proxy/proxy"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/backoff"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
"gopkg.in/macaroon.v2"
|
||||
)
|
||||
|
||||
|
|
@ -65,7 +60,7 @@ func (e *proxyErr) Unwrap() error {
|
|||
// component.
|
||||
func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
|
||||
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
|
||||
// by base64(username:password). Because we only have a password, we
|
||||
|
|
@ -85,7 +80,6 @@ func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
|
|||
permsMgr: permsMgr,
|
||||
macValidator: validator,
|
||||
superMacValidator: superMacValidator,
|
||||
bufListener: bufListener,
|
||||
}
|
||||
p.grpcServer = grpc.NewServer(
|
||||
// From the grpxProxy doc: This codec is *crucial* to the
|
||||
|
|
@ -162,7 +156,6 @@ type rpcProxy struct {
|
|||
|
||||
macValidator macaroons.MacaroonValidator
|
||||
superMacValidator session.SuperMacaroonValidator
|
||||
bufListener *bufconn.Listener
|
||||
|
||||
superMacaroon string
|
||||
|
||||
|
|
@ -176,21 +169,9 @@ type rpcProxy struct {
|
|||
}
|
||||
|
||||
// Start creates initial connection to lnd.
|
||||
func (p *rpcProxy) Start() error {
|
||||
func (p *rpcProxy) Start(lndConn *grpc.ClientConn) error {
|
||||
var err error
|
||||
|
||||
// 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)
|
||||
}
|
||||
p.lndConn = lndConn
|
||||
|
||||
// Make sure we can connect to all the daemons that are configured to be
|
||||
// running in remote mode.
|
||||
|
|
@ -242,13 +223,6 @@ func (p *rpcProxy) hasStarted() bool {
|
|||
func (p *rpcProxy) Stop() error {
|
||||
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 err := p.faradayConn.Close(); err != nil {
|
||||
log.Errorf("Error closing faraday connection: %v", err)
|
||||
|
|
@ -681,68 +655,6 @@ func (p *rpcProxy) convertSuperMacaroon(ctx context.Context, macHex string,
|
|||
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
|
||||
// gRPC dial options from it.
|
||||
func readMacaroon(macPath string) ([]byte, error) {
|
||||
|
|
|
|||
18
terminal.go
18
terminal.go
|
|
@ -160,6 +160,7 @@ type LightningTerminal struct {
|
|||
wg sync.WaitGroup
|
||||
errQueue *queue.ConcurrentQueue[error]
|
||||
|
||||
lndConn *grpc.ClientConn
|
||||
lndClient *lndclient.GrpcLndServices
|
||||
basicClient lnrpc.LightningClient
|
||||
|
||||
|
|
@ -244,7 +245,7 @@ func (g *LightningTerminal) Run() error {
|
|||
g.loopServer = loopd.New(g.cfg.Loop, nil)
|
||||
g.poolServer = pool.NewServer(g.cfg.Pool)
|
||||
g.rpcProxy = newRpcProxy(
|
||||
g.cfg, g, g.validateSuperMacaroon, g.permsMgr, bufRpcListener,
|
||||
g.cfg, g, g.validateSuperMacaroon, g.permsMgr,
|
||||
)
|
||||
g.accountService, err = accounts.NewService(
|
||||
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
|
||||
// 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
|
||||
// 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",
|
||||
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 err := g.httpServer.Close(); err != nil {
|
||||
log.Errorf("Error stopping UI server: %v", err)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue