Merge pull request #115 from halseth/loopd-mobile

Create loopd package, allow custom listeners
pull/130/head
Johan T. Halseth 4 years ago committed by GitHub
commit 5e00ce6267
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

3
.gitignore vendored

@ -29,9 +29,6 @@ output*.log
loop
!cmd/loop/
loopd
!cmd/loopd/
*.key
*.hex

@ -2,118 +2,14 @@ package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"github.com/jessevdk/go-flags"
"github.com/lightninglabs/loop"
"github.com/lightningnetwork/lnd/build"
"github.com/lightningnetwork/lnd/lntypes"
)
const (
defaultConfTarget = int32(6)
)
var (
defaultConfigFilename = "loopd.conf"
swaps = make(map[lntypes.Hash]loop.SwapInfo)
subscribers = make(map[int]chan<- interface{})
nextSubscriberID int
swapsLock sync.Mutex
"github.com/lightninglabs/loop/loopd"
)
func main() {
err := start()
cfg := loopd.RPCConfig{}
err := loopd.Start(cfg)
if err != nil {
fmt.Println(err)
}
}
func start() error {
config := defaultConfig
// Parse command line flags.
parser := flags.NewParser(&config, flags.Default)
parser.SubcommandsOptional = true
_, err := parser.Parse()
if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
return nil
}
if err != nil {
return err
}
// Parse ini file.
loopDir := filepath.Join(loopDirBase, config.Network)
if err := os.MkdirAll(loopDir, os.ModePerm); err != nil {
return err
}
configFile := filepath.Join(loopDir, defaultConfigFilename)
if err := flags.IniParse(configFile, &config); err != nil {
// If it's a parsing related error, then we'll return
// immediately, otherwise we can proceed as possibly the config
// file doesn't exist which is OK.
if _, ok := err.(*flags.IniError); ok {
return err
}
}
// Parse command line flags again to restore flags overwritten by ini
// parse.
_, err = parser.Parse()
if err != nil {
return err
}
// Show the version and exit if the version flag was specified.
appName := filepath.Base(os.Args[0])
appName = strings.TrimSuffix(appName, filepath.Ext(appName))
if config.ShowVersion {
fmt.Println(appName, "version", loop.Version())
os.Exit(0)
}
// Special show command to list supported subsystems and exit.
if config.DebugLevel == "show" {
fmt.Printf("Supported subsystems: %v\n",
logWriter.SupportedSubsystems())
os.Exit(0)
}
// Append the network type to the log directory so it is
// "namespaced" per network in the same fashion as the data directory.
config.LogDir = filepath.Join(config.LogDir, config.Network)
// Initialize logging at the default logging level.
err = logWriter.InitLogRotator(
filepath.Join(config.LogDir, defaultLogFilename),
config.MaxLogFileSize, config.MaxLogFiles,
)
if err != nil {
return err
}
err = build.ParseAndSetDebugLevels(config.DebugLevel, logWriter)
if err != nil {
return err
}
// Print the version before executing either primary directive.
log.Infof("Version: %v", loop.Version())
// Execute command.
if parser.Active == nil {
return daemon(&config)
}
if parser.Active.Name == "view" {
return view(&config)
}
return fmt.Errorf("unimplemented command %v", parser.Active.Name)
}

@ -10,7 +10,7 @@ require (
github.com/google/go-cmp v0.3.1 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.10.0
github.com/jessevdk/go-flags v1.4.0
github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20191212054348-dca31c2bf8be
github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20200103000305-22e1f006b194
github.com/lightningnetwork/lnd/queue v1.0.2
github.com/urfave/cli v1.20.0
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect

@ -136,10 +136,11 @@ github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
github.com/lightninglabs/neutrino v0.11.0 h1:lPpYFCtsfJX2W5zI4pWycPmbbBdr7zU+BafYdLoD6k0=
github.com/lightninglabs/neutrino v0.11.0/go.mod h1:CuhF0iuzg9Sp2HO6ZgXgayviFTn1QHdSTJlMncK80wg=
github.com/lightningnetwork/lightning-onion v0.0.0-20190909101754-850081b08b6a h1:GoWPN4i4jTKRxhVNh9a2vvBBO1Y2seiJB+SopUYoKyo=
github.com/lightningnetwork/lightning-onion v0.0.0-20190909101754-850081b08b6a/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20191212054348-dca31c2bf8be h1:CX8ScoYxJju6AcceHY6nATfRLThZpewqHcgn4sGMdZE=
github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20191212054348-dca31c2bf8be/go.mod h1:60/zDjDYaYPmISAm3J1WWKyyt+ZiAvuET1XzglO8s70=
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI=
github.com/lightningnetwork/lightning-onion v0.0.0-20191214001659-f34e9dc1651d h1:U50MHOOeL6gR3Ee/l0eMvZMpmRo+ydzmlQuIruCyCsA=
github.com/lightningnetwork/lightning-onion v0.0.0-20191214001659-f34e9dc1651d/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20200103000305-22e1f006b194 h1:PCzjJcVWcMbkiQvzFNc3ta0JmiMprFDqzMZsSpd/km8=
github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20200103000305-22e1f006b194/go.mod h1:WHK90FD3m2n6OyWzondS7ho0Uhtgfp30Nxvj24lQYX4=
github.com/lightningnetwork/lnd/cert v1.0.0 h1:J0gtf2UNQX2U+/j5cXnX2wIMSTuJuwrXv7m9qJr2wtw=
github.com/lightningnetwork/lnd/cert v1.0.0/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo=
github.com/lightningnetwork/lnd/queue v1.0.1 h1:jzJKcTy3Nj5lQrooJ3aaw9Lau3I0IwvQR5sqtjdv2R0=

@ -103,7 +103,7 @@ func NewBasicClient(lndHost, tlsPath, macDir, network string, basicOptions ...Ba
// We need to use a custom dialer so we can also connect to unix sockets
// and not just TCP addresses.
opts = append(
opts, grpc.WithDialer(
opts, grpc.WithContextDialer(
lncfg.ClientAddressDialer(defaultRPCPort),
),
)

@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"net"
"path/filepath"
"time"
@ -38,9 +39,24 @@ type GrpcLndServices struct {
cleanup func()
}
// NewLndServices creates a set of required RPC services.
func NewLndServices(lndAddress, application, network, macaroonDir,
tlsPath string) (*GrpcLndServices, error) {
// NewLndServices creates creates a connection to the given lnd instance and
// creates a set of required RPC services.
func NewLndServices(lndAddress, network, macaroonDir, tlsPath string) (
*GrpcLndServices, error) {
// We need to use a custom dialer so we can also connect to unix
// sockets and not just TCP addresses.
dialer := lncfg.ClientAddressDialer(defaultRPCPort)
return NewLndServicesWithDialer(
dialer, lndAddress, network, macaroonDir, tlsPath,
)
}
// NewLndServices creates a set of required RPC services by connecting to lnd
// using the given dialer.
func NewLndServicesWithDialer(dialer dialerFunc, lndAddress, network,
macaroonDir, tlsPath string) (*GrpcLndServices, error) {
// Based on the network, if the macaroon directory isn't set, then
// we'll use the expected default locations.
@ -85,7 +101,7 @@ func NewLndServices(lndAddress, application, network, macaroonDir,
// Setup connection with lnd
log.Infof("Creating lnd connection to %v", lndAddress)
conn, err := getClientConn(lndAddress, network, tlsPath)
conn, err := getClientConn(dialer, lndAddress, tlsPath)
if err != nil {
return nil, err
}
@ -189,7 +205,9 @@ var (
maxMsgRecvSize = grpc.MaxCallRecvMsgSize(1 * 1024 * 1024 * 200)
)
func getClientConn(address string, network string, tlsPath string) (
type dialerFunc func(context.Context, string) (net.Conn, error)
func getClientConn(dialer dialerFunc, address string, tlsPath string) (
*grpc.ClientConn, error) {
// Load the specified TLS certificate and build transport credentials
@ -206,15 +224,12 @@ func getClientConn(address string, network string, tlsPath string) (
// Create a dial options array.
opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
// Use a custom dialer, to allow connections to unix sockets,
// in-memory listeners etc, and not just TCP addresses.
grpc.WithContextDialer(dialer),
}
// We need to use a custom dialer so we can also connect to unix sockets
// and not just TCP addresses.
opts = append(
opts, grpc.WithDialer(
lncfg.ClientAddressDialer(defaultRPCPort),
),
)
conn, err := grpc.Dial(address, opts...)
if err != nil {
return nil, fmt.Errorf("unable to connect to RPC server: %v", err)

@ -1,4 +1,4 @@
package main
package loopd
import (
"path/filepath"

@ -1,4 +1,4 @@
package main
package loopd
import (
"context"
@ -14,14 +14,27 @@ import (
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/lightninglabs/loop"
"github.com/lightninglabs/loop/lndclient"
"github.com/lightninglabs/loop/looprpc"
"google.golang.org/grpc"
)
// listenerCfg holds closures used to retrieve listeners for the gRPC services.
type listenerCfg struct {
// grpcListener returns a listener to use for the gRPC server.
grpcListener func() (net.Listener, error)
// restListener returns a listener to use for the REST proxy.
restListener func() (net.Listener, error)
// getLnd returns a grpc connection to an lnd instance.
getLnd func(string, *lndConfig) (*lndclient.GrpcLndServices, error)
}
// daemon runs loopd in daemon mode. It will listen for grpc connections,
// execute commands and pass back swap status information.
func daemon(config *config) error {
lnd, err := getLnd(config.Network, config.Lnd)
func daemon(config *config, lisCfg *listenerCfg) error {
lnd, err := lisCfg.getLnd(config.Network, config.Lnd)
if err != nil {
return err
}
@ -74,7 +87,7 @@ func daemon(config *config) error {
// Next, start the gRPC server listening for HTTP/2 connections.
log.Infof("Starting gRPC listener")
grpcListener, err := net.Listen("tcp", config.RPCListen)
grpcListener, err := lisCfg.grpcListener()
if err != nil {
return fmt.Errorf("RPC server unable to listen on %s",
config.RPCListen)
@ -95,15 +108,30 @@ func daemon(config *config) error {
return err
}
log.Infof("Starting REST proxy listener")
restListener, err := net.Listen("tcp", config.RESTListen)
restListener, err := lisCfg.restListener()
if err != nil {
return fmt.Errorf("REST proxy unable to listen on %s",
config.RESTListen)
}
defer restListener.Close()
proxy := &http.Server{Handler: mux}
go proxy.Serve(restListener)
// A nil listener indicates REST is disabled.
if restListener != nil {
log.Infof("Starting REST proxy listener")
defer restListener.Close()
proxy := &http.Server{Handler: mux}
go func() {
err := proxy.Serve(restListener)
// ErrServerClosed is always returned when the proxy is
// shut down, so don't log it.
if err != nil && err != http.ErrServerClosed {
log.Error(err)
}
}()
} else {
log.Infof("REST proxy disabled")
}
statusChan := make(chan loop.SwapInfo)
@ -161,7 +189,10 @@ func daemon(config *config) error {
defer wg.Done()
log.Infof("RPC server listening on %s", grpcListener.Addr())
log.Infof("REST proxy listening on %s", restListener.Addr())
if restListener != nil {
log.Infof("REST proxy listening on %s", restListener.Addr())
}
err = grpcServer.Serve(grpcListener)
if err != nil {

@ -1,4 +1,4 @@
package main
package loopd
import (
"github.com/btcsuite/btclog"

@ -0,0 +1,177 @@
package loopd
import (
"context"
"fmt"
"net"
"os"
"path/filepath"
"strings"
"sync"
"github.com/jessevdk/go-flags"
"github.com/lightninglabs/loop"
"github.com/lightninglabs/loop/lndclient"
"github.com/lightningnetwork/lnd/build"
"github.com/lightningnetwork/lnd/lntypes"
)
const (
defaultConfTarget = int32(6)
)
var (
defaultConfigFilename = "loopd.conf"
swaps = make(map[lntypes.Hash]loop.SwapInfo)
subscribers = make(map[int]chan<- interface{})
nextSubscriberID int
swapsLock sync.Mutex
)
// RPCConfig holds optional options that can be used to make the loop daemon
// communicate on custom connections.
type RPCConfig struct {
// RPCListener is an optional listener that if set will override the
// daemon's gRPC settings, and make the gRPC server listen on this
// listener.
// Note that setting this will also disable REST.
RPCListener net.Listener
// LndConn is an optional connection to an lnd instance. If set it will
// override the TCP connection created from daemon's config.
LndConn net.Conn
}
// newListenerCfg creates and returns a new listenerCfg from the passed config
// and RPCConfig.
func newListenerCfg(config *config, rpcCfg RPCConfig) *listenerCfg {
return &listenerCfg{
grpcListener: func() (net.Listener, error) {
// If a custom RPC listener is set, we will listen on
// it instead of the regular tcp socket.
if rpcCfg.RPCListener != nil {
return rpcCfg.RPCListener, nil
}
return net.Listen("tcp", config.RPCListen)
},
restListener: func() (net.Listener, error) {
// If a custom RPC listener is set, we disable REST.
if rpcCfg.RPCListener != nil {
return nil, nil
}
return net.Listen("tcp", config.RESTListen)
},
getLnd: func(network string, cfg *lndConfig) (
*lndclient.GrpcLndServices, error) {
// If a custom lnd connection is specified we use that
// directly.
if rpcCfg.LndConn != nil {
dialer := func(context.Context, string) (
net.Conn, error) {
return rpcCfg.LndConn, nil
}
return lndclient.NewLndServicesWithDialer(
dialer,
rpcCfg.LndConn.RemoteAddr().String(),
network, cfg.MacaroonDir, cfg.TLSPath,
)
}
return lndclient.NewLndServices(
cfg.Host, network, cfg.MacaroonDir, cfg.TLSPath,
)
},
}
}
func Start(rpcCfg RPCConfig) error {
config := defaultConfig
// Parse command line flags.
parser := flags.NewParser(&config, flags.Default)
parser.SubcommandsOptional = true
_, err := parser.Parse()
if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
return nil
}
if err != nil {
return err
}
// Parse ini file.
loopDir := filepath.Join(loopDirBase, config.Network)
if err := os.MkdirAll(loopDir, os.ModePerm); err != nil {
return err
}
configFile := filepath.Join(loopDir, defaultConfigFilename)
if err := flags.IniParse(configFile, &config); err != nil {
// If it's a parsing related error, then we'll return
// immediately, otherwise we can proceed as possibly the config
// file doesn't exist which is OK.
if _, ok := err.(*flags.IniError); ok {
return err
}
}
// Parse command line flags again to restore flags overwritten by ini
// parse.
_, err = parser.Parse()
if err != nil {
return err
}
// Show the version and exit if the version flag was specified.
appName := filepath.Base(os.Args[0])
appName = strings.TrimSuffix(appName, filepath.Ext(appName))
if config.ShowVersion {
fmt.Println(appName, "version", loop.Version())
os.Exit(0)
}
// Special show command to list supported subsystems and exit.
if config.DebugLevel == "show" {
fmt.Printf("Supported subsystems: %v\n",
logWriter.SupportedSubsystems())
os.Exit(0)
}
// Append the network type to the log directory so it is
// "namespaced" per network in the same fashion as the data directory.
config.LogDir = filepath.Join(config.LogDir, config.Network)
// Initialize logging at the default logging level.
err = logWriter.InitLogRotator(
filepath.Join(config.LogDir, defaultLogFilename),
config.MaxLogFileSize, config.MaxLogFiles,
)
if err != nil {
return err
}
err = build.ParseAndSetDebugLevels(config.DebugLevel, logWriter)
if err != nil {
return err
}
// Print the version before executing either primary directive.
log.Infof("Version: %v", loop.Version())
lisCfg := newListenerCfg(&config, rpcCfg)
// Execute command.
if parser.Active == nil {
return daemon(&config, lisCfg)
}
if parser.Active.Name == "view" {
return view(&config, lisCfg)
}
return fmt.Errorf("unimplemented command %v", parser.Active.Name)
}

@ -1,4 +1,4 @@
package main
package loopd
import (
"context"

@ -1,4 +1,4 @@
package main
package loopd
import (
"os"
@ -8,13 +8,6 @@ import (
"github.com/lightninglabs/loop/lndclient"
)
// getLnd returns an instance of the lnd services proxy.
func getLnd(network string, cfg *lndConfig) (*lndclient.GrpcLndServices, error) {
return lndclient.NewLndServices(
cfg.Host, "client", network, cfg.MacaroonDir, cfg.TLSPath,
)
}
// getClient returns an instance of the swap client.
func getClient(network, swapServer string, insecure bool, tlsPathServer string,
lnd *lndclient.LndServices) (*loop.Client, func(), error) {

@ -1,4 +1,4 @@
package main
package loopd
import (
"fmt"
@ -11,13 +11,13 @@ import (
)
// view prints all swaps currently in the database.
func view(config *config) error {
func view(config *config, lisCfg *listenerCfg) error {
chainParams, err := swap.ChainParamsFromNetwork(config.Network)
if err != nil {
return err
}
lnd, err := getLnd(config.Network, config.Lnd)
lnd, err := lisCfg.getLnd(config.Network, config.Lnd)
if err != nil {
return err
}
Loading…
Cancel
Save