diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e001bbe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tmp/ +projectreshoot diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bc48ad9 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module projectreshoot + +go 1.23.5 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/handlers/root.go b/handlers/root.go new file mode 100644 index 0000000..09ecb06 --- /dev/null +++ b/handlers/root.go @@ -0,0 +1,19 @@ +package handlers + +import ( + "html/template" + "net/http" +) + +func HandleRoot() http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.NotFound(w, r) + return + } + templ := template.Must(template.ParseFiles("templates/index.html")) + templ.Execute(w, nil) + }, + ) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..a108f0c --- /dev/null +++ b/main.go @@ -0,0 +1,60 @@ +package main + +import ( + "context" + "fmt" + "io" + "net" + "net/http" + "os" + "os/signal" + "sync" + "time" +) + +func run(ctx context.Context, w io.Writer, args []string) error { + ctx, cancel := signal.NotifyContext(ctx, os.Interrupt) + defer cancel() + + config := &Config{ + Host: "", + Port: "3333", + } + + srv := NewServer(config) + httpServer := &http.Server{ + Addr: net.JoinHostPort(config.Host, config.Port), + Handler: srv, + } + + go func() { + fmt.Fprintf(w, "Listening on %s\n", httpServer.Addr) + if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { + fmt.Fprintf(os.Stderr, "Error listening and serving: %s\n", err) + } + }() + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + <-ctx.Done() + shutdownCtx := context.Background() + shutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second) + defer cancel() + if err := httpServer.Shutdown(shutdownCtx); err != nil { + fmt.Fprintf(os.Stderr, "Error shutting down http server: %s\n", err) + } + }() + wg.Wait() + fmt.Fprintln(w, "Shutting down") + return nil +} + +func main() { + ctx := context.Background() + if err := run(ctx, os.Stdout, os.Args); err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } +} diff --git a/middleware/logging.go b/middleware/logging.go new file mode 100644 index 0000000..ae0e019 --- /dev/null +++ b/middleware/logging.go @@ -0,0 +1,29 @@ +package middleware + +import ( + "log" + "net/http" + "time" +) + +type wrappedWriter struct { + http.ResponseWriter + statusCode int +} + +func (w *wrappedWriter) WriteHeader(statusCode int) { + w.ResponseWriter.WriteHeader(statusCode) + w.statusCode = statusCode +} + +func Logging(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + wrapped := &wrappedWriter{ + ResponseWriter: w, + statusCode: http.StatusOK, + } + next.ServeHTTP(wrapped, r) + log.Println(wrapped.statusCode, r.Method, r.URL.Path, time.Since(start)) + }) +} diff --git a/routes.go b/routes.go new file mode 100644 index 0000000..91bcd10 --- /dev/null +++ b/routes.go @@ -0,0 +1,13 @@ +package main + +import ( + "net/http" + "projectreshoot/handlers" +) + +func addRoutes( + mux *http.ServeMux, + config Config, +) { + mux.Handle("GET /", handlers.HandleRoot()) +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..b170a43 --- /dev/null +++ b/server.go @@ -0,0 +1,24 @@ +package main + +import ( + "net/http" + "projectreshoot/middleware" +) + +type Config struct { + Host string + Port string +} + +func NewServer( + config *Config, +) http.Handler { + mux := http.NewServeMux() + addRoutes( + mux, + *config, + ) + var handler http.Handler = mux + handler = middleware.Logging(handler) + return handler +} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..05b5f18 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,7 @@ + +
+