diff --git a/fs.go b/fs.go new file mode 100644 index 0000000..93fec55 --- /dev/null +++ b/fs.go @@ -0,0 +1,9 @@ +package main + +import "embed" + +//go:embed static/* +var staticFS embed.FS + +//go:embed tpl/* +var tplFS embed.FS diff --git a/go.mod b/go.mod index 2dac8cc..4c3df9a 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module go.neonxp.dev/pkg -go 1.18 +go 1.22 require github.com/go-chi/chi/v5 v5.0.7 diff --git a/main.go b/main.go index d8e7015..0ba6106 100644 --- a/main.go +++ b/main.go @@ -4,19 +4,16 @@ import ( "context" "encoding/json" "html/template" - "log" + "log/slog" "net/http" "os" "os/signal" - "path/filepath" - "strings" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" + "gitrepo.ru/neonxp/middleware" ) var ( - templates = template.Must(template.ParseGlob("./tpl/*.gohtml")) + templates = template.Must(template.ParseFS(tplFS, "tpl/*.gohtml")) packages = Packages{} ) @@ -32,21 +29,15 @@ func main() { fp, err := os.Open("./config.json") if err != nil { - log.Fatal(err) + panic(err) } if err := json.NewDecoder(fp).Decode(cfg); err != nil { - log.Fatal(err) + panic(err) } - r := chi.NewRouter() + mux := http.NewServeMux() - r.Use(middleware.RequestID) - r.Use(middleware.StripSlashes) - r.Use(middleware.RealIP) - r.Use(middleware.Logger) - r.Use(middleware.Recoverer) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) templates.ExecuteTemplate(w, "index.gohtml", indexRenderContext{ Title: cfg.Title, @@ -56,8 +47,8 @@ func main() { }) }) - r.Get("/{pkg}", func(w http.ResponseWriter, r *http.Request) { - pkgID := chi.URLParam(r, "pkg") + mux.HandleFunc("GET /{pkg}", func(w http.ResponseWriter, r *http.Request) { + pkgID := r.PathValue("pkg") pkg, ok := (*cfg.Packages)[pkgID] if !ok { w.WriteHeader(http.StatusNotFound) @@ -71,42 +62,24 @@ func main() { Doc: "//pkg.go.dev/", }) }) + mux.Handle("GET /static/", http.FileServerFS(staticFS)) - workDir, _ := os.Getwd() - filesDir := http.Dir(filepath.Join(workDir, "static")) - FileServer(r, "/static", filesDir) + logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{})) + h := middleware.Logger(mux, logger) + h = middleware.Recover(h, logger) + h = middleware.RequestID(h) srv := &http.Server{ - Handler: r, + Handler: h, Addr: addr, } go func() { <-ctx.Done() srv.Shutdown(context.Background()) }() - log.Println("Start at", addr) + + logger.Info("server started", slog.String("bind", addr)) if err := srv.ListenAndServe(); err != http.ErrServerClosed { - log.Fatal(err) + panic(err) } } - -// FileServer conveniently sets up a http.FileServer handler to serve -// static files from a http.FileSystem. -func FileServer(r chi.Router, path string, root http.FileSystem) { - if strings.ContainsAny(path, "{}*") { - panic("FileServer does not permit any URL parameters.") - } - - if path != "/" && path[len(path)-1] != '/' { - r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP) - path += "/" - } - path += "*" - - r.Get(path, func(w http.ResponseWriter, r *http.Request) { - rctx := chi.RouteContext(r.Context()) - pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*") - fs := http.StripPrefix(pathPrefix, http.FileServer(root)) - fs.ServeHTTP(w, r) - }) -}