package main import ( "fmt" "html/template" "log" "net/http" "strings" ) func baseLoadTemplate(base string, path string) (*template.Template, any) { return template.New(base).ParseFiles( "./views/"+base, "./views/"+path, "./views/partials/header.html", ) } func loadTemplate(path string) (*template.Template, any) { return baseLoadTemplate("layout.html", path) } func LoadView(writer http.ResponseWriter, path string, data interface{}) { tmpl, err := loadTemplate(path) if err != nil { fmt.Printf("Failed to load view %s\n", path) fmt.Println(err) if path == "500.html" { writer.Write([]byte("

Failed to load 500.html check console for more info

")) } else { LoadView(writer, "500.html", nil) } return } if err := tmpl.Execute(writer, data); err != nil { fmt.Printf("Failed to load view %s\n", path) fmt.Println(err) writer.WriteHeader(http.StatusInternalServerError) if path == "500.html" { writer.Write([]byte("

Failed to load 500.html check console for more info

")) } else { LoadView(writer, "500.html", nil) } return } } /** Only returns the html without template */ func LoadHtml(writer http.ResponseWriter, path string, data interface{}) { tmpl, err := baseLoadTemplate("html.html", path) if err != nil { fmt.Printf("Failed to load template %s\n", path) fmt.Println(err) writer.WriteHeader(http.StatusInternalServerError) if path == "500.html" { writer.Write([]byte("

Failed to load 500.html check console for more info

")) } else { LoadHtml(writer, "500.html", nil) } return } if err := tmpl.Execute(writer, data); err != nil { fmt.Printf("Failed to execute template %s\n", path) fmt.Println(err) writer.WriteHeader(http.StatusInternalServerError) if path == "500.html" { writer.Write([]byte("

Failed to load 500.html check console for more info

")) } else { LoadHtml(writer, "500.html", nil) } return } } type Error struct { code int msg *string } type AnswerType int const ( NORMAL AnswerType = iota HTML JSON HTMLFULL ) func LoadBasedOnAnswer(ans AnswerType, w http.ResponseWriter, path string, data map[string]interface{}) { if ans == NORMAL { LoadView(w, path, nil) return } else if ans == HTML { LoadHtml(w, path, nil) return } else if ans == HTMLFULL { if data == nil { LoadHtml(w, path, map[string]interface{}{ "App": true, }) } else { data["App"] = true LoadHtml(w, path, data) } return } else if ans == JSON { panic("TODO JSON!") } else { panic("unreachable") } } type Handler interface { New() Startup() Get(fn func(mode AnswerType, w http.ResponseWriter, r *http.Request) *Error) } type Handle struct{} func handleError(err *Error, answerType AnswerType, w http.ResponseWriter) { if err != nil { w.WriteHeader(err.code) if err.code == 404 { LoadBasedOnAnswer(answerType, w, "404.html", nil) return } if err.msg != nil { w.Write([]byte(*err.msg)) } } } func (x Handle) Get(path string, fn func(mode AnswerType, w http.ResponseWriter, r *http.Request) *Error) { http.HandleFunc("/"+path, func(w http.ResponseWriter, r *http.Request) { if r.Method != "Get" { header := r.Header.Get("REQUEST-TYPE") if header == "html" { handleError(fn(HTMLFULL, w, r), HTMLFULL, w) return } handleError(fn(NORMAL, w, r), NORMAL, w) } }) http.HandleFunc("/api/html/"+path, func(w http.ResponseWriter, r *http.Request) { if r.Method != "Get" { handleError(fn(HTML, w, r), HTML, w) } }) http.HandleFunc("/api/json/"+path, func(w http.ResponseWriter, r *http.Request) { if r.Method != "Get" { handleError(fn(JSON, w, r), JSON, w) } }) } func (x Handle) New() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { w.WriteHeader(http.StatusNotFound) LoadView(w, "404.html", nil) return } LoadView(w, "index.html", nil) }) http.HandleFunc("/styles/", func(w http.ResponseWriter, r *http.Request) { path := r.URL.Path[len("/styles/"):] if !strings.HasSuffix(path, ".css") { w.WriteHeader(http.StatusNotFound) w.Write([]byte("File not found")) return } t, err := template.ParseFiles("./views/styles/" + path) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Failed to load template")) fmt.Println("Error:") fmt.Println(err) return } w.Header().Set("Content-Type", "text/css; charset=utf-8") t.Execute(w, nil) }) } func (x Handle) Startup() { fmt.Printf("Starting up!\n") log.Fatal(http.ListenAndServe(":8000", nil)) }