package main import ( "fmt" "os" "time" "github.com/gin-gonic/gin" "qr-scanner/config" "qr-scanner/handlers" "qr-scanner/services" ) func main() { cfg := config.Default().WithEnv() if err := os.MkdirAll(cfg.TempDir, 0o755); err != nil { panic(err) } store := services.NewTaskStore() scanner := services.NewScanner(store, time.Duration(cfg.DebugDelayMS)*time.Millisecond) exporter := services.NewExporter() uploadHandler := handlers.NewUploadHandler(cfg, store) scanHandler := handlers.NewScanHandler(cfg, store, scanner) progressHandler := handlers.NewProgressHandler(store) resultsHandler := handlers.NewResultsHandler(store) exportHandler := handlers.NewExportHandler(store, exporter) cancelHandler := handlers.NewCancelHandler(store) r := gin.Default() if cfg.MaxUploadMB > 0 { r.MaxMultipartMemory = cfg.MaxUploadMB * 1024 * 1024 } r.GET("/", func(c *gin.Context) { c.File("./static/index.html") }) r.Static("/static", "./static") api := r.Group("/api") { api.POST("/upload", uploadHandler.HandleUpload) api.POST("/scan", scanHandler.StartScan) api.GET("/progress/:taskID", progressHandler.GetProgress) api.GET("/progress/:taskID/stream", progressHandler.StreamProgress) api.GET("/results/:taskID", resultsHandler.GetResults) api.GET("/export/:taskID", exportHandler.Download) api.POST("/cancel/:taskID", cancelHandler.Cancel) } go func() { retention := time.Duration(cfg.RetentionMinutes) * time.Minute ticker := time.NewTicker(time.Minute) defer ticker.Stop() for range ticker.C { store.Cleanup(retention) } }() addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) if err := r.Run(addr); err != nil { panic(err) } }