qr-scanner/main.go

106 lines
2.5 KiB
Go

package main
import (
"embed"
"fmt"
"io/fs"
"net"
"net/http"
"os"
"os/exec"
"runtime"
"time"
"github.com/gin-gonic/gin"
"qr-scanner/config"
"qr-scanner/handlers"
"qr-scanner/services"
)
//go:embed static/*
var staticFS embed.FS
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
}
sub, err := fs.Sub(staticFS, "static")
if err != nil {
panic(err)
}
r.GET("/", func(c *gin.Context) { c.Redirect(http.StatusFound, "/static/index.html") })
r.StaticFS("/static", http.FS(sub))
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)
ln, err := net.Listen("tcp", addr)
if err != nil {
panic(err)
}
openURL := fmt.Sprintf("http://%s:%d/", browserHost(cfg.Host), cfg.Port)
_ = openBrowser(openURL)
srv := &http.Server{Handler: r}
if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed {
panic(err)
}
}
func browserHost(listenHost string) string {
if listenHost == "" || listenHost == "0.0.0.0" || listenHost == "::" {
return "localhost"
}
return listenHost
}
func openBrowser(url string) error {
switch runtime.GOOS {
case "windows":
return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
case "darwin":
return exec.Command("open", url).Start()
default:
return exec.Command("xdg-open", url).Start()
}
}