From 53f37ff619bcab76a95f43118bddf47385388b5c Mon Sep 17 00:00:00 2001
From: Chakib Benziane
Date: Sat, 6 Apr 2019 03:45:50 +0200
Subject: [PATCH] Better session handling, wip download invoice
- Improved API endpoints logic
- Use gorilla sessions for more granularity
---
api/download.go | 112 +++++++++++++++++++++++
api/handlers.go | 45 ++++------
api/routes.go | 36 ++++----
api/session.go | 12 +++
{storage => api}/upload_ctrl.go | 107 ++++++++++++----------
{storage => api}/upload_form.go | 2 +-
btc/price.go | 2 +-
go.mod | 3 +
go.sum | 4 +
ln/api.go | 155 +++-----------------------------
{storage => ln}/utils.go | 6 +-
main.go | 6 +-
storage/upload_model.go | 39 +++++++-
web/Caddyfile | 7 +-
web/Caddyfile-prod | 5 +-
web/src/Home.vue | 2 +-
web/src/api.js | 8 +-
17 files changed, 303 insertions(+), 248 deletions(-)
create mode 100644 api/download.go
create mode 100644 api/session.go
rename {storage => api}/upload_ctrl.go (79%)
rename {storage => api}/upload_form.go (97%)
rename {storage => ln}/utils.go (63%)
diff --git a/api/download.go b/api/download.go
new file mode 100644
index 0000000..b02f555
--- /dev/null
+++ b/api/download.go
@@ -0,0 +1,112 @@
+package api
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+
+ "git.sp4ke.com/sp4ke/bit4sat/ln"
+ "git.sp4ke.com/sp4ke/bit4sat/storage"
+ "git.sp4ke.com/sp4ke/bit4sat/utils"
+ "github.com/gin-contrib/sessions"
+ "github.com/gin-gonic/gin"
+)
+
+func DownloadHandler(c *gin.Context) {
+
+ dlId := c.Param("dlId")
+
+ // Get upload id for dl id
+ upId, err := storage.GetUploadIdForDlId(dlId)
+ if err != nil {
+ utils.JSONErr(c, http.StatusNotFound, "this file does not exist anymore")
+ return
+ }
+
+ // Get the upload session
+ session, err := SessionStore.Get(c.Request, DlSessionKey)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
+
+ dlSess, exists := session.Values["session-id"]
+ log.Printf("%#v", dlSess)
+
+ // Test if we are alread in a download session
+ if !exists {
+ // This is a new download session
+ log.Println("new download session")
+
+ // Create a unique session id for this download session
+ sessId, err := storage.GetShortId()
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
+
+ log.Printf("going to generate invoice for %s", upId)
+
+ session.AddFlash(sessId, "session-id")
+
+ session.Save(c.Request, c.Writer)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
+
+ //TODO: use fee asked by uploader
+ //
+ // Get upload fee asked by uploader
+ //
+ invoiceOpts := ln.InvoiceOpts{
+ Amount: 100,
+ Curr: ln.CurSat,
+ Memo: fmt.Sprintf("bit4sat download: %s", sessId),
+ }
+
+ invoice, err := ln.NewInvoice(invoiceOpts)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
+
+ // This is a returning download session to pay the invoice
+ //
+ c.JSON(http.StatusPaymentRequired, gin.H{
+ "invoice_rhash": invoice.RHash,
+ })
+
+ } else {
+ log.Printf("continue download session id: %s", dlSess)
+ session.Flashes("session-id")
+
+ err = session.Save(c.Request, c.Writer)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
+
+ c.Status(http.StatusOK)
+ }
+
+ return
+}
+
+func TestDownHandler(c *gin.Context) {
+ sess := sessions.Default(c)
+
+ test := sess.Get("test")
+ log.Printf("%#v", test)
+ if test != nil {
+ sess.Clear()
+ sess.Save()
+ c.String(http.StatusOK, "I remember you")
+ } else {
+ sess.Set("test", 1)
+ sess.Save()
+ c.String(http.StatusOK, "i dont remember you")
+ }
+
+ return
+}
diff --git a/api/handlers.go b/api/handlers.go
index f130ad4..bdb9373 100644
--- a/api/handlers.go
+++ b/api/handlers.go
@@ -9,22 +9,33 @@ import (
"git.sp4ke.com/sp4ke/bit4sat/ln"
"git.sp4ke.com/sp4ke/bit4sat/storage"
"git.sp4ke.com/sp4ke/bit4sat/utils"
- "github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/mediocregopher/radix/v3"
)
-func sessionHandler(c *gin.Context) {
- session := sessions.Default(c)
+func upSessionHandler(c *gin.Context) {
- lastUp := session.Get(storage.SessLastUploadName)
- session.Clear()
- session.Save()
+ upSession, err := SessionStore.Get(c.Request, UpSessionKey)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
+
+ lastUp, exists := upSession.Values["lastUp"]
- if lastUp != nil {
+ if exists {
+
+ err = upSession.Save(c.Request, c.Writer)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
// Get upload status
- key := fmt.Sprintf("upload_status_%s", lastUp.(string))
+
+ uId := lastUp.([]string)[0]
+
+ key := fmt.Sprintf("upload_status_%s", uId)
var upStatus storage.UpStatus
err := db.DB.Redis.Do(radix.FlatCmd(&upStatus, "GET", key))
@@ -102,21 +113,3 @@ func invoiceCbHandler(c *gin.Context) {
return
}
-
-func downHandler(c *gin.Context) {
- sess := sessions.Default(c)
-
- test := sess.Get("test")
- log.Printf("%#v", test)
- if test != nil {
- sess.Clear()
- sess.Save()
- c.String(http.StatusOK, "I remember you")
- } else {
- sess.Set("test", 1)
- sess.Save()
- c.String(http.StatusOK, "i dont remember you")
- }
-
- return
-}
diff --git a/api/routes.go b/api/routes.go
index e9e8088..4a6177d 100644
--- a/api/routes.go
+++ b/api/routes.go
@@ -2,15 +2,13 @@ package api
import (
"git.sp4ke.com/sp4ke/bit4sat/config"
- "git.sp4ke.com/sp4ke/bit4sat/storage"
+ "github.com/boj/redistore"
"github.com/gin-contrib/cors"
- "github.com/gin-contrib/sessions"
- "github.com/gin-contrib/sessions/redis"
"github.com/gin-gonic/gin"
)
var (
- UploadCtrl = storage.UploadCtrl{}
+ upCtrl = UploadCtrl{}
)
type API struct {
@@ -20,28 +18,35 @@ type API struct {
func (api *API) Run() {
// Get last session if it exists
- api.router.GET("/a/session", sessionHandler)
- uploadRoute := api.router.Group("/a/u")
+ v1 := api.router.Group("/api/v1")
+ v1.GET("/session", upSessionHandler)
+
+ uploadRoute := v1.Group("/u")
{
- uploadRoute.POST("", UploadCtrl.New)
- uploadRoute.PUT(":id", UploadCtrl.Upload)
+ uploadRoute.POST("", upCtrl.New)
+ uploadRoute.PUT("/:id", upCtrl.Upload)
//TODO: make a poll version + this one
- uploadRoute.GET("/check/:id", UploadCtrl.CheckStatus)
- uploadRoute.GET("/poll/:id", UploadCtrl.PollStatus)
+ uploadRoute.GET("/check/:id", upCtrl.CheckStatus)
+ uploadRoute.GET("/poll/:id", upCtrl.PollStatus)
}
// Download route
- downRoute := api.router.Group("/a/d")
+ downRoute := v1.Group("/d")
{
- downRoute.GET("t", downHandler)
+
+ // Download
+ downRoute.GET(":dlId", DownloadHandler)
}
+ // test rout
+ v1.GET("/t", TestDownHandler)
+
// Websocket server
//api.router.GET("/ws", ws.Serve)
// LN charge callback
- api.router.POST("/"+config.ChargeCallbackEndpoint, invoiceCbHandler)
+ //api.router.POST("/"+config.ChargeCallbackEndpoint, invoiceCbHandler)
api.router.Run(config.ApiListen)
}
@@ -51,14 +56,13 @@ func NewAPI() *API {
router.Use(cors.Default())
// Setup Session
- sessionStore, err := redis.NewStore(10, "tcp", "redis:6379",
+ var err error
+ SessionStore, err = redistore.NewRediStore(10, "tcp", "redis:6379",
"", []byte(config.SessionSecret))
if err != nil {
panic(err)
}
- router.Use(sessions.Sessions("bit4sat", sessionStore))
-
//
//
//router.Use(secure.New(secure.Config{
diff --git a/api/session.go b/api/session.go
new file mode 100644
index 0000000..1041e18
--- /dev/null
+++ b/api/session.go
@@ -0,0 +1,12 @@
+package api
+
+import "github.com/boj/redistore"
+
+const (
+ UpSessionKey = "bit4sat-up"
+ DlSessionKey = "bit4sat-dl"
+)
+
+var (
+ SessionStore *redistore.RediStore
+)
diff --git a/storage/upload_ctrl.go b/api/upload_ctrl.go
similarity index 79%
rename from storage/upload_ctrl.go
rename to api/upload_ctrl.go
index 43e12db..ff56204 100644
--- a/storage/upload_ctrl.go
+++ b/api/upload_ctrl.go
@@ -1,4 +1,4 @@
-package storage
+package api
import (
"crypto/sha256"
@@ -11,15 +11,11 @@ import (
"git.sp4ke.com/sp4ke/bit4sat/db"
"git.sp4ke.com/sp4ke/bit4sat/ln"
+ "git.sp4ke.com/sp4ke/bit4sat/storage"
"git.sp4ke.com/sp4ke/bit4sat/utils"
- "github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
)
-const (
- SessLastUploadName = "last-upload"
-)
-
type UploadCtrl struct{}
//TODO: tell client to avoid sending duplicate if we already have hash
@@ -34,7 +30,7 @@ func (ctrl UploadCtrl) New(c *gin.Context) {
}
// Create unique id
- uploadId, err := GetShortId()
+ uploadId, err := storage.GetShortId()
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -56,7 +52,7 @@ func (ctrl UploadCtrl) New(c *gin.Context) {
}
// Create new upload
- up := &Upload{}
+ up := &storage.Upload{}
up.UploadId = uploadId
up.AskFee = uploadForm.RequestPayment
up.AskCurrency = uploadForm.PaymentCurrency
@@ -64,7 +60,7 @@ func (ctrl UploadCtrl) New(c *gin.Context) {
// Generate unique download id
//
- dlId, err := GetShortId()
+ dlId, err := storage.GetShortId()
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -80,7 +76,7 @@ func (ctrl UploadCtrl) New(c *gin.Context) {
}
for _, file := range uploadForm.Files {
- fup := &FileUpload{}
+ fup := &storage.FileUpload{}
fup.UploadId = uploadId
fup.FileName, fup.FileExt = utils.CleanFileName(file.Name)
@@ -104,34 +100,47 @@ func (ctrl UploadCtrl) New(c *gin.Context) {
}
// Set upload status to new
- err = SetUploadStatus(uploadId, UpNew)
+ err = storage.SetUploadStatus(uploadId, storage.UpNew)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
}
// Upload seems valid, handle new upload procedure
- session := sessions.Default(c)
+ //
+ // Get the upload session
+ upSession, err := SessionStore.Get(c.Request, UpSessionKey)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
// Set the uploadId as last upload for session
- session.AddFlash(SessLastUploadName, uploadId)
- //session.AddFlash(SessLastUploadName, uploadId)
- session.Save()
+ upSession.AddFlash(uploadId)
+
+ err = upSession.Save(c.Request, c.Writer)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
// If not free upload generate a an invoice
// TODO: check if upload fee is free
if uploadForm.RequestPayment {
- invoice, err := ln.NewInvoiceForUpload(uploadForm.RequestPaymentAmount,
- ln.CurrencyID[uploadForm.PaymentCurrency],
- uploadId)
+ invoiceOpts := ln.InvoiceOpts{
+ Amount: uploadForm.RequestPaymentAmount,
+ Curr: ln.CurrencyID[uploadForm.PaymentCurrency],
+ Memo: fmt.Sprintf("bit4sat upload: %s", uploadId),
+ }
+ invoice, err := ln.NewInvoice(invoiceOpts)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
}
// Update Upload Invoice
- err = SetUploadInvoice(uploadId, invoice)
+ err = storage.SetUploadInvoice(uploadId, invoice)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -148,7 +157,7 @@ func (ctrl UploadCtrl) New(c *gin.Context) {
//}
c.JSON(http.StatusOK, gin.H{
- "status": UpNew,
+ "status": storage.UpNew,
"invoice": invoice,
"upload_id": uploadId,
})
@@ -172,7 +181,7 @@ func (ctrl UploadCtrl) New(c *gin.Context) {
func (ctrl UploadCtrl) CheckStatus(c *gin.Context) {
uploadId := c.Param("id")
- exists, err := IdExists(uploadId)
+ exists, err := storage.IdExists(uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -184,7 +193,7 @@ func (ctrl UploadCtrl) CheckStatus(c *gin.Context) {
}
// Get upload status
- uploadStatus, err := GetUploadStatus(uploadId)
+ uploadStatus, err := storage.GetUploadStatus(uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -198,7 +207,7 @@ func (ctrl UploadCtrl) CheckStatus(c *gin.Context) {
}
// Get invoice id for upload
- invoiceId, err := GetUploadIdInvoiceId(uploadId)
+ invoiceId, err := storage.GetUploadIdInvoiceId(uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -217,7 +226,7 @@ func (ctrl UploadCtrl) CheckStatus(c *gin.Context) {
return
}
- c.JSON(InvoiceHttpCode(invoice), gin.H{
+ c.JSON(ln.InvoiceHttpCode(invoice), gin.H{
"upload_id": uploadId,
"invoice": invoice,
"status": uploadStatus,
@@ -228,7 +237,7 @@ func (ctrl UploadCtrl) CheckStatus(c *gin.Context) {
func (ctrl UploadCtrl) PollStatus(c *gin.Context) {
uploadId := c.Param("id")
- exists, err := IdExists(uploadId)
+ exists, err := storage.IdExists(uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -239,13 +248,13 @@ func (ctrl UploadCtrl) PollStatus(c *gin.Context) {
return
}
- uploadStatus, err := GetUploadStatus(uploadId)
+ uploadStatus, err := storage.GetUploadStatus(uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
}
- if uploadStatus&UpNew != 0 {
+ if uploadStatus&storage.UpNew != 0 {
c.JSON(http.StatusCreated, gin.H{
"status": uploadStatus,
})
@@ -253,7 +262,7 @@ func (ctrl UploadCtrl) PollStatus(c *gin.Context) {
}
// we are not in UpNew state so we should have an invoice
- invoice, err := GetUploadInvoice(uploadId)
+ invoice, err := storage.GetUploadInvoice(uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -282,7 +291,7 @@ func (ctrl UploadCtrl) PollStatus(c *gin.Context) {
// if expired return with expired response
if invoice.Expired {
- err := SetUploadStatus(uploadId, UpPayExpired)
+ err := storage.SetUploadStatus(uploadId, storage.UpPayExpired)
if err != nil {
log.Printf("Redis error: %s", err)
}
@@ -301,43 +310,51 @@ func (ctrl UploadCtrl) PollStatus(c *gin.Context) {
//
log.Println("POLL: invoice was paid")
- uploadStatus |= UpPaid
- err := SetUploadStatus(uploadId, uploadStatus)
+ uploadStatus |= storage.UpPaid
+ err := storage.SetUploadStatus(uploadId, uploadStatus)
if err != nil {
log.Printf("Redis error: %s", err)
}
// Update Upload Invoice
- err = SetUploadInvoice(uploadId, invoice)
+ err = storage.SetUploadInvoice(uploadId, invoice)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
}
// Generate admin token and save it
- adminToken, err := GetLongId()
+ adminToken, err := storage.GetLongId()
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
}
- err = SetUploadAdminToken(uploadId, adminToken)
+ err = storage.SetUploadAdminToken(uploadId, adminToken)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
}
// Get the download id
- dlId, err := GetDownloadId(uploadId)
+ dlId, err := storage.GetDownloadId(uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
}
// Clear the session
- session := sessions.Default(c)
- session.Clear()
- session.Save()
+ upSession, err := SessionStore.Get(c.Request, UpSessionKey)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
+ upSession.Flashes()
+ err = upSession.Save(c.Request, c.Writer)
+ if err != nil {
+ utils.JSONErrPriv(c, http.StatusInternalServerError, err)
+ return
+ }
// invoice was paid
c.JSON(http.StatusAccepted, gin.H{
@@ -368,7 +385,7 @@ func (ctrl UploadCtrl) Upload(c *gin.Context) {
// Check that upload ID exists
uploadId := c.Param("id")
- exists, err := IdExists(uploadId)
+ exists, err := storage.IdExists(uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -438,7 +455,7 @@ func (ctrl UploadCtrl) Upload(c *gin.Context) {
sum256 := hex.EncodeToString(hasher.Sum(nil))
// Get the file's metadata from upload table
- up, err := GetByHashID(sum256, uploadId)
+ up, err := storage.GetByHashID(sum256, uploadId)
if err != nil {
utils.JSONErrPriv(c, http.StatusNotFound, err)
db.RollbackTx(tx, nil)
@@ -456,7 +473,7 @@ func (ctrl UploadCtrl) Upload(c *gin.Context) {
//
//
log.Println("Storing file")
- err = StoreFormFile(formFd, up.SHA256+up.FileExt)
+ err = storage.StoreFormFile(formFd, up.SHA256+up.FileExt)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
db.RollbackTx(tx, nil)
@@ -464,7 +481,7 @@ func (ctrl UploadCtrl) Upload(c *gin.Context) {
}
log.Printf("%s stored at %s", up.FileName,
- GetStoreDestination(up.SHA256+up.FileExt))
+ storage.GetStoreDestination(up.SHA256+up.FileExt))
// Setting status to stored
log.Println("Updating file upload stored status")
@@ -475,7 +492,7 @@ func (ctrl UploadCtrl) Upload(c *gin.Context) {
// Rollback and remove the file
db.RollbackTx(tx, func() {
- err := os.Remove(GetStoreDestination(up.SHA256 + up.FileExt))
+ err := os.Remove(storage.GetStoreDestination(up.SHA256 + up.FileExt))
if err != nil {
log.Println(err)
}
@@ -491,7 +508,7 @@ func (ctrl UploadCtrl) Upload(c *gin.Context) {
}
// Set the whole transaction as stored
- err = SetUploadStatus(uploadId, UpStored)
+ err = storage.SetUploadStatus(uploadId, storage.UpStored)
if err != nil {
utils.JSONErrPriv(c, http.StatusInternalServerError, err)
return
@@ -499,7 +516,7 @@ func (ctrl UploadCtrl) Upload(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": http.StatusOK,
- "store_status": UpStored,
+ "store_status": storage.UpStored,
"upload_id": uploadId,
})
diff --git a/storage/upload_form.go b/api/upload_form.go
similarity index 97%
rename from storage/upload_form.go
rename to api/upload_form.go
index e626ff2..f1c0f01 100644
--- a/storage/upload_form.go
+++ b/api/upload_form.go
@@ -1,4 +1,4 @@
-package storage
+package api
import "time"
diff --git a/btc/price.go b/btc/price.go
index bd2cb97..331ea11 100644
--- a/btc/price.go
+++ b/btc/price.go
@@ -21,7 +21,7 @@ var FixedRates = map[string]float64{
"BTC": 1,
}
-func ToMsat(currency string, amount float64) (int64, error) {
+func FiatToMsat(currency string, amount float64) (int64, error) {
rate, err := getRate(currency)
if err != nil {
return -1, err
diff --git a/go.mod b/go.mod
index fea71e5..78cd6e9 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,8 @@ module git.sp4ke.com/sp4ke/bit4sat
go 1.12
require (
+ github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff
+ github.com/garyburd/redigo v1.6.0 // indirect
github.com/gin-contrib/cors v0.0.0-20190301062745-f9e10995c85a
github.com/gin-contrib/sessions v0.0.0-20190226023029-1532893d996f
github.com/gin-gonic/gin v1.3.0
@@ -26,5 +28,6 @@ require (
google.golang.org/appengine v1.5.0 // indirect
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 // indirect
google.golang.org/grpc v1.19.1
+ gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b // indirect
gopkg.in/macaroon.v2 v2.1.0
)
diff --git a/go.sum b/go.sum
index dec2c12..3614f72 100644
--- a/go.sum
+++ b/go.sum
@@ -52,6 +52,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/frankban/quicktest v1.0.0 h1:QgmxFbprE29UG4oL88tGiiL/7VuiBl5xCcz+wJcJhc0=
github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
+github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/gin-contrib/cors v0.0.0-20190301062745-f9e10995c85a h1:zBycVvXa03SIX+jdMv8wGu9TMDMWdN8EhaR1FoeKHNo=
github.com/gin-contrib/cors v0.0.0-20190301062745-f9e10995c85a/go.mod h1:pL2kNE+DgDU+eQ+dary5bX0Z6LPP8nR6Mqs1iejILw4=
github.com/gin-contrib/sessions v0.0.0-20190226023029-1532893d996f h1:f8TGHcU6cxOhMwW6YQhpRe+zlr05qNjVmdcK1qigr5I=
@@ -241,6 +243,8 @@ google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.19.1 h1:TrBcJ1yqAl1G++wO39nD/qtgpsW9/1+QGrluyMGEYgM=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b h1:U/Uqd1232+wrnHOvWNaxrNqn/kFnr4yu4blgPtQt0N8=
+gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b/go.mod h1:fgfIZMlsafAHpspcks2Bul+MWUNw/2dyQmjC2faKjtg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/ln/api.go b/ln/api.go
index e73d846..7fefb71 100644
--- a/ln/api.go
+++ b/ln/api.go
@@ -1,22 +1,17 @@
package ln
import (
- "bytes"
"encoding/json"
"fmt"
"log"
"net/http"
- "net/url"
- "strconv"
"strings"
"git.sp4ke.com/sp4ke/bit4sat/btc"
"git.sp4ke.com/sp4ke/bit4sat/bus"
- "git.sp4ke.com/sp4ke/bit4sat/config"
"git.sp4ke.com/sp4ke/bit4sat/db"
"git.sp4ke.com/sp4ke/bit4sat/lndrpc"
"git.sp4ke.com/sp4ke/bit4sat/utils"
- "github.com/gin-gonic/gin"
"github.com/mediocregopher/radix/v3"
)
@@ -24,20 +19,6 @@ var (
Client *http.Client
)
-func Info() (gin.H, error) {
-
- result := make(gin.H)
- resp, err := Client.Get(getUrl(InfoEndpoint))
- if err != nil {
- return nil, err
- }
-
- jsonDec := json.NewDecoder(resp.Body)
- jsonDec.Decode(&result)
-
- return result, nil
-}
-
// Quick check if invoice was paid
func CheckInvoice(id string) (*Invoice, error) {
@@ -97,160 +78,50 @@ func PollPaidInvoice(invoiceId string, invoicePaidChan chan<- *Invoice, errorCha
}
}
-func PollPaidInvoiceTMP(invoiceId string, invoiceChan chan<- *Invoice, errorChan chan<- error) {
-
- invoice := Invoice{}
-
- reqParams := url.Values{}
- // Timeout in seconds
- reqParams.Set("timeout", strconv.Itoa(60))
- reqURI := fmt.Sprintf("%s/%s/wait?%s",
- getUrl(InvoiceEndpoint),
- invoiceId,
- reqParams.Encode())
-
- log.Printf("polling to %s", reqURI)
-
- var err error
- var jsonDec *json.Decoder
- resp := &http.Response{}
-
- for {
- //log.Println("new poll")
- resp, err = http.Get(reqURI)
- if err != nil {
- log.Printf("Error: ", err)
- }
- jsonDec = json.NewDecoder(resp.Body)
-
- if resp.StatusCode == http.StatusPaymentRequired {
- log.Printf("invoice %s not yet paid", invoiceId)
- continue
- }
-
- if resp.StatusCode == http.StatusGone {
- log.Printf("invoice expired %s", invoiceId)
- invoice.Expired = true
- break
- }
-
- if resp.StatusCode == http.StatusOK {
- log.Printf("Invoice paid %s", invoice)
- break
- } else {
- log.Println("else !")
-
- // This section handles unknown answer from ln-charge
- log.Printf("InvoicePoll Error: unknown resopnse %s", resp.Status)
- jsonDec.Decode(&invoice)
-
- close(invoiceChan)
- errorChan <- fmt.Errorf("%s: %s", resp.Status, invoice)
-
- return
- }
-
- }
-
- jsonDec.Decode(&invoice)
-
- invoiceChan <- &invoice
- log.Printf("quit polling %s", invoiceId)
+type InvoiceOpts struct {
+ Amount float64
+ Curr Currency
+ Memo string
}
-func NewInvoiceForUpload(amount float64, curr Currency, uploadId string) (*Invoice, error) {
+func NewInvoice(opts InvoiceOpts) (*Invoice, error) {
var err error
var satValue int64
- description := fmt.Sprintf("bit4sat upload: %s", uploadId)
-
- if curr == CurMSat {
+ if opts.Curr == CurMSat {
log.Println("cur is msat")
// Convert to MSAT, meaning values under 1000 MSAT are ignored
- satValue = int64(amount / 1000)
+ satValue = int64(opts.Amount / 1000)
// Other supported currecies
}
- if curr != CurSat {
+ if opts.Curr != CurSat {
log.Println("cur is custom")
// Get Sat satValue for this invoice
- msatVal, err := btc.ToMsat(CurrencyString[curr], amount)
+ msatVal, err := btc.FiatToMsat(CurrencyString[opts.Curr], opts.Amount)
if err != nil {
return nil, err
}
satValue = msatVal / 1000
} else {
- satValue = int64(amount)
+ satValue = int64(opts.Amount)
}
- lndInvoice, err := lndrpc.AddInvoiceSat(description, satValue)
+ lndInvoice, err := lndrpc.AddInvoiceSat(opts.Memo, satValue)
if err != nil {
return nil, err
}
invoice := InvoiceFromLndIn(lndInvoice)
- invoice.QuotedCurrency = CurrencyString[curr]
- invoice.QuotedAmount = amount
+ invoice.QuotedCurrency = CurrencyString[opts.Curr]
+ invoice.QuotedAmount = opts.Amount
return invoice, nil
}
-func NewInvoiceForUploadTMP(amount float32, curr Currency, uploadId string) (*Invoice, error) {
-
- webhookUrl := fmt.Sprintf("http://%s:%s/%s", config.ApiHost, config.ApiPort,
- config.ChargeCallbackEndpoint)
-
- reqData := gin.H{
- "description": fmt.Sprintf("bit4sat upload: %s", uploadId),
- "webhook": webhookUrl,
- }
-
- // If Satoshi convert to millisat
- if curr == CurSat {
- reqData["msatoshi"] = amount * 1000
- } else {
- reqData["currency"] = CurrencyString[curr]
- reqData["amount"] = amount
- }
-
- jsonEnc, err := json.Marshal(reqData)
- if err != nil {
- return nil, err
- }
-
- log.Printf("Asking for invoice with: %s", jsonEnc)
-
- resp, err := Client.Post(getUrl(InvoiceEndpoint),
- "application/json",
- bytes.NewReader(jsonEnc))
-
- if err != nil {
- return nil, err
- }
-
- invoice := Invoice{}
- jsonDec := json.NewDecoder(resp.Body)
- jsonDec.Decode(&invoice)
-
- return &invoice, nil
-}
-
-func getUrl(endpoint string) string {
- url, err := url.Parse(fmt.Sprintf("http://api-token:%s@%s/%s",
- config.LnChargeToken,
- config.LnChargeApi,
- endpoint))
- if err != nil {
- log.Fatal(err)
- }
-
- return url.String()
-
-}
-
func init() {
Client = utils.NewHttpClient()
}
diff --git a/storage/utils.go b/ln/utils.go
similarity index 63%
rename from storage/utils.go
rename to ln/utils.go
index 0debc71..83fd624 100644
--- a/storage/utils.go
+++ b/ln/utils.go
@@ -1,12 +1,10 @@
-package storage
+package ln
import (
"net/http"
-
- "git.sp4ke.com/sp4ke/bit4sat/ln"
)
-func InvoiceHttpCode(invoice *ln.Invoice) int {
+func InvoiceHttpCode(invoice *Invoice) int {
if invoice.Expired {
return http.StatusGone
}
diff --git a/main.go b/main.go
index bcaa26e..eb32b00 100644
--- a/main.go
+++ b/main.go
@@ -12,6 +12,8 @@ func main() {
defer db.DB.Sql.Close()
- api := api.NewAPI()
- api.Run()
+ v1 := api.NewAPI()
+ defer api.SessionStore.Close()
+
+ v1.Run()
}
diff --git a/storage/upload_model.go b/storage/upload_model.go
index a0418ad..d96d33e 100644
--- a/storage/upload_model.go
+++ b/storage/upload_model.go
@@ -255,7 +255,7 @@ func GetDownloadId(uploadId string) (string, error) {
//if !exists get from sql and store in redis
if !exists {
- log.Printf("download id not found for %s, trying form db", uploadId)
+ log.Printf("redis: dlId %s not found for, trying form db", uploadId)
query := `SELECT download_id from uploads WHERE upload_id = $1`
err = DB.Sql.Get(&downloadId, query, uploadId)
if err != nil {
@@ -268,12 +268,49 @@ func GetDownloadId(uploadId string) (string, error) {
// Store it back on redis cache
err = DB.Redis.Do(radix.FlatCmd(nil, "SET", key, downloadId))
+ } else {
+ err = DB.Redis.Do(radix.FlatCmd(&downloadId, "GET", key))
}
return downloadId, err
}
+func GetUploadIdForDlId(dlId string) (string, error) {
+ key := fmt.Sprintf("upload_for_download_%s", dlId)
+
+ // Try redis
+ var upId string
+ var exists bool
+
+ // check exists on redis
+ err := DB.Redis.Do(radix.FlatCmd(&exists, "EXISTS", key))
+ if err != nil {
+ return "", err
+ }
+
+ // if not get from sql and store on redis
+ if !exists {
+ log.Printf("redis: upId %s not found , trying form db", dlId)
+ query := `SELECT upload_id from uploads WHERE download_id = $1`
+ err = DB.Sql.Get(&upId, query, dlId)
+ if err != nil {
+ return "", err
+ }
+
+ if len(upId) == 0 {
+ return "", fmt.Errorf("upload id missing in %s", dlId)
+ }
+
+ // Store it back on redis cache
+ err = DB.Redis.Do(radix.FlatCmd(nil, "SET", key, upId))
+ } else {
+ err = DB.Redis.Do(radix.FlatCmd(&upId, "GET", key))
+ }
+
+ return upId, err
+}
+
func GetUploadInvoice(uploadId string) (*ln.Invoice, error) {
var invoice ln.Invoice
diff --git a/web/Caddyfile b/web/Caddyfile
index 643a8d6..5526047 100644
--- a/web/Caddyfile
+++ b/web/Caddyfile
@@ -11,7 +11,12 @@ header / {
## API
-proxy /a localhost:8880 {
+proxy /api localhost:8880 {
+ transparent
+}
+
+## test
+proxy /t localhost:8880 {
transparent
}
diff --git a/web/Caddyfile-prod b/web/Caddyfile-prod
index 831ab8c..a43b6e0 100644
--- a/web/Caddyfile-prod
+++ b/web/Caddyfile-prod
@@ -10,11 +10,8 @@ header / {
}
-proxy /d bit4sat-api:8880
+proxy /api bit4sat-api:8880
-proxy /a bit4sat-api:8880 {
- transparent
-}
#log /api stdout
log / stdout
diff --git a/web/src/Home.vue b/web/src/Home.vue
index f2a0827..eaa78fb 100644
--- a/web/src/Home.vue
+++ b/web/src/Home.vue
@@ -7,7 +7,7 @@
If choose to setup a fee for your link, every download will
require a payment.
- You can redeem your payments at any time.
+ You can redeem your payments at any time using your admin token.
diff --git a/web/src/api.js b/web/src/api.js
index b6e07a6..94ade41 100644
--- a/web/src/api.js
+++ b/web/src/api.js
@@ -5,10 +5,10 @@ import 'babel-polyfill';
const endPoints = {
- upload: '/a/u',
- session: '/a/session',
- pollstatus: '/a/u/poll',
- checkstatus: '/a/u/check'
+ upload: '/api/v1/u',
+ session: '/api/v1/session',
+ pollstatus: '/api/v1/u/poll',
+ checkstatus: '/api/v1/u/check'
}