Files
file-upload/main.go
T
2026-08-31 15:19:46 +08:00

75 lines
2.2 KiB
Go

package main
import (
"flag"
"log"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
)
// -----------------------------------------------------------------------------
// 配置 (可被命令行参数覆盖)
// -----------------------------------------------------------------------------
var (
uploadDir = flag.String("dir", "./data/uploads", "上传文件保存目录")
listen = flag.String("listen", ":8080", "HTTP 监听地址")
fileTTL = flag.Duration("ttl", 24*time.Hour, "文件过期 TTL")
scanEvery = flag.Duration("scan", 1*time.Hour, "清理扫描间隔")
auditDir = flag.String("audit-dir", "./data/audit", "审计日志目录 (每天一个 YYYY-MM-DD.log 文件, 空字符串禁用)")
quota = flag.Int64("quota", 10<<30, "总目录配额 (字节, 默认 10GB, 0=不限)")
)
const (
fieldName = "file"
)
// -----------------------------------------------------------------------------
// main
// -----------------------------------------------------------------------------
func main() {
flag.Parse()
startCleaner()
if err := initAudit(); err != nil {
log.Fatalf("init audit: %v", err)
}
initQuota()
r := gin.New()
r.Use(gin.Logger(), gin.Recovery(), auditT0())
// 嵌入式首页 (HTML 骨架, CSS/JS 经 /static 引用)
r.GET("/", func(c *gin.Context) {
c.Data(http.StatusOK, "text/html; charset=utf-8", indexTpl)
})
// 静态资源 (CSS/JS): no-cache 防止二进制升级后浏览器使用旧缓存 JS
r.Use(func(c *gin.Context) {
if strings.HasPrefix(c.Request.URL.Path, "/static") {
c.Header("Cache-Control", "no-cache")
}
c.Next()
})
r.StaticFS("/static", http.FS(staticFS))
// 业务路由
r.POST("/upload", uploadHandler)
r.GET("/download/:filename", downloadHandler)
r.POST("/download-zip", batchDownloadHandler)
r.POST("/files-delete", batchDeleteHandler)
r.DELETE("/files/:filename", deleteHandler)
r.GET("/files", listHandler)
// file-viewer CDN 资源本地缓存代理 (前端文件预览依赖)
r.GET("/file-viewer/*filepath", fileViewerProxy)
log.Printf("server listening on %s, uploads -> %s, ttl=%s", *listen, *uploadDir, *fileTTL)
if err := r.Run(*listen); err != nil {
log.Fatal(err)
}
}