Files
chaosmith-site/main.go

126 lines
3.1 KiB
Go

package main
import (
"compress/gzip"
"io"
"log"
"net/http"
"strings"
"chaosmith-site/blog"
)
type gzipResponseWriter struct {
io.Writer
http.ResponseWriter
}
func (w gzipResponseWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}
func gzipHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
next.ServeHTTP(w, r)
return
}
w.Header().Set("Content-Encoding", "gzip")
w.Header().Del("Content-Length")
gz := gzip.NewWriter(w)
defer gz.Close()
next.ServeHTTP(gzipResponseWriter{Writer: gz, ResponseWriter: w}, r)
})
}
func cacheHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/src/") ||
strings.HasPrefix(r.URL.Path, "/content/images/") ||
strings.HasPrefix(r.URL.Path, "/ABSTRACTS.") ||
strings.HasPrefix(r.URL.Path, "/blog/og/") {
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
}
next.ServeHTTP(w, r)
})
}
type mimeWriter struct {
http.ResponseWriter
override string
wrote bool
}
func (m *mimeWriter) WriteHeader(code int) {
if !m.wrote {
m.wrote = true
m.Header().Set("Content-Type", m.override)
}
m.ResponseWriter.WriteHeader(code)
}
func (m *mimeWriter) Write(b []byte) (int, error) {
if !m.wrote {
m.WriteHeader(200)
}
return m.ResponseWriter.Write(b)
}
func mimeHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ext := strings.ToLower(r.URL.Path[strings.LastIndex(r.URL.Path, ".")+1:])
var ct string
switch ext {
case "woff2":
ct = "font/woff2"
case "woff":
ct = "font/woff"
case "ttf":
ct = "font/ttf"
case "js":
ct = "text/javascript"
case "css":
ct = "text/css"
case "webp":
ct = "image/webp"
case "svg":
ct = "image/svg+xml"
case "ico":
ct = "image/x-icon"
}
if ct != "" {
next.ServeHTTP(&mimeWriter{ResponseWriter: w, override: ct}, r)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/ABSTRACTS.png", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "ABSTRACTS.png")
})
mux.HandleFunc("/ABSTRACTS.webp", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "ABSTRACTS.webp")
})
mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "favicon.ico")
})
mux.HandleFunc("/favicon.svg", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "favicon.svg")
})
mux.Handle("/src/", http.StripPrefix("/src/", http.FileServer(http.Dir("src"))))
mux.Handle("/content/images/", http.StripPrefix("/content/images/", http.FileServer(http.Dir("content/images"))))
if err := blog.RegisterRoutes(mux, "content/posts"); err != nil {
log.Fatalf("blog: %v", err)
}
// Landing page — served by blog package so htmx can swap between sections
mux.HandleFunc("/", blog.ServeLanding)
log.Println("listening on :8000")
http.ListenAndServe(":8000", mimeHandler(cacheHandler(gzipHandler(mux))))
}