Files
server-scripts/haven-notify/templates.go
Jose Henrique b1cdf15cc8
Some checks failed
Check scripts syntax / check-scripts-syntax (push) Successful in 3s
Test automated-nfs-backup / test-automated-nfs-backup (push) Successful in 4s
Haven Notify Build and Deploy / Build Haven Notify Image (pull_request) Has been cancelled
Haven Notify Build and Deploy / Build Haven Notify Image (PR) (pull_request) Has been cancelled
Haven Notify Build and Deploy / Deploy Haven Notify (internal) (pull_request) Has been cancelled
Haven Notify Build and Deploy / Test Haven Notify (pull_request) Has been cancelled
adding test containers
2026-07-16 09:14:51 -03:00

136 lines
3.2 KiB
Go

package main
import (
"bytes"
"embed"
"encoding/json"
"fmt"
"io/fs"
"strconv"
"text/template"
)
//go:embed template/*.tmpl
var templatesFS embed.FS
type templateRenderer struct {
templates map[string]*template.Template
}
type templateExtra struct {
Name string
Value string
}
type backupTemplateData struct {
Title string
Asset string
BackupSizeInMB float64
Extra []templateExtra
}
type updateTemplateData struct {
Host string
Asset string
Time float64
}
type errorTemplateData struct {
Caller string
Message string
Critical bool
Extra []templateExtra
}
func newTemplateRenderer() (*templateRenderer, error) {
return newTemplateRendererFromFS(templatesFS)
}
func newTemplateRendererFromFS(templateFS fs.FS) (*templateRenderer, error) {
functions := template.FuncMap{
"formatSize": formatSize,
"formatSeconds": formatSeconds,
"json": jsonLiteral,
}
templates := make(map[string]*template.Template, 3)
for _, name := range []string{"backup", "update", "error"} {
contents, err := fs.ReadFile(templateFS, "template/"+name+".tmpl")
if err != nil {
return nil, err
}
parsed, err := template.New(name).Funcs(functions).Parse(string(contents))
if err != nil {
return nil, err
}
templates[name] = parsed
}
return &templateRenderer{templates: templates}, nil
}
func (r *templateRenderer) renderBackup(request backupRequest) (discordPayload, error) {
return r.render("backup", backupTemplateData{
Title: *request.Title,
Asset: *request.Asset,
BackupSizeInMB: *request.BackupSizeInMB,
Extra: templateExtras(request.Extra),
})
}
func (r *templateRenderer) renderUpdate(request updateRequest) (discordPayload, error) {
return r.render("update", updateTemplateData{
Host: *request.Host,
Asset: *request.Asset,
Time: *request.Time,
})
}
func (r *templateRenderer) renderError(request errorRequest) (discordPayload, error) {
return r.render("error", errorTemplateData{
Caller: *request.Caller,
Message: *request.Message,
Critical: *request.Critical,
Extra: templateExtras(request.Extra),
})
}
func (r *templateRenderer) render(name string, data any) (discordPayload, error) {
parsed, ok := r.templates[name]
if !ok {
return discordPayload{}, fmt.Errorf("unknown template %q", name)
}
var rendered bytes.Buffer
if err := parsed.Execute(&rendered, data); err != nil {
return discordPayload{}, err
}
var payload discordPayload
if err := json.Unmarshal(rendered.Bytes(), &payload); err != nil {
return discordPayload{}, fmt.Errorf("template produced invalid JSON: %w", err)
}
normalizeDiscordPayload(&payload)
return payload, nil
}
func templateExtras(extra extraRequests) []templateExtra {
result := make([]templateExtra, 0, len(extra))
for _, field := range extra {
result = append(result, templateExtra{Name: *field.Name, Value: *field.Value})
}
return result
}
func jsonLiteral(value any) (string, error) {
encoded, err := json.Marshal(value)
return string(encoded), err
}
func formatSize(size float64) string {
if size >= 1024 {
return fmt.Sprintf("%.2f GiB", size/1024)
}
return fmt.Sprintf("%.2f MiB", size)
}
func formatSeconds(seconds float64) string {
return strconv.FormatFloat(seconds, 'f', -1, 64) + " seconds"
}