lnd.xprv/mobile/bindings.go

153 lines
4.1 KiB
Go
Raw Normal View History

// +build mobile
2019-01-24 16:51:06 +03:00
package lndmobile
import (
"errors"
2019-01-24 16:51:06 +03:00
"fmt"
"os"
"strings"
"sync/atomic"
2019-01-24 16:51:06 +03:00
flags "github.com/jessevdk/go-flags"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/signal"
"google.golang.org/grpc"
2019-01-24 16:51:06 +03:00
)
// lndStarted will be used atomically to ensure only a singel lnd instance is
// attempted to be started at once.
var lndStarted int32
2019-01-24 16:51:06 +03:00
// Start starts lnd in a new goroutine.
//
// extraArgs can be used to pass command line arguments to lnd that will
// override what is found in the config file. Example:
// extraArgs = "--bitcoin.testnet --lnddir=\"/tmp/folder name/\" --profile=5050"
//
// The rpcReady is called lnd is ready to accept RPC calls.
//
// NOTE: On mobile platforms the '--lnddir` argument should be set to the
// current app directory in order to ensure lnd has the permissions needed to
// write to it.
func Start(extraArgs string, rpcReady Callback) {
// (Re-)initialize the in-mem gRPC listeners we're going to give to lnd.
// This is required each time lnd is started, because when lnd shuts
// down, the in-mem listeners are closed.
RecreateListeners()
2019-01-24 16:51:06 +03:00
// Split the argument string on "--" to get separated command line
// arguments.
var splitArgs []string
for _, a := range strings.Split(extraArgs, "--") {
// Trim any whitespace space, and ignore empty params.
a := strings.TrimSpace(a)
2019-01-24 16:51:06 +03:00
if a == "" {
continue
}
// Finally we prefix any non-empty string with -- to mimic the
// regular command line arguments.
splitArgs = append(splitArgs, "--"+a)
2019-01-24 16:51:06 +03:00
}
// Add the extra arguments to os.Args, as that will be parsed in
// LoadConfig below.
2019-01-24 16:51:06 +03:00
os.Args = append(os.Args, splitArgs...)
// Hook interceptor for os signals.
shutdownInterceptor, err := signal.Intercept()
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
rpcReady.OnError(err)
return
}
// Load the configuration, and parse the extra arguments as command
// line options. This function will also set up logging properly.
loadedConfig, err := lnd.LoadConfig(shutdownInterceptor)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
rpcReady.OnError(err)
return
}
// Set a channel that will be notified when the RPC server is ready to
// accept calls.
var (
rpcListening = make(chan struct{})
quit = make(chan struct{})
)
// We call the main method with the custom in-memory listener called by
// the mobile APIs, such that the grpc server will use it.
2019-01-24 16:51:06 +03:00
cfg := lnd.ListenerCfg{
RPCListener: &lnd.ListenerWithSignal{
Listener: lightningLis,
Ready: rpcListening,
},
2019-01-24 16:51:06 +03:00
}
// We only support a single lnd instance at a time (singleton) for now,
// so we make sure to return immediately if it has already been
// started.
if !atomic.CompareAndSwapInt32(&lndStarted, 0, 1) {
err := errors.New("lnd already started")
rpcReady.OnError(err)
return
}
2019-01-24 16:51:06 +03:00
// Call the "real" main in a nested manner so the defers will properly
// be executed in the case of a graceful shutdown.
go func() {
defer atomic.StoreInt32(&lndStarted, 0)
defer close(quit)
if err := lnd.Main(
loadedConfig, cfg, shutdownInterceptor,
); err != nil {
2019-01-24 16:51:06 +03:00
if e, ok := err.(*flags.Error); ok &&
e.Type == flags.ErrHelp {
} else {
fmt.Fprintln(os.Stderr, err)
}
rpcReady.OnError(err)
return
2019-01-24 16:51:06 +03:00
}
}()
// By default we'll apply the admin auth options, which will include
// macaroons.
setDefaultDialOption(
func() ([]grpc.DialOption, error) {
return lnd.AdminAuthOptions(loadedConfig, false)
},
)
// For the WalletUnlocker and StateService, the macaroons might not be
// available yet when called, so we use a more restricted set of
// options that don't include them.
setWalletUnlockerDialOption(
func() ([]grpc.DialOption, error) {
return lnd.AdminAuthOptions(loadedConfig, true)
},
)
setStateDialOption(
func() ([]grpc.DialOption, error) {
return lnd.AdminAuthOptions(loadedConfig, true)
},
)
// Finally we start a go routine that will call the provided callback
// when the RPC server is ready to accept calls.
go func() {
select {
case <-rpcListening:
case <-quit:
return
}
rpcReady.OnResponse([]byte{})
}()
2019-01-24 16:51:06 +03:00
}