package main import ( "dwelling-upload/internal/http" "dwelling-upload/pkg/utils" "dwelling-upload/pkg/watcher" "dwelling-upload/web" "flag" "fmt" "log" nethttp "net/http" "net/netip" "os" "os/signal" "path" "strings" "syscall" "git.arav.su/Arav/httpr" ) var ( listenAddress *string = flag.String("listen", "/var/run/dwelling-upload/sock", "listen address (ip:port|unix_path)") uploadDir *string = flag.String("upload-dir", "/srv/upload", "directory where uploaded files are stored") keepForHours *int = flag.Int("keep-for", 36, "keep files for this much hours") storageSize *int64 = flag.Int64("storage", 102400, "storage size in MiB for uploads") fileSizeLimit *int64 = flag.Int64("file-size", 128, "max. size in MiB for files") showVersion *bool = flag.Bool("v", false, "show version") ) var version string func main() { flag.Parse() log.SetFlags(log.Llongfile) if *showVersion { fmt.Println("dwelling-upload Ver. ", version, "\nCopyright (c) 2022,2023 Alexander \"Arav\" Andreev ") return } var network string if !strings.ContainsRune(*listenAddress, ':') { network = "unix" defer os.Remove(*listenAddress) } else { ap, err := netip.ParseAddrPort(*listenAddress) if err != nil { log.Fatalln(err) } if ap.Addr().Is4() { network = "tcp4" } else { network = "tcp6" } } watcha, err := watcher.NewInotifyWatcher() if err != nil { log.Fatalln(err) } defer watcha.Close() if err := watcha.AddWatch(*uploadDir, watcher.CrDelMask); err != nil { log.Fatalln(err) } uploadDirNotify := make(chan uint32) go watcha.WatchForMask(uploadDirNotify, watcher.CrDelMask) hashSalt, err := os.ReadFile(path.Join(os.Getenv("CREDENTIALS_DIRECTORY"), "salt")) if err != nil { log.Fatalln("failed to read hash salt file:", err) } logFilePath := path.Join(os.Getenv("LOGS_DIRECTORY"), "file.log") logFileFd, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) if err != nil { log.Fatalln("failed to open file.log:", err) } defer logFileFd.Close() logFile := log.New(logFileFd, "", log.LstdFlags) uploadDirSize, err := utils.DirectorySize(*uploadDir) if err != nil { log.Fatalf("failed to get initial size of %s: %s", *uploadDir, err) } hand := http.NewUploadHandlers(logFile, *uploadDir, &uploadDirSize, string(hashSalt), *keepForHours, *storageSize, *fileSizeLimit) r := httpr.New() r.NotFoundHandler = func(w nethttp.ResponseWriter, r *nethttp.Request) { http.Error(w, r, nethttp.StatusNotFound, "") } r.Handler(nethttp.MethodGet, "/", hand.Index) r.Handler(nethttp.MethodPost, "/", hand.Upload) r.Handler(nethttp.MethodGet, "/:hash/:name", hand.Download) r.Handler(nethttp.MethodPost, "/delete", hand.Delete) r.Handler(nethttp.MethodDelete, "/:hash", hand.Delete) r.ServeStatic("/assets/*filepath", web.Assets()) r.Handler(nethttp.MethodGet, "/robots.txt", http.RobotsTxt) r.Handler(nethttp.MethodGet, "/favicon.svg", http.Favicon) srv := http.NewHttpServer(r) defer func() { if err := srv.Stop(); err != nil { log.Fatalln("failed to properly shutdown a server:", err) } }() if err := srv.Start(network, *listenAddress); err != nil { log.Fatalln("failed to start a server:", err) } doneSignal := make(chan os.Signal, 1) signal.Notify(doneSignal, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) go func() { for { select { case <-uploadDirNotify: uploadDirSize, err = utils.DirectorySize(*uploadDir) if err != nil { log.Println("failed to get uploads directory size:", err) } } } }() <-doneSignal }