96 lines
2.3 KiB
Go
96 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"html/template"
|
|
"net/http"
|
|
|
|
"github.com/serverwentdown/datetime.link/data"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// Datetime is the main application server
|
|
type Datetime struct {
|
|
*http.ServeMux
|
|
tmpl *template.Template
|
|
cities map[string]*data.City
|
|
}
|
|
|
|
// NewDatetime creates an application instance. It assumes certain resources
|
|
// like templates and data exist
|
|
func NewDatetime() (*Datetime, error) {
|
|
// Data
|
|
tmpl, err := template.ParseGlob("templates/*")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cities, err := data.ReadCities()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Mux
|
|
mux := http.NewServeMux()
|
|
app := &Datetime{mux, tmpl, cities}
|
|
|
|
// Routes
|
|
mux.Handle("/data/", http.FileServer(http.Dir(".")))
|
|
mux.Handle("/js/", http.FileServer(http.Dir("assets")))
|
|
mux.Handle("/css/", http.FileServer(http.Dir("assets")))
|
|
mux.Handle("/favicon.ico", http.FileServer(http.Dir("assets")))
|
|
mux.HandleFunc("/", app.index)
|
|
|
|
return app, nil
|
|
}
|
|
|
|
// index handles all incoming page requests
|
|
func (app Datetime) index(w http.ResponseWriter, req *http.Request) {
|
|
var err error
|
|
|
|
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
accept := req.Header.Get("Accept")
|
|
tmpl, acceptable := app.chooseTemplate(accept)
|
|
if !acceptable {
|
|
w.WriteHeader(http.StatusNotAcceptable)
|
|
return
|
|
}
|
|
if tmpl == nil {
|
|
l.Error("unable to find template", zap.String("accept", accept))
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if req.Method == http.MethodHead {
|
|
return
|
|
}
|
|
|
|
l.Debug("", zap.Reflect("url", req.URL))
|
|
err = tmpl.Execute(w, nil)
|
|
if err != nil {
|
|
l.Error("templating failed", zap.Error(err))
|
|
w.WriteHeader(http.StatusInternalServerError) // Usually this will fail
|
|
return
|
|
}
|
|
}
|
|
|
|
// chooseTemplate returns a template based on the accepted mime types from the
|
|
// client, and if a template cannot be found it returns a nil template.
|
|
func (app Datetime) chooseTemplate(accept string) (t *template.Template, acceptable bool) {
|
|
responseType := chooseResponseType(accept)
|
|
templateName := ""
|
|
switch responseType {
|
|
case responsePlain:
|
|
templateName = "index.txt"
|
|
case responseHTML:
|
|
templateName = "index.html"
|
|
case responseAny:
|
|
templateName = "index.txt"
|
|
case responseUnknown:
|
|
return nil, false
|
|
}
|
|
return app.tmpl.Lookup(templateName), true
|
|
}
|