2024-08-28 13:47:44 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"flag"
|
|
|
|
"io/fs"
|
|
|
|
"log"
|
2024-08-28 15:22:01 +03:00
|
|
|
"log/slog"
|
2024-08-28 13:47:44 +03:00
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
|
2024-08-28 15:22:01 +03:00
|
|
|
"go.neonxp.ru/mux"
|
|
|
|
"go.neonxp.ru/mux/middleware"
|
2024-08-28 13:47:44 +03:00
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2024-08-28 15:22:01 +03:00
|
|
|
host string
|
|
|
|
listen string
|
|
|
|
path string
|
|
|
|
htmlPath string
|
|
|
|
ttl time.Duration
|
2024-08-28 13:47:44 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
flag.StringVar(&host, "host", "https://nixshare.ru/", "host of nixshare")
|
|
|
|
flag.StringVar(&listen, "listen", ":8000", "port to listen")
|
2024-08-28 15:22:01 +03:00
|
|
|
flag.StringVar(&htmlPath, "html_path", "./html", "html directory")
|
2024-08-28 13:47:44 +03:00
|
|
|
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))
|
2024-08-28 15:22:01 +03:00
|
|
|
r.Handle("/", http.FileServer(http.Dir("html")))
|
|
|
|
r.Handle("/s/", http.StripPrefix("/s/", http.FileServer(http.Dir(path))))
|
2024-08-28 13:47:44 +03:00
|
|
|
|
|
|
|
srv := http.Server{
|
2024-08-28 15:22:01 +03:00
|
|
|
Addr: listen,
|
|
|
|
Handler: mux.Use(r,
|
|
|
|
middleware.Recover(slog.Default()),
|
|
|
|
middleware.RequestID,
|
|
|
|
middleware.Logger(slog.Default()),
|
|
|
|
),
|
2024-08-28 13:47:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|