package main import ( "embed" "flag" "fmt" "html/template" "io" "log" "net/http" "strings" "time" ) var ( port = flag.Int("port", 42069, "port to listen on") serverStartTime = time.Now() ) var ( //go:embed templates/404.html.template notFoundString string notFoundTemplate = template.Must(template.New("notFound").Parse(notFoundString)) ) func notFound(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) type args struct { Path string } if err := notFoundTemplate.Execute(w, args{Path: r.URL.Path}); err != nil { log.Printf("Warning: notFound: %s", err) } } var ( //go:embed templates/outline.html.template outlineString string outlineTemplate = template.Must(template.New("outline").Parse(outlineString)) //go:embed templates/index.html.template indexString string indexTemplate = template.Must(template.Must(outlineTemplate.Clone()).New("body").Parse(indexString)) ) func index(w http.ResponseWriter, _ *http.Request) { if err := indexTemplate.ExecuteTemplate(w, "outline", nil); err != nil { log.Printf("Warning: index: %s", err) } } var ( //go:embed templates/pong.html.template pongString string pongTemplate = template.Must(template.New("pong").Parse(pongString)) ) func pong(w http.ResponseWriter, _ *http.Request) { if err := pongTemplate.Execute(w, nil); err != nil { log.Printf("Warning: pong: %s", err) } } //go:embed static var staticFiles embed.FS func serveStaticFile(w http.ResponseWriter, r *http.Request, path string) { f, err := staticFiles.Open(path) if err != nil { notFound(w, r) return } defer f.Close() http.ServeContent(w, r, path, serverStartTime, f.(io.ReadSeeker)) } func static(w http.ResponseWriter, r *http.Request) { serveStaticFile(w, r, strings.TrimPrefix(r.URL.Path, "/")) } func favicon(w http.ResponseWriter, r *http.Request) { serveStaticFile(w, r, "static/favicon.ico") } func main() { flag.Parse() http.HandleFunc("GET /pong", pong) http.HandleFunc("GET /static/", static) http.HandleFunc("GET /favicon.ico", favicon) http.HandleFunc("GET /{$}", index) http.HandleFunc("GET /", notFound) addr := fmt.Sprintf(":%d", *port) log.Printf("Listening on %q", addr) log.Fatal(http.ListenAndServe(addr, nil)) }