Files
WarpBox/lib/server/server.go
Daniel Legt a729b641b2 feat(one-time-downloads): add expiry and retry configuration
Introduce new environment variables to control the behavior of one-time download boxes:
- `WARPBOX_ONE_TIME_DOWNLOAD_EXPIRY_SECONDS`: Sets the lifetime of a one-time box after uploads are complete.
- `WARPBOX_ONE_TIME_DOWNLOAD_RETRY_ON_FAILURE`: Determines whether a box remains available if the ZIP creation or transfer fails.

To support these settings, the ZIP delivery process was refactored to use a temporary file. This ensures that a one-time box is only marked as consumed after the file has been successfully transferred to the client, preventing data loss on network interruptions.

Additionally, added a `DecorateFiles` helper in the box store to reduce code duplication.
2026-04-30 04:24:49 +03:00

91 lines
2.3 KiB
Go

package server
import (
"fmt"
"time"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
"warpbox/lib/boxstore"
"warpbox/lib/config"
"warpbox/lib/metastore"
"warpbox/lib/routing"
)
type App struct {
config *config.Config
store *metastore.Store
adminLoginEnabled bool
}
func Run(addr string) error {
cfg, err := config.Load()
if err != nil {
return err
}
if err := cfg.EnsureDirectories(); err != nil {
return err
}
applyBoxstoreRuntimeConfig(cfg)
store, err := metastore.Open(cfg.DBDir)
if err != nil {
return fmt.Errorf("open metadata database: %w", err)
}
defer store.Close()
overrides, err := store.ListSettings()
if err != nil {
return fmt.Errorf("load settings overrides: %w", err)
}
if err := cfg.ApplyOverrides(overrides); err != nil {
return fmt.Errorf("apply settings overrides: %w", err)
}
applyBoxstoreRuntimeConfig(cfg)
bootstrap, err := metastore.BootstrapAdmin(cfg, store)
if err != nil {
return fmt.Errorf("bootstrap admin metadata: %w", err)
}
app := &App{
config: cfg,
store: store,
adminLoginEnabled: bootstrap.AdminLoginEnabled,
}
router := gin.Default()
router.LoadHTMLGlob("templates/*.html")
routing.Register(router, routing.Handlers{
Index: app.handleIndex,
ShowBox: app.handleShowBox,
BoxLogin: handleBoxLogin,
BoxLoginPost: handleBoxLoginPost,
BoxStatus: app.handleBoxStatus,
DownloadBox: app.handleDownloadBox,
DownloadFile: app.handleDownloadFile,
DownloadThumbnail: app.handleDownloadThumbnail,
CreateBox: app.handleCreateBox,
ManifestFileUpload: app.handleManifestFileUpload,
FileStatusUpdate: app.handleFileStatusUpdate,
DirectBoxUpload: app.handleDirectBoxUpload,
LegacyUpload: app.handleLegacyUpload,
})
app.registerAdminRoutes(router)
compressed := router.Group("/", gzip.Gzip(gzip.DefaultCompression))
compressed.Static("/static", "./static")
boxstore.StartThumbnailWorker(cfg.ThumbnailBatchSize, time.Duration(cfg.ThumbnailIntervalSeconds)*time.Second)
return router.Run(addr)
}
func applyBoxstoreRuntimeConfig(cfg *config.Config) {
boxstore.SetUploadRoot(cfg.UploadsDir)
boxstore.SetOneTimeDownloadExpiry(cfg.OneTimeDownloadExpirySeconds)
}