mirror of
https://github.com/trafficlunar/statsys.git
synced 2026-03-28 11:13:17 +00:00
159 lines
3.6 KiB
Go
159 lines
3.6 KiB
Go
package internal
|
|
|
|
import (
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/klauspost/compress/gzhttp"
|
|
)
|
|
|
|
type Incident struct {
|
|
Status string
|
|
StartTime time.Time
|
|
EndTime *time.Time
|
|
// formatted duration
|
|
Duration string
|
|
}
|
|
|
|
type TimelineEntry struct {
|
|
Status string
|
|
Time time.Time
|
|
FormattedTime string
|
|
}
|
|
|
|
type Service struct {
|
|
Name string
|
|
Url string
|
|
LatencyThreshold int64
|
|
Status string
|
|
MinuteTimeline []TimelineEntry
|
|
HourTimeline []TimelineEntry
|
|
DayTimeline []TimelineEntry
|
|
MinuteUptime float64
|
|
HourUptime float64
|
|
DayUptime float64
|
|
Incidents []Incident
|
|
}
|
|
|
|
type TemplateData struct {
|
|
Title string
|
|
View string
|
|
Theme string
|
|
LinkText string
|
|
LinkUrl string
|
|
EnableThemeSwitcher bool
|
|
LastUpdated int64
|
|
IsOperational bool
|
|
Services []Service
|
|
}
|
|
|
|
type ErrorTemplateData struct {
|
|
Title string
|
|
Error string
|
|
}
|
|
|
|
func ToUpper(s string) string {
|
|
return strings.ToUpper(s)
|
|
}
|
|
|
|
var templateData = TemplateData{
|
|
EnableThemeSwitcher: true,
|
|
LastUpdated: time.Now().UTC().UnixMilli(),
|
|
}
|
|
var tmpl *template.Template
|
|
var errorTmpl *template.Template
|
|
|
|
func renderError(w http.ResponseWriter, statusCode int, message string) {
|
|
w.WriteHeader(statusCode)
|
|
|
|
errorData := ErrorTemplateData{
|
|
Error: message,
|
|
}
|
|
|
|
if err := errorTmpl.ExecuteTemplate(w, "error.html", errorData); err != nil {
|
|
log.Printf("error template execute error: %v", err)
|
|
http.Error(w, message, statusCode)
|
|
}
|
|
}
|
|
|
|
func index(w http.ResponseWriter, req *http.Request) {
|
|
// handle 404
|
|
if req.URL.Path != "/" {
|
|
renderError(w, http.StatusNotFound, "Page not found")
|
|
return
|
|
}
|
|
|
|
data := templateData
|
|
data.View = req.URL.Query().Get("view")
|
|
data.Theme = req.URL.Query().Get("theme")
|
|
|
|
switch data.View {
|
|
case "hours", "minutes", "days":
|
|
// is valid, do nothing
|
|
case "":
|
|
data.View = config.DefaultView
|
|
default:
|
|
renderError(w, http.StatusBadRequest, "Invalid view parameter")
|
|
return
|
|
}
|
|
|
|
if data.Theme == "" {
|
|
data.Theme = config.DefaultTheme
|
|
}
|
|
|
|
if err := tmpl.ExecuteTemplate(w, "index.html", data); err != nil {
|
|
log.Printf("template execute error: %v", err)
|
|
renderError(w, http.StatusInternalServerError, "Internal server error")
|
|
return
|
|
}
|
|
}
|
|
|
|
func styles(w http.ResponseWriter, req *http.Request) {
|
|
http.ServeFile(w, req, "www/styles.css")
|
|
}
|
|
|
|
func favicon(w http.ResponseWriter, req *http.Request) {
|
|
http.ServeFile(w, req, "www/favicon.ico")
|
|
}
|
|
|
|
func robots(w http.ResponseWriter, req *http.Request) {
|
|
http.ServeFile(w, req, "www/robots.txt")
|
|
}
|
|
|
|
func StartHttpServer() {
|
|
var err error
|
|
log.Println("starting server on :8888")
|
|
|
|
// create template
|
|
funcMap := template.FuncMap{
|
|
"ToUpper": ToUpper,
|
|
}
|
|
|
|
tmpl, err = template.New("index").Funcs(funcMap).ParseFiles("www/index.html")
|
|
if err != nil {
|
|
log.Fatalf("failed to parse templates: %v", err)
|
|
}
|
|
errorTmpl, err = template.New("error").ParseFiles("www/error.html")
|
|
if err != nil {
|
|
log.Fatalf("failed to parse templates: %v", err)
|
|
}
|
|
|
|
// http server
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/", index)
|
|
mux.HandleFunc("/styles.css", styles)
|
|
mux.HandleFunc("/favicon.ico", favicon)
|
|
mux.HandleFunc("/robots.txt", robots)
|
|
mux.Handle("/themes/", gzhttp.GzipHandler(http.StripPrefix("/themes/", http.FileServer(http.Dir("www/themes/")))))
|
|
mux.Handle("/fonts/", http.StripPrefix("/fonts/", http.FileServer(http.Dir("www/fonts/"))))
|
|
|
|
// wrap with gzip middleware
|
|
handler := gzhttp.GzipHandler(mux)
|
|
|
|
if err := http.ListenAndServe(":8888", handler); err != nil {
|
|
log.Fatalf("server failed: %v", err)
|
|
}
|
|
}
|