You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bit4sat/storage/upload_model.go

208 lines
4.0 KiB
Go

package storage
import (
"database/sql"
"errors"
"fmt"
"log"
"git.sp4ke.com/sp4ke/bit4sat/db"
"github.com/jmoiron/sqlx"
"github.com/mattn/go-sqlite3"
"github.com/mediocregopher/radix/v3"
)
var DB = db.DB
const (
DBUploadSchema = `
CREATE TABLE IF NOT EXISTS upload (
id serial PRIMARY KEY,
upload_id varchar(9) 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),
UNIQUE (upload_id, sha256)
);
`
DBUploadView = `
CREATE OR REPLACE VIEW upload_with_status
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
upload.status = upload_status.type
`
DBUploadStatusSchema = `CREATE TABLE IF NOT EXISTS upload_status
(
type INT NOT NULL PRIMARY KEY,
status CHAR(255) NOT NULL UNIQUE
)
`
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)`
QSetStatus = `UPDATE upload SET status = :status WHERE upload_id = :upload_id `
QGetByHashID = `SELECT upload_id,
sha256,
file_name,
file_type,
file_size,
file_ext,
status
FROM upload WHERE sha256 = $1 AND upload_id = $2`
)
const (
UpNew = iota
UpStored
UpWaitingPayment
UpReady
)
var UploadStatus = map[int]string{
UpNew: "new upload",
UpStored: "stored",
UpWaitingPayment: "waiting payment",
UpReady: "ready",
}
var (
ErrDoesNotExist = errors.New("does not exist")
ErrAlreadyExists = errors.New("already exists")
)
type Upload struct {
ID string `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))
}
// Returns true if id exists in DB
func IdExists(id string) (exists bool, err error) {
key := fmt.Sprintf("upload_status_%s", id)
err = DB.Redis.Do(radix.Cmd(&exists, "EXISTS", key))
return
}
// Get a file by upload id and hash
func GetByHashID(sha256 string, id string) (*Upload, error) {
var up Upload
err := DB.Sql.Get(&up, QGetByHashID, sha256, id)
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)
sqlErr, isSqlErr := err.(sqlite3.Error)
if isSqlErr && sqlErr.Code == sqlite3.ErrConstraint {
return ErrAlreadyExists
}
if err != nil {
return err
}
return nil
}
func (u *Upload) Write() error {
_, err := DB.Sql.NamedExec(QNewUpload, u)
sqlErr, isSqlErr := err.(sqlite3.Error)
if isSqlErr && sqlErr.Code == sqlite3.ErrConstraint {
return ErrAlreadyExists
}
if err != nil {
return err
}
return nil
}
func init() {
_, err := DB.Sql.Exec(DBUploadStatusSchema)
if err != nil {
log.Fatal(err)
}
_, err = DB.Sql.Exec(DBUploadSchema)
if err != nil {
log.Fatal(err)
}
_, err = DB.Sql.Exec(DBUploadView)
if err != nil {
log.Fatal(err)
}
// Populate status types
query := `INSERT INTO upload_status (type, status)
VALUES($1,$2) ON CONFLICT (type) DO UPDATE
SET status = $3`
for k, v := range UploadStatus {
_, err := DB.Sql.Exec(query, k, v, v)
if err != nil {
sqlErr, ok := err.(sqlite3.Error)
if ok && sqlErr.ExtendedCode == sqlite3.ErrConstraintUnique {
log.Panic(err)
}
if !ok {
log.Panic(err)
}
}
}
}