added EventSource to show a thank you message
This commit is contained in:
parent
58f432d04f
commit
a4ad464710
|
@ -1,5 +1,10 @@
|
||||||
package backends
|
package backends
|
||||||
|
|
||||||
|
import "github.com/donovanhide/eventsource"
|
||||||
|
|
||||||
|
// For callbacks when an invoice gets settled
|
||||||
|
type PublishInvoiceSettled func(invoice string, eventSrv *eventsource.Server)
|
||||||
|
|
||||||
type Backend interface {
|
type Backend interface {
|
||||||
Connect() error
|
Connect() error
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"github.com/donovanhide/eventsource"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
|
@ -90,7 +90,7 @@ func (lnd *LND) GetInvoice(message string, amount int64, expiry int64) (invoice
|
||||||
return response.PaymentRequest, err
|
return response.PaymentRequest, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lnd *LND) SubscribeInvoices() error {
|
func (lnd *LND) SubscribeInvoices(callback PublishInvoiceSettled, eventSrv *eventsource.Server) error {
|
||||||
stream, err := lnd.client.SubscribeInvoices(lnd.ctx, &lnrpc.InvoiceSubscription{})
|
stream, err := lnd.client.SubscribeInvoices(lnd.ctx, &lnrpc.InvoiceSubscription{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -101,7 +101,7 @@ func (lnd *LND) SubscribeInvoices() error {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
in, streamErr := stream.Recv()
|
invoice, streamErr := stream.Recv()
|
||||||
|
|
||||||
if streamErr == io.EOF {
|
if streamErr == io.EOF {
|
||||||
err = errors.New("lost connection to LND gRPC")
|
err = errors.New("lost connection to LND gRPC")
|
||||||
|
@ -119,8 +119,12 @@ func (lnd *LND) SubscribeInvoices() error {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(in)
|
if invoice.Settled {
|
||||||
|
callback(invoice.PaymentRequest, eventSrv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-wait
|
<-wait
|
||||||
|
|
|
@ -115,6 +115,12 @@
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#lightningTipThankYou {
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
<script async defer src="lightningTip.js"></script>
|
<script async defer src="lightningTip.js"></script>
|
||||||
<script async defer src="https://cdn.rawgit.com/kazuhikoarase/qrcode-generator/886a247e/js/qrcode.js"></script>
|
<script async defer src="https://cdn.rawgit.com/kazuhikoarase/qrcode-generator/886a247e/js/qrcode.js"></script>
|
||||||
|
<script async defer src="https://cdn.rawgit.com/emn178/js-sha256/189bb9b0/build/sha256.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<div id="lightningTip">
|
<div id="lightningTip">
|
||||||
|
|
|
@ -11,7 +11,10 @@ var qrCode;
|
||||||
|
|
||||||
var defaultGetInvoice;
|
var defaultGetInvoice;
|
||||||
|
|
||||||
// TODO: listen to eventsource and show tank you when invoice settled
|
// TODO: show error when invoice expires
|
||||||
|
// TODO: maybe don't show full invoice
|
||||||
|
// TODO: proper url handling window.location.protocol + window.location.hostname + ":8081/getinvoice"
|
||||||
|
// TODO: show price in dollar?
|
||||||
function getInvoice() {
|
function getInvoice() {
|
||||||
if (running === false) {
|
if (running === false) {
|
||||||
running = true;
|
running = true;
|
||||||
|
@ -34,6 +37,16 @@ function getInvoice() {
|
||||||
console.log("Got invoice: " + json.Invoice);
|
console.log("Got invoice: " + json.Invoice);
|
||||||
console.log("Invoice expires in: " + json.Expiry);
|
console.log("Invoice expires in: " + json.Expiry);
|
||||||
|
|
||||||
|
var hash = sha256(json.Invoice);
|
||||||
|
|
||||||
|
console.log("Got hash of invoice: " + hash);
|
||||||
|
|
||||||
|
// TODO: find alternative for Edge and IE
|
||||||
|
console.log("Starting listening for invoice to get settled");
|
||||||
|
|
||||||
|
listenInvoiceSettled(hash);
|
||||||
|
|
||||||
|
// Update UI
|
||||||
invoice = json.Invoice;
|
invoice = json.Invoice;
|
||||||
|
|
||||||
var wrapper = document.getElementById("lightningTip");
|
var wrapper = document.getElementById("lightningTip");
|
||||||
|
@ -65,6 +78,8 @@ function getInvoice() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
|
console.error(exception);
|
||||||
|
|
||||||
showErrorMessage("Failed to reach backend");
|
showErrorMessage("Failed to reach backend");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +87,6 @@ function getInvoice() {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: proper url handling window.location.protocol + window.location.hostname + ":8081/getinvoice"
|
|
||||||
request.open("POST", "http://localhost:8081/getinvoice", true);
|
request.open("POST", "http://localhost:8081/getinvoice", true);
|
||||||
request.send(data);
|
request.send(data);
|
||||||
|
|
||||||
|
@ -99,6 +113,19 @@ function getInvoice() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listenInvoiceSettled(hash) {
|
||||||
|
var eventSrc = new EventSource("http://localhost:8081/eventsource");
|
||||||
|
|
||||||
|
eventSrc.onmessage = function (event) {
|
||||||
|
if (event.data === hash) {
|
||||||
|
var wrapper = document.getElementById("lightningTip");
|
||||||
|
|
||||||
|
wrapper.innerHTML = "<p id=\"lightningTipLogo\">⚡</p>";
|
||||||
|
wrapper.innerHTML += "<a id='lightningTipThankYou'>Thank you for your tip!</a>";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function starTimer(duration, element) {
|
function starTimer(duration, element) {
|
||||||
showTimer(duration, element);
|
showTimer(duration, element);
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,35 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/donovanhide/eventsource"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const eventChannel = "invoiceSettled"
|
||||||
|
|
||||||
|
var eventSrv *eventsource.Server
|
||||||
|
|
||||||
|
var pendingInvoices []PendingInvoice
|
||||||
|
|
||||||
|
type PendingInvoice struct {
|
||||||
|
Invoice string
|
||||||
|
Hash string
|
||||||
|
Expiry time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// To use the pendingInvoice type as event for the EventSource stream
|
||||||
|
func (pending PendingInvoice) Id() string { return "" }
|
||||||
|
func (pending PendingInvoice) Event() string { return "" }
|
||||||
|
func (pending PendingInvoice) Data() string { return pending.Hash }
|
||||||
|
|
||||||
type invoiceResponse struct {
|
type invoiceResponse struct {
|
||||||
Invoice string
|
Invoice string
|
||||||
Expiry int64
|
Expiry int64
|
||||||
|
@ -32,14 +53,18 @@ func main() {
|
||||||
err := backend.Connect()
|
err := backend.Connect()
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
log.Info("Starting EventSource stream")
|
||||||
|
|
||||||
|
eventSrv = eventsource.NewServer()
|
||||||
|
|
||||||
http.HandleFunc("/", notFoundHandler)
|
http.HandleFunc("/", notFoundHandler)
|
||||||
http.HandleFunc("/getinvoice", getInvoiceHandler)
|
http.HandleFunc("/getinvoice", getInvoiceHandler)
|
||||||
|
http.HandleFunc("/eventsource", eventSrv.Handler(eventChannel))
|
||||||
|
|
||||||
log.Info("Subscribing to invoices")
|
log.Info("Subscribing to invoices")
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// TODO: let clients listen if their invoice was paid (eventsource)
|
err = cfg.LND.SubscribeInvoices(publishInvoiceSettled, eventSrv)
|
||||||
err = cfg.LND.SubscribeInvoices()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to subscribe to invoices: " + fmt.Sprint(err))
|
log.Error("Failed to subscribe to invoices: " + fmt.Sprint(err))
|
||||||
|
@ -68,6 +93,23 @@ func main() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callbacks when an invoice gets settled
|
||||||
|
func publishInvoiceSettled(invoice string, eventSrv *eventsource.Server) {
|
||||||
|
for index, pending := range pendingInvoices {
|
||||||
|
if pending.Invoice == invoice {
|
||||||
|
log.Info("Invoice settled: " + invoice)
|
||||||
|
|
||||||
|
eventSrv.Publish([]string{eventChannel}, pending)
|
||||||
|
|
||||||
|
pendingInvoices = append(pendingInvoices[:index], pendingInvoices[index+1:]...)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func getInvoiceHandler(writer http.ResponseWriter, request *http.Request) {
|
func getInvoiceHandler(writer http.ResponseWriter, request *http.Request) {
|
||||||
errorMessage := "Could not parse values from request"
|
errorMessage := "Could not parse values from request"
|
||||||
|
|
||||||
|
@ -89,8 +131,22 @@ func getInvoiceHandler(writer http.ResponseWriter, request *http.Request) {
|
||||||
logMessage += " with message \"" + body.Message + "\""
|
logMessage += " with message \"" + body.Message + "\""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sha := sha256.New()
|
||||||
|
sha.Write([]byte(invoice))
|
||||||
|
|
||||||
|
hash := hex.EncodeToString(sha.Sum(nil))
|
||||||
|
|
||||||
|
expiryDuration := time.Duration(cfg.TipExpiry) * time.Second
|
||||||
|
|
||||||
log.Info(logMessage)
|
log.Info(logMessage)
|
||||||
|
|
||||||
|
// TODO: check every minute or so if expired
|
||||||
|
pendingInvoices = append(pendingInvoices, PendingInvoice{
|
||||||
|
Invoice: invoice,
|
||||||
|
Hash: hash,
|
||||||
|
Expiry: time.Now().Add(expiryDuration),
|
||||||
|
})
|
||||||
|
|
||||||
writer.Write(marshalJson(invoiceResponse{
|
writer.Write(marshalJson(invoiceResponse{
|
||||||
Invoice: invoice,
|
Invoice: invoice,
|
||||||
Expiry: cfg.TipExpiry,
|
Expiry: cfg.TipExpiry,
|
||||||
|
|
Loading…
Reference in New Issue