bit4sat/storage/upload_model.go
2019-03-24 22:36:28 +01:00

201 lines
3.8 KiB
Go

package storage
import (
"database/sql"
"errors"
"log"
"git.sp4ke.com/sp4ke/bit4sat/db"
"github.com/jmoiron/sqlx"
"github.com/mattn/go-sqlite3"
)
var DB = db.DB
const (
DBUploadSchema = `
CREATE TABLE IF NOT EXISTS upload (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
upload_id CHAR(20) NOT NULL,
sha256 CHAR(32) NOT NULL,
file_name CHAR(255) NOT NULL,
file_type CHAR(255) DEFAULT '',
file_size INT NOT NULL,
file_ext CHAR(255) DEFAULT '',
status INT DEFAULT 0,
FOREIGN KEY (status) REFERENCES upload_status(type),
UNIQUE (upload_id, sha256)
);
`
DBUploadView = `
CREATE VIEW IF NOT EXISTS 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 * FROM upload
WHERE
sha256 = ?
AND
upload_id = ?`
)
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"`
}
// Returns true if id exists in DB
func IdExists(id string) (exists bool, err error) {
qUploadExists := `
SELECT EXISTS (SELECT upload_id FROM upload where upload_id = ?)
`
err = DB.Sql.Get(&exists, qUploadExists, id)
// No result found is also no result
if err == sql.ErrNoRows {
err = nil
}
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(?,?)`
for k, v := range UploadStatus {
_, err := DB.Sql.Exec(query, k, v)
if err != nil {
sqlErr, ok := err.(sqlite3.Error)
if ok && sqlErr.ExtendedCode == sqlite3.ErrConstraintUnique {
log.Panic(err)
}
if !ok {
log.Panic(err)
}
}
}
}