package server import ( "encoding/json" "html/template" "path/filepath" "time" "github.com/gin-contrib/gzip" "github.com/gin-gonic/gin" "warpbox/lib/boxstore" "warpbox/lib/config" "warpbox/lib/routing" ) type App struct { config *config.Config settingsOverridesPath string } func Run(addr string) error { cfg, err := config.Load() if err != nil { return err } if err := cfg.EnsureDirectories(); err != nil { return err } overridesPath := filepath.Join(cfg.DBDir, config.AdminSettingsOverrideFilename) overrides, err := config.ReadAdminSettingsOverrides(overridesPath) if err != nil { return err } if err := cfg.ApplyOverrides(overrides); err != nil { return err } applyBoxstoreRuntimeConfig(cfg) app := &App{config: cfg, settingsOverridesPath: overridesPath} router := gin.Default() htmlTemplates, err := loadHTMLTemplates() if err != nil { return err } router.SetHTMLTemplate(htmlTemplates) 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, AdminLogin: app.handleAdminLogin, AdminLoginPost: app.handleAdminLoginPost, AdminLogout: app.handleAdminLogout, AdminDashboard: app.handleAdminDashboard, AdminAlerts: app.handleAdminAlerts, AdminBoxes: app.handleAdminBoxes, AdminBoxesAction: app.handleAdminBoxesAction, AdminSettings: app.handleAdminSettings, AdminSettingsExport: app.handleAdminSettingsExport, AdminSettingsSave: app.handleAdminSettingsSave, AdminSettingsImport: app.handleAdminSettingsImport, AdminSettingsReset: app.handleAdminSettingsReset, AdminAuth: app.adminAuthMiddleware, }) 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 loadHTMLTemplates() (*template.Template, error) { tmpl := template.New("").Funcs(template.FuncMap{ "toJSON": func(value any) template.JS { data, err := json.Marshal(value) if err != nil { return template.JS("null") } return template.JS(data) }, }) for _, pattern := range []string{ "templates/*.html", "templates/admin/*.html", "templates/admin/partials/*.html", } { var err error tmpl, err = tmpl.ParseGlob(pattern) if err != nil { return nil, err } } return tmpl, nil } func applyBoxstoreRuntimeConfig(cfg *config.Config) { boxstore.SetUploadRoot(cfg.UploadsDir) boxstore.SetOneTimeDownloadExpiry(cfg.OneTimeDownloadExpirySeconds) }