Files
bird-lg-go/frontend/template.go
2025-07-01 17:45:12 -07:00

184 lines
3.9 KiB
Go

package main
import (
"embed"
"html/template"
"net/url"
"regexp"
"strings"
)
// import templates and other assets
//
//go:embed assets
var assets embed.FS
const TEMPLATE_PATH = "assets/templates/"
// template argument structures
// page
type TemplatePage struct {
// Global options
Options map[string]string
Servers []string
ServersDisplay []string
// Parameters related to current request
AllServersLinkActive bool
AllServerTitle string
AllServersURL string
AllServersURLCustom string
// Whois specific handling (for its unique URL)
IsWhois bool
WhoisTarget string
URLOption string
URLServer string
URLCommand string
// Generated content to be displayed
Title string
Brand string
BrandURL string
Content template.HTML
}
// summary
type SummaryRowData struct {
Name string `json:"name"`
Proto string `json:"proto"`
Table string `json:"table"`
State string `json:"state"`
MappedState string `json:"-"`
Since string `json:"since"`
Info string `json:"info"`
}
// utility functions to allow filtering of results in the template
func (r SummaryRowData) NameHasPrefix(prefix string) bool {
return strings.HasPrefix(r.Name, prefix)
}
func (r SummaryRowData) NameContains(prefix string) bool {
return strings.Contains(r.Name, prefix)
}
func (r SummaryRowData) ProtocolMatches(protocols []string) bool {
for _, protocol := range protocols {
if strings.EqualFold(r.Proto, protocol) {
return true
}
}
return false
}
// pre-compiled regexp and constant statemap for summary rendering
var splitSummaryLine = regexp.MustCompile(`^([\w-]+)\s+(\w+)\s+([\w-]+)\s+(\w+)\s+([0-9\-\. :]+)(.*)$`)
var summaryStateMap = map[string]string{
"up": "success",
"down": "secondary",
"start": "danger",
"passive": "info",
}
func SummaryRowDataFromLine(line string) *SummaryRowData {
lineSplitted := splitSummaryLine.FindStringSubmatch(line)
if lineSplitted == nil {
return nil
}
var row SummaryRowData
row.Name = strings.TrimSpace(lineSplitted[1])
row.Proto = strings.TrimSpace(lineSplitted[2])
row.Table = strings.TrimSpace(lineSplitted[3])
row.State = strings.TrimSpace(lineSplitted[4])
row.Since = strings.TrimSpace(lineSplitted[5])
row.Info = strings.TrimSpace(lineSplitted[6])
if strings.Contains(row.Info, "Passive") {
row.MappedState = summaryStateMap["passive"]
} else {
row.MappedState = summaryStateMap[row.State]
}
return &row
}
type TemplateSummary struct {
ServerName string
Raw string
Header []string
Rows []SummaryRowData
}
// whois
type TemplateWhois struct {
Target string
Result template.HTML
}
// bgpmap
type TemplateBGPmap struct {
Servers []string
Target string
Result string
}
// bird
type TemplateBird struct {
ServerName string
Target string
Result template.HTML
}
// global variable to hold the templates
var TemplateLibrary map[string]*template.Template
// list of required templates
var requiredTemplates = [...]string{
"page",
"summary",
"whois",
"bgpmap",
"bird",
}
// define functions to be made available in templates
var funcMap = template.FuncMap{
"pathescape": url.PathEscape,
}
// import templates from embedded assets
func ImportTemplates() {
// create a new (blank) initial template
TemplateLibrary = make(map[string]*template.Template)
// for each template that is needed
for _, tmpl := range requiredTemplates {
// extract the template definition from the embedded assets
def, err := assets.ReadFile(TEMPLATE_PATH + tmpl + ".tpl")
if err != nil {
panic("Unable to read template (" + TEMPLATE_PATH + tmpl + ": " + err.Error())
}
// and add it to the template library
template, err := template.New(tmpl).Funcs(funcMap).Parse(string(def))
if err != nil {
panic("Unable to parse template (" + TEMPLATE_PATH + tmpl + ": " + err.Error())
}
// store in the library
TemplateLibrary[tmpl] = template
}
}