From 62af948ff7851fdb7f6764ed144e6b2eb0d3ca6f Mon Sep 17 00:00:00 2001 From: James Date: Sun, 22 Mar 2026 15:14:22 -0400 Subject: [PATCH] feat: temp-server Go binary (replaces Python http.server) --- temp-server/go.mod | 3 ++ temp-server/main.go | 88 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 temp-server/go.mod create mode 100644 temp-server/main.go diff --git a/temp-server/go.mod b/temp-server/go.mod new file mode 100644 index 0000000..cf936c6 --- /dev/null +++ b/temp-server/go.mod @@ -0,0 +1,3 @@ +module temp-server + +go 1.26.1 diff --git a/temp-server/main.go b/temp-server/main.go new file mode 100644 index 0000000..07b761a --- /dev/null +++ b/temp-server/main.go @@ -0,0 +1,88 @@ +package main + +import ( + "context" + "flag" + "fmt" + "log" + "net/http" + "os" + "os/signal" + "syscall" + "time" +) + +func main() { + folder := flag.String("folder", ".", "Folder to serve") + port := flag.Int("port", 8888, "Port number") + timeout := flag.Int("timeout", 60, "Auto-shutdown after N minutes (0 = no timeout)") + bind := flag.String("bind", "0.0.0.0", "Bind address") + flag.Parse() + + abs, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + _ = abs + + fs := http.FileServer(noCacheFS{http.Dir(*folder)}) + http.Handle("/", fs) + + addr := fmt.Sprintf("%s:%d", *bind, *port) + srv := &http.Server{Addr: addr} + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + go func() { + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT) + <-sig + log.Println("shutting down...") + cancel() + }() + + if *timeout > 0 { + go func() { + select { + case <-time.After(time.Duration(*timeout) * time.Minute): + log.Printf("timeout (%dm) reached, shutting down", *timeout) + cancel() + case <-ctx.Done(): + } + }() + } + + go func() { + <-ctx.Done() + shutCtx, shutCancel := context.WithTimeout(context.Background(), 3*time.Second) + defer shutCancel() + srv.Shutdown(shutCtx) + }() + + log.Printf("serving %s at http://%s (timeout: %dm)", *folder, addr, *timeout) + if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Fatal(err) + } + log.Println("stopped") +} + +type noCacheFS struct{ http.FileSystem } + +func (n noCacheFS) Open(name string) (http.File, error) { return n.FileSystem.Open(name) } + +type noCacheResponseWriter struct { + http.ResponseWriter +} + +func (w noCacheResponseWriter) WriteHeader(code int) { + w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("Expires", "0") + w.ResponseWriter.WriteHeader(code) +} + +func init() { + origHandler := http.DefaultServeMux + _ = origHandler +}