frostfs-http-gw/internal/handler/browse.go
Nikita Zinkevich 733362dbb2
Some checks failed
/ DCO (pull_request) Successful in 51s
/ Vulncheck (pull_request) Successful in 1m15s
/ Lint (pull_request) Successful in 2m5s
/ Tests (pull_request) Successful in 1m13s
/ Builds (pull_request) Failing after 1m7s
[#137] Add index page support
Signed-off-by: Nikita Zinkevich <n.zinkevich@yadro.com>
2024-09-20 14:49:09 +03:00

118 lines
2.5 KiB
Go

package handler
import (
"html/template"
"path"
"strconv"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/utils"
"github.com/docker/go-units"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
"golang.org/x/exp/slices"
)
const (
dateFormat = "02-01-2006 15:04"
attrOID, attrCreated, attrFileName, attrSize = "OID", "Created", "FileName", "Size"
)
type (
BrowsePageData struct {
BucketName,
Prefix string
Objects []ResponseObject
}
ResponseObject struct {
OID string
Created string
FileName string
Size string
}
)
func parseTimestamp(tstamp string) (time.Time, error) {
millis, err := strconv.ParseInt(tstamp, 10, 64)
if err != nil {
return time.Time{}, err
}
return time.UnixMilli(millis), nil
}
func NewResponseObject(nodes map[string]string) ResponseObject {
return ResponseObject{
OID: nodes[attrOID],
Created: nodes[attrCreated],
FileName: nodes[attrFileName],
Size: nodes[attrSize],
}
}
func formatTimestamp(strdate string) string {
date, err := parseTimestamp(strdate)
if err != nil || date.IsZero() {
return ""
}
return date.Format(dateFormat)
}
func formatSize(strsize string) string {
size, err := strconv.ParseFloat(strsize, 64)
if err != nil {
return ""
}
return units.HumanSize(size)
}
func (h *Handler) browseObjects(c *fasthttp.RequestCtx, bucketName, prefix string) {
var log = h.log.With(zap.String("bucket", bucketName))
ctx := utils.GetContextFromRequest(c)
nodes, err := h.listObjects(ctx, bucketName, prefix)
if err != nil {
logAndSendBucketError(c, log, err)
return
}
respObjects := make([]ResponseObject, len(nodes))
for i, node := range nodes {
respObjects[i] = NewResponseObject(node)
}
slices.SortFunc(respObjects, func(a, b ResponseObject) int {
aIsDir := a.Size == ""
bIsDir := b.Size == ""
// prefix objects go first
if aIsDir && !bIsDir {
return -1
} else if !aIsDir && bIsDir {
return 1
}
if a.FileName < b.FileName {
return -1
}
return 1
})
templatePath := h.config.IndexPageTemplatePath()
tmpl, err := template.New(path.Base(templatePath)).Funcs(template.FuncMap{
"formatTimestamp": formatTimestamp,
"formatSize": formatSize,
}).ParseFiles(templatePath)
if err != nil {
logAndSendBucketError(c, log, err)
return
}
if err = tmpl.Execute(c, &BrowsePageData{
BucketName: bucketName,
Prefix: prefix,
Objects: respObjects,
}); err != nil {
logAndSendBucketError(c, log, err)
return
}
}