Add file duration

This commit is contained in:
Nils O. Selåsdal
2026-07-04 19:30:25 +02:00
parent fd205fb8fe
commit e0531098d8
+113 -1
View File
@@ -3,9 +3,11 @@ package main
import (
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"html/template"
"io"
"io/fs"
"log"
"mime"
"net/http"
@@ -27,6 +29,17 @@ func main() {
if uploadDir == "" {
uploadDir = "/uploads"
}
var fileExpires time.Duration = 7 * 24 * time.Hour
dryRun := strings.ToLower(os.Getenv("DRYRUN_CLEAN")) != "false"
fileDuration := os.Getenv("FILE_DURATION")
if fileDuration != "" {
expires, err := time.ParseDuration(fileDuration)
if err != nil {
log.Fatalf("FILE_DURATION %s is invalid: %v", fileDuration, err)
}
fileExpires = expires
}
port := os.Getenv("PORT")
if port == "" {
@@ -40,6 +53,13 @@ func main() {
http.HandleFunc("/", handleRequest)
log.Printf("Starting server on port %s, upload directory: %s", port, uploadDir)
log.Printf("Files expires after: %v (DRYRUN_CLEAN=%v)", fileExpires, dryRun)
if fileExpires != 0 {
go cleanupProcedure(fileExpires, dryRun)
} else {
log.Print("Cleaning old files is disabled")
}
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatalf("Server failed: %v", err)
}
@@ -261,7 +281,7 @@ func getHost(r *http.Request) string {
// Check standard Forwarded header (RFC 7239)
if forwarded := r.Header.Get("Forwarded"); forwarded != "" {
// Parse "Forwarded: for=...; host=example.com; proto=https"
// Parse "Forwarded: for=...; host=example.com; proto=https"
parts := strings.SplitSeq(forwarded, ";")
for part := range parts {
part = strings.TrimSpace(part)
@@ -325,3 +345,95 @@ func serveFrontpage(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
indexHTML.Execute(w, pageData)
}
// Cleanup
func isDirEmpty(name string) (bool, error) {
f, err := os.Open(name)
if err != nil {
return false, err
}
defer f.Close()
// Read exactly one entry.
_, err = f.ReadDir(1)
if errors.Is(err, io.EOF) {
// EOF means there are no entries, so the directory is empty.
return true, nil
}
// If err is nil, an entry was found (not empty).
// If err is something else, a real error occurred.
return false, err
}
func cleanupProcedure(duration time.Duration, dryRun bool) {
var oldFiles []string
var emptyDirs []string
deleteIfTooOld := func(path string, d fs.DirEntry, err error) error {
if err != nil {
return nil
}
if d.IsDir() {
return nil
}
info, err := d.Info()
if err != nil {
log.Printf("Error cleaning file '%s' : %v", d.Name(), err)
return nil
}
age := time.Since(info.ModTime())
if age >= duration {
oldFiles = append(oldFiles, path)
}
return nil
}
findEmptyDirs := func(path string, d fs.DirEntry, err error) error {
if !d.IsDir() {
return nil
}
empty, err := isDirEmpty(path)
if empty {
emptyDirs = append(emptyDirs, path)
} else if err != nil {
log.Printf("Error cleaning directory '%s' : %v", path, err)
}
return nil
}
for {
filepath.WalkDir(uploadDir, deleteIfTooOld)
for _, file := range oldFiles {
if !dryRun {
err := os.Remove(file)
if err != nil {
log.Printf("Failed to remove expired file '%s' : %v", file, err)
} else {
log.Printf("Removed expired file '%s'", file)
}
} else {
log.Printf("Dry run: Would remove expired file '%s'", file)
}
}
filepath.WalkDir(uploadDir, findEmptyDirs)
for _, file := range emptyDirs {
if !dryRun {
err := os.Remove(file)
if err != nil {
log.Printf("Failed to remove empty folder '%s' : %v", file, err)
} else {
log.Printf("Removed empty folder '%s'", file)
}
} else {
log.Printf("Dry run: Would remove empty folder '%s'", file)
}
}
time.Sleep(6 * time.Hour)
}
}