106 lines
2.5 KiB
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()
|
|
}
|
|
}
|