finished LND implementation
This commit is contained in:
parent
cc124317ea
commit
f7e60168b4
|
@ -3,10 +3,13 @@ package backends
|
|||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
|
@ -76,3 +79,41 @@ func (lnd *LND) GetInvoice(description string, value int64, expiry int64) (invoi
|
|||
|
||||
return response.PaymentRequest, err
|
||||
}
|
||||
|
||||
func (lnd *LND) SubscribeInvoices() error {
|
||||
stream, err := lnd.client.SubscribeInvoices(lnd.ctx, &lnrpc.InvoiceSubscription{})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wait := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
for {
|
||||
in, streamErr := stream.Recv()
|
||||
|
||||
if streamErr == io.EOF {
|
||||
err = errors.New("lost connection to LND gRPC")
|
||||
|
||||
close(wait)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if streamErr != nil {
|
||||
err = streamErr
|
||||
|
||||
close(wait)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(in)
|
||||
}
|
||||
}()
|
||||
|
||||
<-wait
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
24
config.go
24
config.go
|
@ -10,12 +10,20 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// TODO: add option to show URI of Lightning node
|
||||
|
||||
const (
|
||||
defaultConfigFile = "lightningTip.conf"
|
||||
|
||||
defaultLogFile = "lightningTip.log"
|
||||
defaultLogLevel = "debug"
|
||||
|
||||
defaultRESTHost = "localhost:8081"
|
||||
|
||||
defaultTipMessage = "A generous tip"
|
||||
defaultTipExpiry = 3600
|
||||
defaultTipValue = 100
|
||||
|
||||
defaultLndRPCHost = "localhost:10009"
|
||||
defaultLndCertFile = "tls.cert"
|
||||
defaultMacaroonFile = "admin.macaroon"
|
||||
|
@ -27,13 +35,18 @@ type config struct {
|
|||
LogFile string `long:"logfile" Description:"Log file location"`
|
||||
LogLevel string `long:"loglevel" Description:"Log level: debug, info, warning, error"`
|
||||
|
||||
RESTHost string `long:"resthost" Description:"Host for the rest interface of LightningTip"`
|
||||
|
||||
TipMessage string `long:"tipmessage" Description:"Message embedded in the payment request"`
|
||||
TipExpiry int64 `long:"tipexpiry" Description:"Expiry time in seconds"`
|
||||
DefaultTipValue int64 `long:"defaulttipvalue" Description:"The default value of a tip in satoshis"`
|
||||
|
||||
LND *backends.LND `group:"LND" namespace:"lnd"`
|
||||
}
|
||||
|
||||
var cfg config
|
||||
|
||||
var backend backends.Backend
|
||||
var backendName string
|
||||
|
||||
func initConfig() {
|
||||
lndDir := getDefaultLndDir()
|
||||
|
@ -44,6 +57,12 @@ func initConfig() {
|
|||
LogFile: defaultLogFile,
|
||||
LogLevel: defaultLogLevel,
|
||||
|
||||
RESTHost: defaultRESTHost,
|
||||
|
||||
TipMessage: defaultTipMessage,
|
||||
TipExpiry: defaultTipExpiry,
|
||||
DefaultTipValue: defaultTipValue,
|
||||
|
||||
LND: &backends.LND{
|
||||
RPCHost: defaultLndRPCHost,
|
||||
CertFile: path.Join(lndDir, defaultLndCertFile),
|
||||
|
@ -82,9 +101,8 @@ func initConfig() {
|
|||
log.Infof("Failed to parse config file: %v", errFile)
|
||||
}
|
||||
|
||||
// TODO: add more backend options like for example c-lighting
|
||||
// TODO: add more backend options like for example c-lighting and eclair
|
||||
backend = cfg.LND
|
||||
backendName = "LND"
|
||||
}
|
||||
|
||||
func getDefaultLndDir() (dir string) {
|
||||
|
|
131
lightningtip.go
131
lightningtip.go
|
@ -1,6 +1,31 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type getInvoiceRequest struct {
|
||||
Value int64
|
||||
Message string
|
||||
}
|
||||
|
||||
type invoiceResponse struct {
|
||||
Invoice string
|
||||
Error string
|
||||
}
|
||||
|
||||
type tipValueResponse struct {
|
||||
TipValue int64
|
||||
}
|
||||
|
||||
type errorResponse struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
func main() {
|
||||
initLog()
|
||||
|
@ -10,12 +35,108 @@ func main() {
|
|||
err := backend.Connect()
|
||||
|
||||
if err == nil {
|
||||
log.Info("Successfully connected to " + backendName)
|
||||
http.HandleFunc("/", notFoundHandler)
|
||||
http.HandleFunc("/getinvoice", getInvoiceHandler)
|
||||
http.HandleFunc("/defaulttipvalue", defaultTipValueHandler)
|
||||
|
||||
invoice, err := backend.GetInvoice("Just a test", 1, 3600)
|
||||
log.Info("Subscribing to invoices")
|
||||
|
||||
go func() {
|
||||
err = cfg.LND.SubscribeInvoices()
|
||||
|
||||
if err != nil {
|
||||
log.Error("Failed to subscribe to invoices: " + fmt.Sprint(err))
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
log.Info("Starting HTTP server")
|
||||
|
||||
go func() {
|
||||
err = http.ListenAndServe(cfg.RESTHost, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Failed to start HTTP server: " + fmt.Sprint(err))
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
select {}
|
||||
|
||||
log.Info("Got invoice " + invoice)
|
||||
log.Info(fmt.Sprint(err))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getInvoiceHandler(writer http.ResponseWriter, request *http.Request) {
|
||||
var errorMessage string
|
||||
|
||||
tipValue := cfg.DefaultTipValue
|
||||
tipMessage := cfg.TipMessage
|
||||
|
||||
if request.Method == http.MethodPost {
|
||||
var body getInvoiceRequest
|
||||
|
||||
data, _ := ioutil.ReadAll(request.Body)
|
||||
|
||||
err := json.Unmarshal(data, &body)
|
||||
|
||||
if err == nil {
|
||||
if body.Value != 0 {
|
||||
tipValue = body.Value
|
||||
}
|
||||
|
||||
if body.Message != "" {
|
||||
tipMessage = body.Message
|
||||
}
|
||||
|
||||
} else {
|
||||
errorMessage = "Could not parse values from request"
|
||||
|
||||
log.Warning(errorMessage)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
invoice, err := backend.GetInvoice(tipMessage, tipValue, cfg.TipExpiry)
|
||||
|
||||
if err == nil {
|
||||
log.Info("Created invoice with value of " + strconv.FormatInt(tipValue, 10) + " satoshis")
|
||||
|
||||
writer.Write(marshalJson(invoiceResponse{
|
||||
Invoice: invoice,
|
||||
Error: errorMessage,
|
||||
}))
|
||||
|
||||
} else {
|
||||
errorMessage := "Failed to create invoice"
|
||||
|
||||
log.Error(errorMessage + ": " + fmt.Sprint(err))
|
||||
|
||||
writer.Write(marshalJson(errorResponse{
|
||||
Error: errorMessage,
|
||||
}))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func defaultTipValueHandler(writer http.ResponseWriter, request *http.Request) {
|
||||
writer.Write(marshalJson(tipValueResponse{
|
||||
TipValue: cfg.DefaultTipValue,
|
||||
}))
|
||||
}
|
||||
|
||||
func notFoundHandler(writer http.ResponseWriter, request *http.Request) {
|
||||
writer.Write(marshalJson(errorResponse{
|
||||
Error: "Not found",
|
||||
}))
|
||||
}
|
||||
|
||||
func marshalJson(data interface{}) []byte {
|
||||
response, _ := json.MarshalIndent(data, "", " ")
|
||||
|
||||
return response
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue