package main import ( "bytes" "embed" "flag" "fmt" "html/template" "io" "log" "net/http" "net/http/httputil" "net/url" "slices" "strings" "time" ) var ( port = flag.Int("port", 42069, "port to listen on") https = flag.Bool("https", false, "use https") 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)) ) var ( //go:embed templates/blog/post.html.template postString string //go:embed templates/blog/posts blogPostFiles embed.FS ) func preloadBlogPosts() map[string][]byte { base, err := outlineTemplate.Clone() if err != nil { log.Fatalf("outlineTemplate.Clone: %s", err) } base, err = base.New("body").Parse(postString) if err != nil { log.Fatalf("post.html.template: invalid template: %s", err) } postTemplates, err := blogPostFiles.ReadDir("templates/blog/posts") if err != nil { log.Fatalf("blog posts: %s", err) } posts := make(map[string][]byte, len(postTemplates)) for _, post := range postTemplates { postTemplate, err := base.Clone() if err != nil { log.Fatalf("base.Clone: %s", err) } postString, err := blogPostFiles.ReadFile("templates/blog/posts/" + post.Name()) if err != nil { log.Fatalf("somehow I fucked the paths up: %s", err) } postTemplate, err = postTemplate.New("post").Parse(string(postString)) if err != nil { log.Fatalf("%q: invalid template: %s", post.Name(), err) } buf := new(bytes.Buffer) if err := postTemplate.ExecuteTemplate(buf, "outline", nil); err != nil { log.Fatalf("%q: error: %s", post.Name(), err) } posts[strings.TrimSuffix(post.Name(), ".html.template")] = buf.Bytes() } return posts } var blogPostsHTML = preloadBlogPosts() func blog(w http.ResponseWriter, r *http.Request) { post, ok := blogPostsHTML[strings.TrimPrefix(r.URL.Path, "/blog/")] if !ok { notFound(w, r) return } http.ServeContent(w, r, "post.html", serverStartTime, bytes.NewReader(post)) } //go:embed templates/index.html.template var indexString string func preloadIndex() []byte { base, err := outlineTemplate.Clone() if err != nil { log.Fatalf("outlineTemplate.Clone: %s", err) } base.Funcs(template.FuncMap{ "name": func(post string) string { postBytes, err := blogPostFiles.ReadFile("templates/blog/posts/" + post + ".html.template") if err != nil { log.Fatalf("no such post %q: %s", post, err) } date := post[:strings.IndexByte(post, '_')] firstLine := postBytes[:bytes.IndexByte(postBytes, '\n')] return date + ": " + string(bytes.TrimSuffix(bytes.TrimPrefix(firstLine, []byte("