149 lines
3.2 KiB
Go
149 lines
3.2 KiB
Go
package server
|
|
|
|
import (
|
|
"embed"
|
|
"errors"
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"retroHub/data"
|
|
"strings"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
"github.com/mileusna/useragent"
|
|
)
|
|
|
|
type injector struct {
|
|
Version string
|
|
}
|
|
|
|
type userAgentInjector struct {
|
|
injector
|
|
UserAgent useragent.UserAgent
|
|
}
|
|
|
|
type providerInjector struct {
|
|
injector
|
|
Provider data.Provider
|
|
}
|
|
|
|
type errorInjector struct {
|
|
injector
|
|
StatusCode int
|
|
StatusText string
|
|
}
|
|
|
|
const version string = "0.1.1"
|
|
|
|
//go:embed templates
|
|
var templates embed.FS
|
|
|
|
var (
|
|
provider data.Provider
|
|
indexTemplate *template.Template
|
|
uaTemplate *template.Template
|
|
errTemplate *template.Template
|
|
|
|
errLog *log.Logger
|
|
)
|
|
|
|
func init() {
|
|
indexTemplate = template.Must(template.ParseFS(templates, "templates/base.html", "templates/index.html"))
|
|
uaTemplate = template.Must(template.ParseFS(templates, "templates/base.html", "templates/ua.html"))
|
|
errTemplate = template.Must(template.ParseFS(templates, "templates/base.html", "templates/error.html"))
|
|
|
|
errLog = log.New(os.Stderr, "", log.LstdFlags)
|
|
}
|
|
|
|
func Serve(contentProvider data.Provider, port uint) error {
|
|
if contentProvider == nil {
|
|
return errors.New("content provider cannot be nil")
|
|
}
|
|
provider = contentProvider
|
|
|
|
r := chi.NewRouter()
|
|
r.Use(middleware.Logger)
|
|
r.Use(panicHandler)
|
|
|
|
r.NotFound(notFoundHandler)
|
|
r.Get("/", indexHandler)
|
|
r.Get("/ua", userAgentHandler)
|
|
|
|
log.Printf("the server is up and running on %d", port)
|
|
err := http.ListenAndServe(fmt.Sprintf(":%d", port), r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func panicHandler(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
errLog.Println("ERROR", r)
|
|
injectedData := errorInjector{
|
|
injector: injector{
|
|
Version: version,
|
|
},
|
|
StatusCode: http.StatusInternalServerError,
|
|
StatusText: "Internal Server Error",
|
|
}
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
err := errTemplate.ExecuteTemplate(w, "base", injectedData)
|
|
if err != nil {
|
|
errLog.Println("ERROR", err)
|
|
}
|
|
}
|
|
}()
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
func indexHandler(w http.ResponseWriter, r *http.Request) {
|
|
injectedData := providerInjector{
|
|
injector: injector{
|
|
Version: version,
|
|
},
|
|
Provider: provider,
|
|
}
|
|
err := indexTemplate.ExecuteTemplate(w, "base", injectedData)
|
|
if err != nil {
|
|
errLog.Println("ERROR", err)
|
|
}
|
|
}
|
|
|
|
func userAgentHandler(w http.ResponseWriter, r *http.Request) {
|
|
injectedData := userAgentInjector{
|
|
injector: injector{
|
|
Version: version,
|
|
},
|
|
}
|
|
userAgent := strings.TrimSpace(r.UserAgent())
|
|
if len(userAgent) > 0 {
|
|
injectedData.UserAgent = useragent.Parse(userAgent)
|
|
}
|
|
err := uaTemplate.ExecuteTemplate(w, "base", injectedData)
|
|
if err != nil {
|
|
errLog.Println("ERROR", err)
|
|
}
|
|
}
|
|
|
|
func notFoundHandler(w http.ResponseWriter, _ *http.Request) {
|
|
injectedData := errorInjector{
|
|
injector: injector{
|
|
Version: version,
|
|
},
|
|
StatusCode: http.StatusNotFound,
|
|
StatusText: "Not Found",
|
|
}
|
|
w.WriteHeader(http.StatusNotFound)
|
|
err := errTemplate.ExecuteTemplate(w, "base", injectedData)
|
|
if err != nil {
|
|
errLog.Println("ERROR", err)
|
|
}
|
|
}
|