bit4sat/storage/upload_model.go

209 lines
4.0 KiB
Go
Raw Normal View History

2019-03-15 18:00:35 +00:00
package storage
import (
2019-03-21 17:44:40 +00:00
"database/sql"
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-03-23 18:29:48 +00:00
"git.sp4ke.com/sp4ke/bit4sat/db"
2019-03-21 17:44:40 +00:00
"github.com/jmoiron/sqlx"
2019-03-15 18:00:35 +00:00
"github.com/mattn/go-sqlite3"
2019-03-26 16:03:13 +00:00
"github.com/mediocregopher/radix/v3"
"github.com/segmentio/ksuid"
2019-03-15 18:00:35 +00:00
)
var DB = db.DB
const (
DBUploadSchema = `
2019-03-24 21:36:28 +00:00
CREATE TABLE IF NOT EXISTS upload (
2019-03-27 15:35:36 +00:00
id serial PRIMARY KEY,
upload_id varchar(27) NOT NULL,
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 '',
status integer DEFAULT 0 REFERENCES upload_status(type),
2019-03-21 17:44:40 +00:00
UNIQUE (upload_id, sha256)
2019-03-15 18:00:35 +00:00
);
`
2019-03-21 17:44:40 +00:00
DBUploadView = `
2019-03-27 15:35:36 +00:00
CREATE OR REPLACE VIEW upload_with_status
2019-03-24 21:36:28 +00:00
AS SELECT
upload.upload_id,
upload.sha256,
upload_status.status,
upload.file_name,
upload.file_type,
upload.file_size,
upload.file_ext
FROM upload
JOIN upload_status ON
2019-03-21 17:44:40 +00:00
upload.status = upload_status.type
`
DBUploadStatusSchema = `CREATE TABLE IF NOT EXISTS upload_status
(
2019-03-24 21:36:28 +00:00
type INT NOT NULL PRIMARY KEY,
status CHAR(255) NOT NULL UNIQUE
2019-03-21 17:44:40 +00:00
)
`
QNewUpload = `INSERT INTO upload
(upload_id, sha256, file_name, file_type, file_size, file_ext, status)
VALUES
(:upload_id, :sha256, :file_name, :file_type, :file_size, :file_ext, :status)`
2019-03-21 17:44:40 +00:00
QSetStatus = `UPDATE upload SET status = :status WHERE upload_id = :upload_id `
2019-03-26 16:03:13 +00:00
QGetByHashID = `SELECT upload_id,
sha256,
file_name,
file_type,
file_size,
file_ext,
status
2019-03-27 15:35:36 +00:00
FROM upload WHERE sha256 = $1 AND upload_id = $2`
2019-03-15 18:00:35 +00:00
)
2019-03-17 19:25:44 +00:00
const (
UpNew = iota
2019-03-21 17:44:40 +00:00
UpStored
2019-03-17 19:25:44 +00:00
UpWaitingPayment
UpReady
)
2019-03-21 17:44:40 +00:00
var UploadStatus = map[int]string{
UpNew: "new upload",
UpStored: "stored",
UpWaitingPayment: "waiting payment",
UpReady: "ready",
}
2019-03-15 18:00:35 +00:00
var (
ErrDoesNotExist = errors.New("does not exist")
ErrAlreadyExists = errors.New("already exists")
)
type Upload struct {
2019-03-26 16:03:13 +00:00
ID ksuid.KSUID `db:"upload_id"`
SHA256 string `db:"sha256"`
FileName string `db:"file_name"`
FileType string `db:"file_type"`
FileSize int64 `db:"file_size"`
FileExt string `db:"file_ext"`
Status int `db:"status"`
}
func CacheSetUploadStatus(id string, status int) error {
key := fmt.Sprintf("upload_status_%s", id)
return DB.Redis.Do(radix.FlatCmd(nil, "SET", key, status))
2019-03-15 18:00:35 +00:00
}
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
func GetByHashID(sha256 string, id string) (*Upload, error) {
var up Upload
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
}
func (u *Upload) TxSetState(tx *sqlx.Tx, status int) error {
_, err := tx.NamedExec(QSetStatus, u)
if err != nil {
return err
}
return nil
}
func (u *Upload) TxWrite(tx *sqlx.Tx) error {
_, err := tx.NamedExec(QNewUpload, u)
2019-03-23 18:29:48 +00:00
2019-03-21 17:44:40 +00:00
sqlErr, isSqlErr := err.(sqlite3.Error)
2019-03-23 18:29:48 +00:00
2019-03-21 17:44:40 +00:00
if isSqlErr && sqlErr.Code == sqlite3.ErrConstraint {
return ErrAlreadyExists
}
if err != nil {
return err
}
return nil
}
2019-03-15 18:00:35 +00:00
func (u *Upload) Write() error {
2019-03-23 18:29:48 +00:00
_, err := DB.Sql.NamedExec(QNewUpload, u)
2019-03-15 18:00:35 +00:00
sqlErr, isSqlErr := err.(sqlite3.Error)
if isSqlErr && sqlErr.Code == sqlite3.ErrConstraint {
return ErrAlreadyExists
}
if err != nil {
return err
}
return nil
}
func init() {
2019-03-24 21:36:28 +00:00
_, err := DB.Sql.Exec(DBUploadStatusSchema)
2019-03-15 18:00:35 +00:00
if err != nil {
log.Fatal(err)
}
2019-03-24 21:36:28 +00:00
_, err = DB.Sql.Exec(DBUploadSchema)
2019-03-21 17:44:40 +00:00
if err != nil {
log.Fatal(err)
}
2019-03-24 21:36:28 +00:00
_, err = DB.Sql.Exec(DBUploadView)
2019-03-21 17:44:40 +00:00
if err != nil {
log.Fatal(err)
}
// Populate status types
2019-03-27 15:35:36 +00:00
query := `INSERT INTO upload_status (type, status)
VALUES($1,$2) ON CONFLICT (type) DO UPDATE
SET status = $3`
2019-03-21 17:44:40 +00:00
for k, v := range UploadStatus {
2019-03-26 13:42:07 +00:00
_, err := DB.Sql.Exec(query, k, v, v)
2019-03-21 17:44:40 +00:00
if err != nil {
sqlErr, ok := err.(sqlite3.Error)
if ok && sqlErr.ExtendedCode == sqlite3.ErrConstraintUnique {
log.Panic(err)
}
if !ok {
log.Panic(err)
}
}
}
2019-03-15 18:00:35 +00:00
}