Files
mstore/app/operator/file.go
T
2026-01-28 15:33:19 +02:00

209 lines
4.7 KiB
Go

package operator
import (
"io"
"net/http"
"path"
"strconv"
"mstore/app/descr"
"mstore/pkg/auxtool"
"mstore/pkg/auxuuid"
)
// File exists
type FileExistsParams struct {
Filepath string
Source string
Dest string
}
type FileExistsResult struct {
ContentType string
ContentLength string
ContentDigest string
}
func (oper *Operator) FileExists(param *FileExistsParams) (int, *FileExistsResult, error) {
var err error
code := http.StatusOK
res := &FileExistsResult{}
filename := path.Base(param.Filepath)
collection := path.Dir(param.Filepath)
exist, fileDescr, err := oper.mdb.GetFileByCollection(collection, filename)
if !exist {
code = http.StatusNotFound
return code, res, err
}
res = &FileExistsResult{
ContentLength: strconv.FormatInt(fileDescr.Size, 10),
ContentType: fileDescr.Type,
ContentDigest: fileDescr.Checksum,
}
return code, res, err
}
// Put file
type PutFileParams struct {
ContentType string
ContentLength string
Filepath string
Source io.ReadCloser
}
type PutFileResult struct{}
const defaultContentType = "application/octet-stream"
func (oper *Operator) PutFile(param *PutFileParams) (int, *PutFileResult, error) {
var err error
res := &PutFileResult{}
size, err := strconv.ParseInt(param.ContentLength, 10, 64)
if err != nil {
code := http.StatusLengthRequired
return code, res, err
}
contentType := param.ContentType
if contentType == "" {
contentType = defaultContentType
}
// TODO: convert file path to a unified and secure state
filename := path.Base(param.Filepath)
collection := path.Dir(param.Filepath)
oper.logg.Debugf("Put file %s %s", collection, filename)
tmpname, size, checksum, err := oper.store.WriteTempFile(param.Source)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
descrExists, fileDescr, err := oper.mdb.GetFileByCollection(collection, filename)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
now := auxtool.TimeNow()
if descrExists {
fileDescr.Size = size
fileDescr.Checksum = checksum
fileDescr.UpdatedAt = now
fileDescr.Type = contentType
err = oper.mdb.UpdateFileByID(fileDescr.ID, fileDescr)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
} else {
fileDescr = &descr.File{
ID: auxuuid.NewUUID(),
Name: filename,
Collection: collection,
Size: size,
Type: contentType,
Checksum: checksum,
CreatedAt: now,
UpdatedAt: now,
}
err = oper.mdb.InsertFile(fileDescr)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
}
err = oper.store.HardlinkFile(tmpname, collection, filename)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
code := http.StatusOK
return code, res, err
}
// Get file
type GetFileParams struct {
Filepath string
}
type GetFileResult struct {
ContentType string
ContentLength string
ContentDigest string
Source io.ReadCloser
}
func (oper *Operator) GetFile(param *GetFileParams) (int, *GetFileResult, error) {
var err error
res := &GetFileResult{}
// TODO: convert file path to a unified and secure state
filename := path.Base(param.Filepath)
collection := path.Dir(param.Filepath)
oper.logg.Debugf("Gut file %s %s", collection, filename)
descrExists, fileDescr, err := oper.mdb.GetFileByCollection(collection, filename)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
if !descrExists {
code := http.StatusNotFound
return code, res, err
}
reader, err := oper.store.GetFileReader(collection, filename)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
res = &GetFileResult{
ContentLength: strconv.FormatInt(fileDescr.Size, 10),
ContentType: fileDescr.Type,
ContentDigest: fileDescr.Checksum,
Source: reader,
}
code := http.StatusOK
return code, res, err
}
// Delete file
type DeleteFileParams struct {
Filepath string
}
type DeleteFileResult struct{}
func (oper *Operator) DeleteFile(param *DeleteFileParams) (int, *DeleteFileResult, error) {
var err error
res := &DeleteFileResult{}
code := http.StatusOK
filename := path.Base(param.Filepath)
collection := path.Dir(param.Filepath)
exist, _, err := oper.mdb.GetFileByCollection(collection, filename)
if err != nil {
code = http.StatusInternalServerError
return code, res, err
}
if exist {
err = oper.mdb.DeleteFileByCollection(collection, filename)
if err != nil {
code = http.StatusInternalServerError
return code, res, err
}
}
err = oper.store.DeleteFile(collection, filename)
if err != nil {
code = http.StatusInternalServerError
return code, res, err
}
return code, res, err
}