diff --git a/index.html b/index.html index f98fd30..c01d42d 100644 --- a/index.html +++ b/index.html @@ -14,13 +14,13 @@
- {{ if .HasQuery }} + {{ if ne .Query "" }} {{ .Query }} est un mot IN{{ else }}valid">{{ end }}VALIDE au scrabble. {{ end }}
diff --git a/main.go b/main.go index ab42630..7cd4630 100644 --- a/main.go +++ b/main.go @@ -1,20 +1,23 @@ package main import ( + "context" "embed" + "fmt" + "html/template" + "log/slog" + "net" + "net/http" + "os" + "os/signal" + "strings" + "syscall" + "time" + "unicode" + "golang.org/x/text/runes" "golang.org/x/text/transform" "golang.org/x/text/unicode/norm" - "html/template" - "log/slog" - "net/http" - "strings" - "unicode" -) - -// Variables to customise the search -const ( - listenStr = "0.0.0.0:8090" ) //go:embed ods.txt @@ -30,16 +33,14 @@ var static embed.FS var indexTemplate = template.Must(template.New("index").ParseFS(templatesFS, "index.html")) type IndexData struct { - HasQuery bool - Query string - Invalid bool + Invalid bool + Query string } func getIndex() http.Handler { data := IndexData{ - HasQuery: false, - Query: "", - Invalid: true, + Query: "", + Invalid: true, } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-store, no-cache") @@ -52,9 +53,8 @@ func postIndex() http.Handler { words := strings.Split(ods, "\n") return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data := IndexData{ - HasQuery: true, - Query: r.FormValue("query"), - Invalid: true, + Query: r.FormValue("query"), + Invalid: true, } query, _, _ := transform.String(normalizer, strings.TrimSpace(strings.ToUpper(data.Query))) for _, w := range words { @@ -68,12 +68,72 @@ func postIndex() http.Handler { }) } +func run( + ctx context.Context, + getenv func(string) string, +) error { + ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM) + defer cancel() + + mux := http.NewServeMux() + mux.Handle("GET /static/", http.FileServer(http.FS(static))) + mux.Handle("GET /", getIndex()) + mux.Handle("POST /", postIndex()) + + host := getenv("ODS_HOST") + if host == "" { + host = "127.0.0.1" + } + port := getenv("ODS_PORT") + if port == "" { + port = "8080" + } + + httpServer := &http.Server{ + Addr: net.JoinHostPort(host, port), + Handler: mux, + } + errChan := make(chan error, 1) + go func() { + slog.Info("backend http server listening", "address", httpServer.Addr) + if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { + errChan <- fmt.Errorf("error listening and serving backend http server on %s: %w", httpServer.Addr, err) + } + }() + + select { + case err := <-errChan: + return err + case <-ctx.Done(): + slog.Info("backend http server shutting down") + shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second) + defer shutdownCancel() + if err := httpServer.Shutdown(shutdownCtx); err != nil { + return fmt.Errorf("error shutting down backend http server: %w", err) + } + } + + return nil +} + func main() { - http.Handle("GET /static/", http.FileServer(http.FS(static))) - http.Handle("GET /", getIndex()) - http.Handle("POST /", postIndex()) - slog.Info("listening", "addr", listenStr) - if err := http.ListenAndServe(listenStr, nil); err != nil && err != http.ErrServerClosed { - slog.Error("error listening and serving", "error", err) + ctx := context.Background() + + var opts *slog.HandlerOptions + if os.Getenv("ODS_DEBUG") != "" { + opts = &slog.HandlerOptions{ + AddSource: true, + Level: slog.LevelDebug, + } + } + logger := slog.New(slog.NewJSONHandler(os.Stdout, opts)) + slog.SetDefault(logger) + + if err := run( + ctx, + os.Getenv, + ); err != nil { + fmt.Fprintf(os.Stderr, "%+v\n", err) + os.Exit(1) } }