package main import ( "context" "flag" "io/fs" "log" "log/slog" "net/http" "os" "os/signal" "path/filepath" "time" "go.neonxp.ru/mux" "go.neonxp.ru/mux/middleware" "golang.org/x/sync/errgroup" ) var ( host string listen string path string htmlPath string ttl time.Duration ) func init() { flag.StringVar(&host, "host", "https://nixshare.ru/", "host of nixshare") flag.StringVar(&listen, "listen", ":8000", "port to listen") flag.StringVar(&htmlPath, "html_path", "./html", "html directory") flag.StringVar(&path, "path", "./storage", "storage directory") flag.DurationVar(&ttl, "ttl", 24*time.Hour, "time to delete uploaded file") } func main() { ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) defer cancel() flag.Parse() r := http.NewServeMux() r.Handle("POST /upload", http.HandlerFunc(uploadHandler)) r.Handle("/", http.FileServer(http.Dir("html"))) r.Handle("/s/", http.StripPrefix("/s/", http.FileServer(http.Dir(path)))) srv := http.Server{ Addr: listen, Handler: mux.Use(r, middleware.Recover(slog.Default()), middleware.RequestID, middleware.Logger(slog.Default()), ), } eg, egCtx := errgroup.WithContext(ctx) eg.Go(func() error { <-egCtx.Done() srv.Close() return nil }) eg.Go(func() error { if err := srv.ListenAndServe(); err != http.ErrServerClosed { return err } return nil }) eg.Go(func() error { timer := time.NewTimer(1 * time.Minute) defer timer.Stop() for { select { case <-timer.C: now := time.Now() err := filepath.Walk(path, func(p string, info fs.FileInfo, err error) error { if info == nil { return nil } if info.IsDir() { return nil } if now.Sub(info.ModTime()).Seconds() > ttl.Seconds() { log.Println("delete old file:", p) if err := os.Remove(p); err != nil { return err } } return nil }) if err != nil { log.Println(err) } case <-egCtx.Done(): return nil } } }) if err := eg.Wait(); err != nil { log.Fatal(err) } }