subidx/internal/server/gzip.go
lakshit verma b56447f067
Add web dashboard, live feed, and deployment configs
- Embedded Svelte dashboard: search, virtualized results, filter, sort,
  dates, export, rate budget meter, streaming NDJSON search
- Live feed: SSE /v1/feed, delta polling /v1/watch, x-max-seq cursor,
  ingest hook and subscriber hub, store mutex fix so reads never starve
  behind ingest backlog
- gzip middleware, /v1/stats with cache and bounded top-k
- CORS allow-list flag for split frontend deployments
- Dockerfile + render.yaml + vercel.json, serve gains -no-drain
2026-08-26 21:24:26 +05:30

52 lines
1.2 KiB
Go

package server
import (
"compress/gzip"
"net/http"
"strings"
)
type gzipResponseWriter struct {
http.ResponseWriter
gz *gzip.Writer
}
func (g *gzipResponseWriter) Write(b []byte) (int, error) {
return g.gz.Write(b)
}
func (g *gzipResponseWriter) Flush() {
g.gz.Flush()
if f, ok := g.ResponseWriter.(http.Flusher); ok {
f.Flush()
}
}
// gzipMiddleware compresses search and stats responses when the client
// accepts it. Hostname lists are highly repetitive text (5-6x ratios),
// so BestSpeed keeps the CPU cost trivial even while tailers ingest.
func gzipMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet ||
!strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
next.ServeHTTP(w, r)
return
}
switch r.URL.Path {
case "/v1/search", "/v1/stats":
h := w.Header()
h.Set("Content-Encoding", "gzip")
h.Add("Vary", "Accept-Encoding")
h.Del("Content-Length")
gz, err := gzip.NewWriterLevel(w, gzip.BestSpeed)
if err != nil {
next.ServeHTTP(w, r)
return
}
next.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, gz: gz}, r)
gz.Close()
default:
next.ServeHTTP(w, r)
}
})
}