Files
mstore/app/fileoper/putfile.go
T

126 lines
2.9 KiB
Go

/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*/
package fileoper
import (
"context"
"fmt"
"io"
"net/http"
"path"
"strconv"
"mstore/pkg/auxtool"
"mstore/pkg/auxuuid"
"mstore/pkg/descr"
)
// PutFile
type PutFileParams struct {
ContentType string
ContentSize string
Filepath string
Source io.ReadCloser
}
type PutFileResult struct{}
// TODO: checking catalog and file names conflict
func (oper *Operator) PutFile(ctx context.Context, operatorID string, params *PutFileParams) (int, *PutFileResult, error) {
var err error
res := &PutFileResult{}
if params.ContentSize == "" {
code := http.StatusLengthRequired
err = fmt.Errorf("Required Content-Size header is empty")
return code, res, err
}
size, err := strconv.ParseInt(params.ContentSize, 10, 64)
if err != nil {
code := http.StatusLengthRequired
return code, res, err
}
contentType := params.ContentType
if contentType == "" {
contentType = defaultContentType
}
resName := params.Filepath
oper.iLock.WaitAndLock(resName)
defer oper.iLock.Done(resName)
// TODO: convert file path to a unified and secure state
xfilepath, err := cleanFilepath(params.Filepath)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
filename := path.Base(xfilepath)
collection := path.Dir(xfilepath)
tmpname, size, checksum, err := oper.store.WriteTempFile(params.Source)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
var helmHash string
var helmMeta string
if contentType == hcMediaType {
helmMeta, helmHash, err = oper.store.HelmMeta(tmpname)
if err != nil {
code := http.StatusInternalServerError
return code, res, err
}
}
descrExists, fileDescr, err := oper.mdb.GetFileByCollectionName(ctx, 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
fileDescr.UpdatedBy = operatorID
fileDescr.HelmMeta = helmMeta
fileDescr.HelmHash = helmHash
err = oper.mdb.UpdateFileByID(ctx, 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,
CreatedBy: operatorID,
UpdatedBy: operatorID,
HelmMeta: helmMeta,
HelmHash: helmHash,
}
err = oper.mdb.InsertFile(ctx, 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
}