Add comprehensive godoc comments to all exported types, functions, and constants throughout the codebase. Create README.md documenting the project architecture, execution flow, database schema, and component relationships.
144 lines
3.5 KiB
Go
144 lines
3.5 KiB
Go
// Package templates provides embedded HTML templates for the RouteWatch application
|
|
package templates
|
|
|
|
import (
|
|
_ "embed"
|
|
"html/template"
|
|
"net/url"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
//go:embed status.html
|
|
var statusHTML string
|
|
|
|
//go:embed as_detail.html
|
|
var asDetailHTML string
|
|
|
|
//go:embed prefix_detail.html
|
|
var prefixDetailHTML string
|
|
|
|
//go:embed prefix_length.html
|
|
var prefixLengthHTML string
|
|
|
|
// Templates contains all parsed templates
|
|
type Templates struct {
|
|
// Status is the template for the main status page
|
|
Status *template.Template
|
|
// ASDetail is the template for displaying AS (Autonomous System) details
|
|
ASDetail *template.Template
|
|
// PrefixDetail is the template for displaying prefix details
|
|
PrefixDetail *template.Template
|
|
// PrefixLength is the template for displaying prefixes by length
|
|
PrefixLength *template.Template
|
|
}
|
|
|
|
var (
|
|
//nolint:gochecknoglobals // Singleton pattern for templates
|
|
defaultTemplates *Templates
|
|
//nolint:gochecknoglobals // Singleton pattern for templates
|
|
once sync.Once
|
|
)
|
|
|
|
const (
|
|
hoursPerDay = 24
|
|
daysPerMonth = 30
|
|
)
|
|
|
|
// timeSince returns a human-readable duration since the given time
|
|
func timeSince(t time.Time) string {
|
|
duration := time.Since(t)
|
|
if duration < time.Minute {
|
|
return "just now"
|
|
}
|
|
if duration < time.Hour {
|
|
minutes := int(duration.Minutes())
|
|
if minutes == 1 {
|
|
return "1 minute ago"
|
|
}
|
|
|
|
return duration.Truncate(time.Minute).String() + " ago"
|
|
}
|
|
if duration < hoursPerDay*time.Hour {
|
|
hours := int(duration.Hours())
|
|
if hours == 1 {
|
|
return "1 hour ago"
|
|
}
|
|
|
|
return duration.Truncate(time.Hour).String() + " ago"
|
|
}
|
|
days := int(duration.Hours() / hoursPerDay)
|
|
if days == 1 {
|
|
return "1 day ago"
|
|
}
|
|
if days < daysPerMonth {
|
|
return duration.Truncate(hoursPerDay*time.Hour).String() + " ago"
|
|
}
|
|
|
|
return t.Format("2006-01-02")
|
|
}
|
|
|
|
// initTemplates parses all embedded templates
|
|
func initTemplates() {
|
|
var err error
|
|
|
|
defaultTemplates = &Templates{}
|
|
|
|
// Create common template functions
|
|
funcs := template.FuncMap{
|
|
"timeSince": timeSince,
|
|
"urlEncode": url.QueryEscape,
|
|
}
|
|
|
|
// Parse status template
|
|
defaultTemplates.Status, err = template.New("status").Parse(statusHTML)
|
|
if err != nil {
|
|
panic("failed to parse status template: " + err.Error())
|
|
}
|
|
|
|
// Parse AS detail template
|
|
defaultTemplates.ASDetail, err = template.New("asDetail").Funcs(funcs).Parse(asDetailHTML)
|
|
if err != nil {
|
|
panic("failed to parse AS detail template: " + err.Error())
|
|
}
|
|
|
|
// Parse prefix detail template
|
|
defaultTemplates.PrefixDetail, err = template.New("prefixDetail").Funcs(funcs).Parse(prefixDetailHTML)
|
|
if err != nil {
|
|
panic("failed to parse prefix detail template: " + err.Error())
|
|
}
|
|
|
|
// Parse prefix length template
|
|
defaultTemplates.PrefixLength, err = template.New("prefixLength").Funcs(funcs).Parse(prefixLengthHTML)
|
|
if err != nil {
|
|
panic("failed to parse prefix length template: " + err.Error())
|
|
}
|
|
}
|
|
|
|
// Get returns the singleton Templates instance
|
|
func Get() *Templates {
|
|
once.Do(initTemplates)
|
|
|
|
return defaultTemplates
|
|
}
|
|
|
|
// StatusTemplate returns the parsed status template
|
|
func StatusTemplate() *template.Template {
|
|
return Get().Status
|
|
}
|
|
|
|
// ASDetailTemplate returns the parsed AS detail template
|
|
func ASDetailTemplate() *template.Template {
|
|
return Get().ASDetail
|
|
}
|
|
|
|
// PrefixDetailTemplate returns the parsed prefix detail template
|
|
func PrefixDetailTemplate() *template.Template {
|
|
return Get().PrefixDetail
|
|
}
|
|
|
|
// PrefixLengthTemplate returns the parsed prefix length template
|
|
func PrefixLengthTemplate() *template.Template {
|
|
return Get().PrefixLength
|
|
}
|