2019-03-15 18:00:35 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
2019-03-21 17:44:40 +00:00
|
|
|
"database/sql"
|
2019-04-02 13:53:52 +00:00
|
|
|
"encoding/binary"
|
2019-03-29 18:50:11 +00:00
|
|
|
"encoding/json"
|
2019-03-15 18:00:35 +00:00
|
|
|
"errors"
|
2019-03-26 16:03:13 +00:00
|
|
|
"fmt"
|
2019-03-15 18:00:35 +00:00
|
|
|
"log"
|
2019-04-02 13:53:52 +00:00
|
|
|
"math/bits"
|
2019-04-07 10:30:43 +00:00
|
|
|
"time"
|
2019-03-15 18:00:35 +00:00
|
|
|
|
2019-03-23 18:29:48 +00:00
|
|
|
"git.sp4ke.com/sp4ke/bit4sat/db"
|
2019-03-29 18:50:11 +00:00
|
|
|
"git.sp4ke.com/sp4ke/bit4sat/ln"
|
2019-03-21 17:44:40 +00:00
|
|
|
"github.com/jmoiron/sqlx"
|
2019-03-29 18:50:11 +00:00
|
|
|
"github.com/lib/pq"
|
2019-03-26 16:03:13 +00:00
|
|
|
"github.com/mediocregopher/radix/v3"
|
2019-03-15 18:00:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var DB = db.DB
|
|
|
|
|
|
|
|
const (
|
2019-03-29 18:50:11 +00:00
|
|
|
//TODO: sync upload status from redis
|
2019-03-30 18:42:41 +00:00
|
|
|
// TODO: status is currently handled in cache not here
|
2019-04-05 16:18:44 +00:00
|
|
|
//
|
|
|
|
// stored: if file was stored
|
|
|
|
DBFileUploadsSchema = `
|
|
|
|
CREATE TABLE IF NOT EXISTS file_uploads (
|
|
|
|
file_upload_id serial PRIMARY KEY,
|
|
|
|
upload_id text NOT NULL references uploads(upload_id),
|
2019-03-27 15:35:36 +00:00
|
|
|
sha256 varchar(64) NOT NULL,
|
|
|
|
file_name varchar(255) NOT NULL,
|
|
|
|
file_type varchar(255) DEFAULT '',
|
|
|
|
file_size integer NOT NULL,
|
|
|
|
file_ext varchar(255) DEFAULT '',
|
2019-04-05 16:18:44 +00:00
|
|
|
stored boolean DEFAULT 'false',
|
2019-03-21 17:44:40 +00:00
|
|
|
UNIQUE (upload_id, sha256)
|
2019-03-15 18:00:35 +00:00
|
|
|
);
|
|
|
|
`
|
|
|
|
|
2019-04-05 16:18:44 +00:00
|
|
|
// Unique entry per upload
|
|
|
|
//
|
|
|
|
// store: all files for upload where stored
|
|
|
|
DBUploadsSchema = `
|
|
|
|
CREATE TABLE IF NOT EXISTS uploads (
|
|
|
|
upload_id text PRIMARY KEY,
|
|
|
|
download_id text DEFAULT '',
|
2019-04-07 10:30:43 +00:00
|
|
|
created timestamp DEFAULT now(),
|
2019-04-05 16:18:44 +00:00
|
|
|
ask_fee boolean NOT NULL DEFAULT 'false',
|
|
|
|
ask_currency varchar(3) DEFAULT '',
|
|
|
|
ask_amount real DEFAULT 0,
|
|
|
|
status integer NOT NULL DEFAULT 0,
|
|
|
|
settled boolean DEFAULT 'false',
|
|
|
|
admin_token text DEFAULT '',
|
|
|
|
invoice_rhash varchar(64) references invoices(rhash)
|
|
|
|
);
|
|
|
|
`
|
|
|
|
|
2019-04-07 20:39:54 +00:00
|
|
|
DBUploadPaymentsSchema = `
|
2019-04-07 20:31:35 +00:00
|
|
|
CREATE TABLE IF NOT EXISTS upload_payments (
|
|
|
|
payment_id_rhash varchar(64) PRIMARY KEY,
|
|
|
|
upload_id text NOT NULL references uploads(upload_id),
|
|
|
|
msat_amount real NOT NULL,
|
|
|
|
created timestamp DEFAULT now()
|
|
|
|
);
|
|
|
|
`
|
|
|
|
|
|
|
|
//TODO: store all invoices from redis to local sqldb
|
2019-04-05 16:18:44 +00:00
|
|
|
DBInvoicesSchema = `
|
|
|
|
CREATE TABLE IF NOT EXISTS invoices (
|
2019-04-07 20:31:35 +00:00
|
|
|
rhash varchar(64) PRIMARY KEY
|
2019-04-05 16:18:44 +00:00
|
|
|
);
|
|
|
|
`
|
2019-03-21 17:44:40 +00:00
|
|
|
|
2019-04-05 16:18:44 +00:00
|
|
|
QSetFileStored = `UPDATE file_uploads
|
|
|
|
SET stored = :stored
|
|
|
|
WHERE upload_id = :upload_id AND sha256 = :sha256`
|
2019-03-21 17:44:40 +00:00
|
|
|
|
2019-03-26 16:03:13 +00:00
|
|
|
QGetByHashID = `SELECT upload_id,
|
|
|
|
sha256,
|
|
|
|
file_name,
|
|
|
|
file_type,
|
|
|
|
file_size,
|
|
|
|
file_ext,
|
2019-04-02 13:53:52 +00:00
|
|
|
stored
|
2019-04-05 16:18:44 +00:00
|
|
|
FROM file_uploads WHERE sha256 = $1 AND upload_id = $2`
|
2019-03-15 18:00:35 +00:00
|
|
|
)
|
|
|
|
|
2019-04-02 13:53:52 +00:00
|
|
|
type UpStatus uint32
|
|
|
|
|
|
|
|
func (st UpStatus) MarshalJSON() ([]byte, error) {
|
|
|
|
res := map[string]string{}
|
|
|
|
res["pay_status"] = st.PrintPayStatus()
|
|
|
|
res["store_status"] = st.PrintStoreStatus()
|
|
|
|
|
|
|
|
return json.Marshal(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st *UpStatus) UnmarshalBinary(b []byte) error {
|
2019-04-02 17:40:25 +00:00
|
|
|
//fmt.Printf("%#v\n", b)
|
2019-04-02 13:53:52 +00:00
|
|
|
|
|
|
|
// first 4 bits are reseved
|
|
|
|
// Single byte will be for 0 value
|
|
|
|
if len(b) == 1 {
|
|
|
|
*st = 0
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
view := binary.BigEndian.Uint32(b)
|
|
|
|
view = bits.Reverse32(view)
|
2019-04-02 17:40:25 +00:00
|
|
|
//fmt.Printf("%32b\n", view)
|
|
|
|
//log.Printf("%d\n", view)
|
2019-04-02 13:53:52 +00:00
|
|
|
|
|
|
|
*st = UpStatus(view)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get list of positions set
|
|
|
|
func (st UpStatus) GetFlagPositions() []int {
|
|
|
|
var i uint32
|
|
|
|
|
|
|
|
var setBits []int
|
|
|
|
|
|
|
|
for i = 31; i > 0; i-- {
|
|
|
|
if st&(1<<i) != 0 {
|
|
|
|
setBits = append(setBits, int(i))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return setBits
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st UpStatus) PrintStoreStatus() string {
|
|
|
|
if st.Stored() {
|
|
|
|
return UploadStatus[UpStored]
|
|
|
|
} else if st.StoreFail() {
|
|
|
|
return UploadStatus[WaitStore]
|
|
|
|
} else {
|
|
|
|
return UploadStatus[WaitStore]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st UpStatus) PrintPayStatus() string {
|
|
|
|
if st.Paid() {
|
|
|
|
return UploadStatus[UpPaid]
|
|
|
|
}
|
|
|
|
if st.Expired() {
|
|
|
|
return UploadStatus[UpPayExpired]
|
|
|
|
}
|
|
|
|
|
|
|
|
return UploadStatus[WaitPay]
|
|
|
|
}
|
|
|
|
|
2019-04-02 17:40:25 +00:00
|
|
|
func (st UpStatus) IsNew() bool {
|
|
|
|
return (st & UpNew) != 0
|
|
|
|
}
|
|
|
|
|
2019-04-02 13:53:52 +00:00
|
|
|
func (st UpStatus) WaitPay() bool {
|
|
|
|
return (!st.Paid()) && (!st.Expired())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st UpStatus) Stored() bool {
|
|
|
|
return (st & UpStored) != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st UpStatus) StoreFail() bool {
|
|
|
|
return (st & UpStoreFail) != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st UpStatus) Paid() bool {
|
|
|
|
return (st & UpPaid) != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st UpStatus) Expired() bool {
|
|
|
|
return (st & UpPayExpired) != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st UpStatus) GetStoreStatus() UpStatus {
|
|
|
|
return st & StoreMask
|
|
|
|
}
|
|
|
|
|
|
|
|
func (st UpStatus) GetPayStatus() UpStatus {
|
|
|
|
return st & PayMask
|
|
|
|
}
|
|
|
|
|
|
|
|
// First 4 bits are reserved for easier parsing from redis
|
2019-03-17 19:25:44 +00:00
|
|
|
const (
|
2019-04-02 13:53:52 +00:00
|
|
|
UpPayExpired UpStatus = 1 << (32 - 1 - iota)
|
|
|
|
UpPaid
|
|
|
|
|
|
|
|
UpStored // All files for this upload where stored
|
|
|
|
UpStoreFail
|
|
|
|
|
|
|
|
// Only used for printing
|
|
|
|
WaitStore
|
|
|
|
WaitPay
|
|
|
|
|
|
|
|
UpNew = UpStatus(0)
|
|
|
|
|
|
|
|
PayMask = UpPaid | UpPayExpired
|
|
|
|
|
|
|
|
StoreMask = UpStored
|
2019-03-17 19:25:44 +00:00
|
|
|
)
|
|
|
|
|
2019-04-02 13:53:52 +00:00
|
|
|
var UploadStatus = map[UpStatus]string{
|
|
|
|
UpNew: "new upload",
|
|
|
|
|
|
|
|
// Payment
|
|
|
|
UpPayExpired: "expired",
|
|
|
|
UpPaid: "paid",
|
|
|
|
WaitPay: "waiting",
|
|
|
|
|
|
|
|
// Storage
|
|
|
|
WaitStore: "waiting storage",
|
|
|
|
UpStored: "stored",
|
2019-03-21 17:44:40 +00:00
|
|
|
}
|
|
|
|
|
2019-03-15 18:00:35 +00:00
|
|
|
var (
|
|
|
|
ErrDoesNotExist = errors.New("does not exist")
|
|
|
|
ErrAlreadyExists = errors.New("already exists")
|
|
|
|
)
|
|
|
|
|
2019-04-05 16:18:44 +00:00
|
|
|
type FileUpload struct {
|
|
|
|
ID string `db:"file_upload_id"`
|
|
|
|
UploadId string `db:"upload_id"`
|
2019-03-29 12:10:06 +00:00
|
|
|
SHA256 string `db:"sha256"`
|
|
|
|
FileName string `db:"file_name"`
|
|
|
|
FileType string `db:"file_type"`
|
|
|
|
FileSize int64 `db:"file_size"`
|
|
|
|
FileExt string `db:"file_ext"`
|
2019-04-02 13:53:52 +00:00
|
|
|
Stored bool `db:"stored"`
|
2019-04-05 16:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Upload struct {
|
2019-04-07 10:30:43 +00:00
|
|
|
UploadId string `db:"upload_id"`
|
2019-04-09 07:20:46 +00:00
|
|
|
DownloadId string `db:"download_id"`
|
2019-04-07 10:30:43 +00:00
|
|
|
AskFee bool `db:"ask_fee"`
|
|
|
|
Created time.Time `db:"created"`
|
|
|
|
AskCurrency string `db:"ask_currency"`
|
|
|
|
AskAmount float64 `db:"ask_amount"`
|
|
|
|
InvoiceRhash string `db:"invoice_rhash"` // used as id
|
|
|
|
Settled bool `db:"settled"`
|
|
|
|
UploadStatus uint32 `db:"status"` // upload flag status
|
2019-04-09 07:20:46 +00:00
|
|
|
AdminToken string `db:"admin_token"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type UploadPayments struct {
|
|
|
|
PaymentId string `db:"payment_id_rhash"`
|
|
|
|
MsatAmount float64 `db:"msat_amount"`
|
|
|
|
PayCreated time.Time `db:"payment_created"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type UploadInfo struct {
|
|
|
|
Upload
|
|
|
|
UploadPayments
|
2019-04-07 10:30:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u Upload) MarshalBinary() ([]byte, error) {
|
|
|
|
return json.Marshal(u)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *Upload) UnmarshalBinary(b []byte) error {
|
|
|
|
return json.Unmarshal(b, &u)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u FileUpload) MarshalBinary() ([]byte, error) {
|
|
|
|
return json.Marshal(u)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *FileUpload) UnmarshalBinary(b []byte) error {
|
|
|
|
return json.Unmarshal(b, &u)
|
2019-03-26 16:03:13 +00:00
|
|
|
}
|
|
|
|
|
2019-03-29 18:50:11 +00:00
|
|
|
// TODO: sync from redis to db
|
|
|
|
//func SyncUploadStatusToDB(){
|
|
|
|
|
|
|
|
//}
|
2019-04-07 20:31:35 +00:00
|
|
|
//
|
|
|
|
func AddPaymentToUpload(uploadId string, rhash string, msatAmount float64) error {
|
|
|
|
query := `INSERT INTO
|
|
|
|
upload_payments (payment_id_rhash, upload_id, msat_amount)
|
|
|
|
VALUES ($1, $2, $3)
|
|
|
|
`
|
|
|
|
_, err := DB.Sql.Exec(query, rhash, uploadId, msatAmount)
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
2019-03-26 16:03:13 +00:00
|
|
|
|
2019-04-05 16:18:44 +00:00
|
|
|
func GetDownloadId(uploadId string) (string, error) {
|
|
|
|
key := fmt.Sprintf("download_for_upload_%s", uploadId)
|
|
|
|
|
|
|
|
// Try redis
|
|
|
|
var downloadId string
|
|
|
|
|
|
|
|
var exists bool
|
|
|
|
|
|
|
|
// Check if exists
|
|
|
|
err := DB.Redis.Do(radix.FlatCmd(&exists, "EXISTS", key))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
//if !exists get from sql and store in redis
|
|
|
|
if !exists {
|
2019-04-06 01:45:50 +00:00
|
|
|
log.Printf("redis: dlId %s not found for, trying form db", uploadId)
|
2019-04-05 16:18:44 +00:00
|
|
|
query := `SELECT download_id from uploads WHERE upload_id = $1`
|
2019-04-05 18:14:23 +00:00
|
|
|
err = DB.Sql.Get(&downloadId, query, uploadId)
|
2019-04-05 16:18:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2019-04-07 10:30:43 +00:00
|
|
|
if downloadId == "" {
|
2019-04-05 16:18:44 +00:00
|
|
|
return "", fmt.Errorf("download id missing in %s", uploadId)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store it back on redis cache
|
2019-04-07 20:31:35 +00:00
|
|
|
err = db.SetKeyVal(key, downloadId)
|
2019-04-06 01:45:50 +00:00
|
|
|
} else {
|
2019-04-07 20:31:35 +00:00
|
|
|
err = db.GetFromKey(key, &downloadId)
|
2019-04-05 16:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return downloadId, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-06 01:45:50 +00:00
|
|
|
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
|
2019-04-07 20:31:35 +00:00
|
|
|
err = db.SetKeyVal(key, upId)
|
2019-04-06 01:45:50 +00:00
|
|
|
} else {
|
2019-04-07 20:31:35 +00:00
|
|
|
err = db.GetFromKey(key, &upId)
|
2019-04-06 01:45:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return upId, err
|
|
|
|
}
|
|
|
|
|
2019-04-02 13:53:52 +00:00
|
|
|
func GetUploadInvoice(uploadId string) (*ln.Invoice, error) {
|
2019-04-04 18:26:43 +00:00
|
|
|
var invoice ln.Invoice
|
2019-04-02 13:53:52 +00:00
|
|
|
|
|
|
|
uploadInvoiceKey := fmt.Sprintf("upload_%s_invoice", uploadId)
|
|
|
|
|
2019-04-07 20:31:35 +00:00
|
|
|
err := db.GetFromKey(uploadInvoiceKey, &invoice)
|
2019-04-02 13:53:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-04-09 07:20:46 +00:00
|
|
|
//log.Printf("GetUploadInvoice returned %#v", invoice)
|
2019-04-07 20:31:35 +00:00
|
|
|
|
2019-04-02 13:53:52 +00:00
|
|
|
return &invoice, nil
|
|
|
|
}
|
|
|
|
|
2019-04-07 10:30:43 +00:00
|
|
|
func GetUploadFilesMeta(uploadId string) ([]FileUpload, error) {
|
|
|
|
key := fmt.Sprintf("upload_files_%s", uploadId)
|
|
|
|
var files []FileUpload
|
|
|
|
var exists bool
|
|
|
|
|
|
|
|
// try redis
|
|
|
|
err := DB.Redis.Do(radix.FlatCmd(&exists, "EXISTS", key))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sql
|
|
|
|
if !exists {
|
|
|
|
log.Printf("upload %s files not in cache", uploadId)
|
|
|
|
query := "SELECT * FROM file_uploads WHERE upload_id = $1"
|
|
|
|
err := DB.Sql.Select(&files, query, uploadId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store back on redis cache
|
|
|
|
err = DB.Redis.Do(radix.FlatCmd(nil, "SADD", key, files))
|
|
|
|
} else {
|
|
|
|
err = DB.Redis.Do(radix.FlatCmd(&files, "SMEMBERS", key))
|
|
|
|
}
|
|
|
|
|
|
|
|
return files, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-09 07:20:46 +00:00
|
|
|
// Get all payments linked to an admin token
|
|
|
|
func GetUploadPaymentsByToken(adminToken string) ([]*UploadInfo, error) {
|
|
|
|
upInfo := []*UploadInfo{}
|
|
|
|
query := `SELECT
|
|
|
|
uploads.upload_id,
|
|
|
|
uploads.download_id,
|
|
|
|
uploads.ask_fee,
|
|
|
|
uploads.ask_currency,
|
|
|
|
uploads.ask_amount,
|
|
|
|
uploads.admin_token,
|
|
|
|
upload_payments.msat_amount,
|
|
|
|
upload_payments.created AS payment_created
|
|
|
|
FROM uploads, upload_payments
|
|
|
|
WHERE uploads.admin_token = $1
|
|
|
|
`
|
|
|
|
err := DB.Sql.Select(&upInfo, query, adminToken)
|
|
|
|
return upInfo, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetMsatBalanceByAdminToken(adminToken string) (float64, error) {
|
|
|
|
var balance float64
|
|
|
|
query := `SELECT SUM(upload_payments.msat_amount)
|
|
|
|
FROM uploads, upload_payments
|
|
|
|
WHERE uploads.upload_id = upload_payments.upload_id
|
|
|
|
AND uploads.admin_token = $1`
|
|
|
|
|
|
|
|
err := DB.Sql.Get(&balance, query, adminToken)
|
|
|
|
return balance, err
|
|
|
|
}
|
|
|
|
|
2019-04-07 10:30:43 +00:00
|
|
|
func GetUploadById(id string) (*Upload, error) {
|
|
|
|
key := fmt.Sprintf("upload_%s", id)
|
|
|
|
up := Upload{}
|
|
|
|
up.UploadId = id
|
|
|
|
|
|
|
|
// Try from redis first
|
|
|
|
var exists bool
|
|
|
|
err := DB.Redis.Do(radix.FlatCmd(&exists, "EXISTS", key))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// if does not exists, get it from sql then set it on redis as cache
|
|
|
|
if !exists {
|
|
|
|
log.Printf("upload %s not found on redis, caching from sql", id)
|
|
|
|
query := `SELECT * FROM uploads WHERE upload_id = $1`
|
|
|
|
err := DB.Sql.Get(&up, query, id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sotre it back on redis
|
2019-04-07 20:31:35 +00:00
|
|
|
err = db.SetKeyVal(key, up)
|
2019-04-07 10:30:43 +00:00
|
|
|
|
|
|
|
// Get it from redis
|
|
|
|
} else {
|
2019-04-07 20:31:35 +00:00
|
|
|
err = db.GetFromKey(key, &up)
|
2019-04-07 10:30:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &up, err
|
|
|
|
}
|
|
|
|
|
2019-04-04 18:26:43 +00:00
|
|
|
func GetUploadIdInvoiceId(uploadId string) (string, error) {
|
|
|
|
|
2019-04-02 17:40:25 +00:00
|
|
|
invoice, err := GetUploadInvoice(uploadId)
|
|
|
|
|
2019-04-03 18:18:51 +00:00
|
|
|
return invoice.RHash, err
|
2019-04-02 17:40:25 +00:00
|
|
|
}
|
|
|
|
|
2019-04-02 13:53:52 +00:00
|
|
|
func SetUploadStatus(id string, status UpStatus) error {
|
2019-04-02 17:40:25 +00:00
|
|
|
//log.Printf("setting upload status for %s", id)
|
2019-04-02 13:53:52 +00:00
|
|
|
|
2019-03-29 18:50:11 +00:00
|
|
|
key := fmt.Sprintf("upload_status_%s", id)
|
2019-04-02 13:53:52 +00:00
|
|
|
|
|
|
|
if status == UpNew {
|
|
|
|
return DB.Redis.Do(radix.FlatCmd(nil, "SETBIT", key, 31, 0))
|
|
|
|
}
|
|
|
|
|
2019-04-02 17:40:25 +00:00
|
|
|
//log.Println("setting upload status for bit positions ", status.GetFlagPositions())
|
2019-04-02 13:53:52 +00:00
|
|
|
// get bit positions
|
|
|
|
|
|
|
|
for _, offset := range status.GetFlagPositions() {
|
2019-04-02 17:40:25 +00:00
|
|
|
//log.Printf("setting bit at position %d", offset)
|
2019-04-02 13:53:52 +00:00
|
|
|
err := DB.Redis.Do(radix.FlatCmd(nil,
|
|
|
|
"SETBIT", key, offset, 1))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-05 16:18:44 +00:00
|
|
|
// Store on sql db
|
|
|
|
query := `UPDATE uploads SET status = $1 WHERE upload_id = $2`
|
|
|
|
_, err := DB.Sql.Exec(query, uint32(status), id)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-04-02 13:53:52 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetUploadStatus(id string) (status UpStatus, err error) {
|
2019-04-02 17:40:25 +00:00
|
|
|
//log.Println("Getting upload status")
|
2019-04-02 13:53:52 +00:00
|
|
|
|
|
|
|
key := fmt.Sprintf("upload_status_%s", id)
|
|
|
|
|
2019-04-07 20:31:35 +00:00
|
|
|
err = db.GetFromKey(key, &status)
|
2019-04-02 13:53:52 +00:00
|
|
|
|
|
|
|
return
|
2019-03-15 18:00:35 +00:00
|
|
|
}
|
|
|
|
|
2019-04-04 00:27:09 +00:00
|
|
|
func SetUploadAdminToken(uploadId, token string) error {
|
|
|
|
key := fmt.Sprintf("upload_admin_%s", uploadId)
|
2019-04-07 20:31:35 +00:00
|
|
|
err := db.SetKeyVal(key, token)
|
2019-04-05 16:18:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
query := `UPDATE uploads SET admin_token = $1 WHERE upload_id = $2`
|
|
|
|
_, err = DB.Sql.Exec(query, token, uploadId)
|
|
|
|
return err
|
2019-04-04 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func GetUploadAdminToken(uploadId string) (string, error) {
|
|
|
|
var token string
|
|
|
|
key := fmt.Sprintf("upload_admin_%s", uploadId)
|
2019-04-07 20:31:35 +00:00
|
|
|
err := db.GetFromKey(key, &token)
|
2019-04-04 00:27:09 +00:00
|
|
|
return token, err
|
|
|
|
}
|
|
|
|
|
2019-03-29 18:50:11 +00:00
|
|
|
func SetUploadInvoice(uploadId string, invoice *ln.Invoice) error {
|
2019-04-01 10:12:29 +00:00
|
|
|
uploadInvoiceKey := fmt.Sprintf("upload_%s_invoice", uploadId)
|
2019-03-29 18:50:11 +00:00
|
|
|
|
2019-04-07 20:31:35 +00:00
|
|
|
err := db.SetKeyVal(uploadInvoiceKey, invoice)
|
2019-04-01 10:12:29 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set inverse relation
|
2019-04-07 20:31:35 +00:00
|
|
|
invoiceUploadKey := fmt.Sprintf("invoice_%s_upload_id", invoice.RHash)
|
|
|
|
err = db.SetKeyVal(invoiceUploadKey, uploadId)
|
2019-04-05 16:18:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// SQL insert
|
|
|
|
tx, err := DB.Sql.Beginx()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add invoice to invoices table
|
2019-04-07 20:31:35 +00:00
|
|
|
query := `INSERT INTO invoices(rhash)
|
|
|
|
VALUES($1)
|
2019-04-05 16:18:44 +00:00
|
|
|
ON CONFLICT DO NOTHING
|
|
|
|
`
|
2019-04-07 20:31:35 +00:00
|
|
|
_, err = tx.Exec(query, invoice.RHash)
|
2019-04-05 16:18:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set invoice to upload
|
|
|
|
query = `UPDATE uploads SET invoice_rhash = $1 WHERE upload_id = $2`
|
|
|
|
_, err = tx.Exec(query, invoice.RHash, uploadId)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
2019-03-29 18:50:11 +00:00
|
|
|
}
|
|
|
|
|
2019-04-03 22:12:03 +00:00
|
|
|
func GetUploadIdForInvoice(invoiceId string) (string, error) {
|
2019-04-07 20:31:35 +00:00
|
|
|
key := fmt.Sprintf("invoice_%s_upload_id", invoiceId)
|
2019-04-03 22:12:03 +00:00
|
|
|
|
2019-04-07 20:31:35 +00:00
|
|
|
err := db.GetFromKey(key, &invoiceId)
|
2019-04-03 22:12:03 +00:00
|
|
|
return invoiceId, err
|
|
|
|
}
|
|
|
|
|
2019-03-21 17:44:40 +00:00
|
|
|
// Returns true if id exists in DB
|
|
|
|
func IdExists(id string) (exists bool, err error) {
|
2019-03-26 16:03:13 +00:00
|
|
|
key := fmt.Sprintf("upload_status_%s", id)
|
2019-03-21 17:44:40 +00:00
|
|
|
|
2019-03-26 16:03:13 +00:00
|
|
|
err = DB.Redis.Do(radix.Cmd(&exists, "EXISTS", key))
|
2019-03-21 17:44:40 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a file by upload id and hash
|
2019-04-05 16:18:44 +00:00
|
|
|
func GetByHashID(sha256 string, id string) (*FileUpload, error) {
|
|
|
|
var up FileUpload
|
2019-03-26 16:03:13 +00:00
|
|
|
|
2019-03-23 18:29:48 +00:00
|
|
|
err := DB.Sql.Get(&up, QGetByHashID, sha256, id)
|
2019-03-21 17:44:40 +00:00
|
|
|
|
|
|
|
if err == sql.ErrNoRows {
|
|
|
|
return nil, ErrDoesNotExist
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &up, nil
|
|
|
|
}
|
|
|
|
|
2019-04-05 16:18:44 +00:00
|
|
|
func (u *FileUpload) TxSetFileStored(tx *sqlx.Tx) error {
|
2019-04-02 13:53:52 +00:00
|
|
|
u.Stored = true
|
2019-04-05 16:18:44 +00:00
|
|
|
_, err := tx.NamedExec(QSetFileStored, u)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *FileUpload) TxWrite(tx *sqlx.Tx) error {
|
|
|
|
query := `INSERT INTO file_uploads
|
|
|
|
(upload_id, sha256, file_name, file_type, file_size, file_ext)
|
|
|
|
VALUES
|
|
|
|
(:upload_id, :sha256, :file_name, :file_type, :file_size, :file_ext)
|
|
|
|
`
|
|
|
|
|
|
|
|
_, err := tx.NamedExec(query, u)
|
|
|
|
|
|
|
|
if pqError, ok := err.(*pq.Error); ok {
|
|
|
|
// unique constraint
|
|
|
|
if pqError.Code == "23505" {
|
|
|
|
return ErrAlreadyExists
|
|
|
|
}
|
|
|
|
}
|
2019-03-21 17:44:40 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *Upload) TxWrite(tx *sqlx.Tx) error {
|
2019-04-05 16:18:44 +00:00
|
|
|
query := `INSERT INTO uploads
|
2019-04-07 11:54:41 +00:00
|
|
|
(upload_id, download_id, ask_fee, ask_currency, ask_amount, settled)
|
2019-04-05 16:18:44 +00:00
|
|
|
VALUES
|
2019-04-07 11:54:41 +00:00
|
|
|
(:upload_id, :download_id, :ask_fee, :ask_currency, :ask_amount, :settled)`
|
2019-03-21 17:44:40 +00:00
|
|
|
|
2019-04-05 16:18:44 +00:00
|
|
|
_, err := tx.NamedExec(query, u)
|
2019-03-23 18:29:48 +00:00
|
|
|
|
2019-03-29 18:50:11 +00:00
|
|
|
if pqError, ok := err.(*pq.Error); ok {
|
|
|
|
// unique constraint
|
|
|
|
if pqError.Code == "23505" {
|
|
|
|
return ErrAlreadyExists
|
|
|
|
}
|
2019-03-21 17:44:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-15 18:00:35 +00:00
|
|
|
func (u *Upload) Write() error {
|
2019-04-05 16:18:44 +00:00
|
|
|
query := `INSERT INTO uploads
|
|
|
|
(upload_id, download_id, ask_fee, ask_currency, settled)
|
|
|
|
VALUES
|
|
|
|
(:upload_id, :download_id, :ask_fee, :ask_currency, :settled)`
|
|
|
|
_, err := DB.Sql.NamedExec(query, u)
|
2019-03-29 18:50:11 +00:00
|
|
|
|
|
|
|
if pqError, ok := err.(*pq.Error); ok {
|
|
|
|
// unique constraint
|
|
|
|
if pqError.Code == "23505" {
|
|
|
|
return ErrAlreadyExists
|
|
|
|
}
|
2019-03-15 18:00:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
2019-04-05 16:18:44 +00:00
|
|
|
_, err := DB.Sql.Exec(DBInvoicesSchema)
|
2019-03-15 18:00:35 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2019-04-05 16:18:44 +00:00
|
|
|
|
|
|
|
_, err = DB.Sql.Exec(DBUploadsSchema)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = DB.Sql.Exec(DBFileUploadsSchema)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2019-04-07 20:39:54 +00:00
|
|
|
_, err = DB.Sql.Exec(DBUploadPaymentsSchema)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2019-03-15 18:00:35 +00:00
|
|
|
}
|