check / check (push) Waiting to run
For a database target, the target list showed only its expiry, so the archive file the README's backup and move-away advice depend on could only be found from a shell on the host. Each database target now shows its archive file's name, its size on disk (the file and its -wal together) and when it was last written, relative with the full UTC time on hover, all from the files' metadata without opening the archive. Before the first write, and after the file has been moved away, it shows the name and "not created yet". Tests cover all three states. Model: opus-5-5
91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"errors"
|
|
"io/fs"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
"sneak.berlin/go/webhooker/internal/delivery"
|
|
)
|
|
|
|
// TargetRowView is one row of the target list on a webhook's page.
|
|
type TargetRowView struct {
|
|
delivery.TargetView
|
|
|
|
// Archive is a database target's archive file, and nil for a target
|
|
// of any other type.
|
|
Archive *ArchiveFileView
|
|
}
|
|
|
|
// ArchiveFileView is what a database target's row shows about its
|
|
// archive file.
|
|
type ArchiveFileView struct {
|
|
Name string
|
|
|
|
// Note stands in for the size and the last write when there are
|
|
// none to show, and is empty when there are.
|
|
Note string
|
|
|
|
// Size is the size on disk. Written is how long ago the file was
|
|
// last written, and WrittenUTC the full time the page shows on
|
|
// hover.
|
|
Size string
|
|
Written string
|
|
WrittenUTC string
|
|
}
|
|
|
|
// targetRows projects a webhook's targets for the target list on its
|
|
// page.
|
|
func (h *Handlers) targetRows(
|
|
webhook *database.Webhook, targets []database.Target,
|
|
) []TargetRowView {
|
|
views := delivery.NewTargetViews(targets)
|
|
rows := make([]TargetRowView, len(views))
|
|
|
|
// NewTargetViews returns one view per target, in order.
|
|
for i := range views {
|
|
rows[i].TargetView = views[i]
|
|
|
|
if targets[i].Type == database.TargetTypeDatabase {
|
|
rows[i].Archive = h.archiveFileView(webhook, &targets[i])
|
|
}
|
|
}
|
|
|
|
return rows
|
|
}
|
|
|
|
// archiveFileView describes a database target's archive file from the
|
|
// file's metadata alone; the archive is never opened. The file is found
|
|
// by the name the archive writer uses, so it follows a rename of the
|
|
// webhook or the target.
|
|
func (h *Handlers) archiveFileView(
|
|
webhook *database.Webhook, target *database.Target,
|
|
) *ArchiveFileView {
|
|
path := delivery.ArchivePath(h.dbMgr, webhook, target)
|
|
view := &ArchiveFileView{Name: filepath.Base(path)}
|
|
|
|
file, err := delivery.StatArchive(path)
|
|
|
|
switch {
|
|
case errors.Is(err, fs.ErrNotExist):
|
|
view.Note = "not created yet"
|
|
case err != nil:
|
|
h.log.Error(
|
|
"failed to read archive file metadata",
|
|
"target_id", target.ID,
|
|
"error", err,
|
|
)
|
|
|
|
view.Note = "could not be read"
|
|
default:
|
|
view.Size = humanize.Bytes(uint64(file.Size)) //nolint:gosec // never negative
|
|
view.Written = humanize.Time(file.Written)
|
|
view.WrittenUTC = file.Written.UTC().Format(time.DateTime) + " UTC"
|
|
}
|
|
|
|
return view
|
|
}
|