package main import ( "fmt" "log" "net" "net/http" "os" "strings" "time" "github.com/urfave/cli/v2" "golang.org/x/exp/slog" ) func serveLogger(logger *log.Logger, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { remoteHost, _, _ := strings.Cut(r.RemoteAddr, ":") logger.Printf("%v %v %v\n", remoteHost, r.Method, r.URL.Path) next.ServeHTTP(w, r) }) } func timeHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, time.Now().Format("02 Jan 2006 15:04:05 MST")) } func main() { // handler := slog.NewJSONHandler(os.Stdout, nil) handler := slog.NewTextHandler(os.Stdout, nil) slog.SetDefault(slog.New(handler)) logger := slog.NewLogLogger(handler, slog.LevelError) var host string var port string var directory string app := &cli.App{ Name: "snice", Usage: "Serve Static Files", Version: "v0.1.0", DefaultCommand: "", Commands: []*cli.Command{ { Name: "serve", Aliases: []string{"s"}, Usage: "Serve directory", Action: func(cCtx *cli.Context) error { var addr string = host + ":" + port srv := &http.Server{ Addr: addr, ErrorLog: logger, } mux := http.NewServeMux() mux.HandleFunc("/time", timeHandler) fileHandler := serveLogger(logger, http.FileServer(http.Dir(directory))) mux.Handle("/", fileHandler) srv.Handler = mux listener, err := net.Listen("tcp", addr) if err != nil { logger.Println(err) } scheme := "http://" logger.Printf("Serving directory %q on %v%v", directory, scheme, listener.Addr()) err = srv.Serve(listener) if err != nil { logger.Println(err) } return nil }, Flags: []cli.Flag{ &cli.StringFlag{ Name: "directory", Aliases: []string{"dir", "d"}, EnvVars: []string{"DIRECTORY"}, Value: ".", Usage: "Directory to serve", Destination: &directory, }, &cli.StringFlag{ Name: "host", EnvVars: []string{"HOST"}, Value: "127.0.0.1", Usage: "Host to listen on", Destination: &host, }}, }, { Name: "healthcheck", Aliases: []string{"hc"}, Usage: "Call healthcheck endpoint", Action: func(cCtx *cli.Context) error { _, err := http.Get(fmt.Sprintf("http://127.0.0.1:%s/health", port)) if err != nil { os.Exit(1) } return nil }}}, Flags: []cli.Flag{ &cli.BoolFlag{Name: "quiet", Aliases: []string{"q"}}, &cli.StringFlag{ Name: "port", Aliases: []string{"p"}, EnvVars: []string{"PORT"}, Value: "3000", Usage: "Port to serve on", Destination: &port, }, }, EnableBashCompletion: true, Compiled: time.Time{}, Authors: []*cli.Author{}, Reader: nil, Writer: nil, ErrWriter: nil, SliceFlagSeparator: "", DisableSliceFlagSeparator: false, UseShortOptionHandling: true, Suggest: true, AllowExtFlags: false, SkipFlagParsing: false, } if err := app.Run(os.Args); err != nil { log.Fatal(err) } }