mstar-webserver/main.go
2024-12-30 15:20:25 +01:00

144 lines
3.6 KiB
Go

package main
import (
"context"
"embed"
"flag"
"fmt"
"html/template"
"net/http"
"os"
"os/signal"
"time"
"git.mstar.dev/mstar/goutils/middleware"
"git.mstar.dev/mstar/goutils/other"
"github.com/rs/zerolog/hlog"
"github.com/rs/zerolog/log"
)
const HTML_PREFIX = "<!-- "
const HTML_SUFFIX = " -->"
//go:embed templates
var embed_templates embed.FS
//go:embed static
var embed_static embed.FS
//go:embed well-known
var embed_well_known embed.FS
// go: embed robots.txt
var embed_robots_txt string
// go: embed humans.txt
var embed_humans_txt string
func main() {
other.SetupFlags()
portFlag := flag.String("port", "8080", "Set the port. Overwrites env vars")
flag.Parse()
other.ConfigureLoggingFromCliArgs()
mux := http.NewServeMux()
mux.HandleFunc("/{$}", handleRoot)
// Catchall that just redirects to Hetzner's 10GB speedtest file
// TODO: Maybe swap that for a forced zip bomb?
mux.Handle(
"/",
http.RedirectHandler("https://hil-speed.hetzner.com/10GB.bin", http.StatusMovedPermanently),
)
mux.HandleFunc("/cat/awawawa", awawaStream)
// static files in /static
mux.Handle("/static/", http.FileServer(http.FS(embed_static)))
// .well-known from /well-known
mux.Handle(
"/.well-known/",
http.StripPrefix("/.well-known/", http.FileServer(http.FS(embed_well_known))),
)
// Static files not in /static or /.well-known
mux.HandleFunc("/robots.txt", buildHTTPFileReader(embed_robots_txt))
mux.HandleFunc("/humans.txt", buildHTTPFileReader(embed_humans_txt))
server := http.Server{
Addr: ":" + *portFlag,
Handler: middleware.ChainMiddlewares(mux, middleware.LoggingMiddleware),
}
exitChan := make(chan os.Signal, 1)
signal.Notify(exitChan, os.Interrupt)
go func() {
log.Info().Str("addr", server.Addr).Msg("Starting server")
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal().Err(err).Msg("Server exited unexpectedly")
}
}()
<-exitChan
log.Info().Msg("Shutting down server due to Interrupt")
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
err := server.Shutdown(ctx)
if err != nil {
log.Fatal().Err(err).Msg("Failed to cleanly shut down")
}
log.Info().Msg("Clean shutdown complete")
}
func handleRoot(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFS(embed_templates, "templates/index.html")
if err != nil {
http.Error(w, "Couldn't parse template file", http.StatusInternalServerError)
return
}
err = tmpl.Execute(w, nil)
if err != nil {
http.Error(w, "Failed to execute template", http.StatusInternalServerError)
}
}
func buildHTTPFileReader(embed_content string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s", embed_content)
}
}
func awawaStream(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(206)
w.Header().Set("Status", "206")
genStub(
1024,
w,
) // Hardcoded. Firefox & Chrome both have this value and a len of 0 wouldn't work
hlog.FromRequest(r).Debug().Msg("Starting stream")
i := true
// Only run every 0.2 seconds, aka 5 times a second
timer := time.Tick(time.Millisecond * 200)
for {
select {
case <-r.Context().Done():
hlog.FromRequest(r).Debug().Msg("Stream done")
return
case <-timer:
if i {
fmt.Fprint(w, "a")
} else {
fmt.Fprint(w, "w")
}
i = !i
}
}
}
func genStub(length int, w http.ResponseWriter) {
PreSufLen := len(HTML_PREFIX) + len(HTML_SUFFIX)
fmt.Fprint(w, HTML_PREFIX)
for i := 0; i < length-PreSufLen; i++ {
fmt.Fprint(w, '\u0020')
}
fmt.Fprint(w, HTML_SUFFIX)
}