package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "synctv/server/internal/config" "synctv/server/internal/httpapi" "synctv/server/internal/proxy" "synctv/server/internal/room" "synctv/server/internal/store" "synctv/server/internal/ws" ) func main() { cfg, err := config.Load("") if err != nil { log.Fatalf("load config: %v", err) } ctx := context.Background() redisStore := store.NewRedis(cfg.Redis.Addr, cfg.Redis.Password, cfg.Redis.DB, time.Duration(cfg.Room.EmptyTTL)) defer redisStore.Close() if err := redisStore.Ping(ctx); err != nil { log.Fatalf("connect redis: %v", err) } roomService := room.NewService( redisStore, cfg.Room.CodeLength, time.Duration(cfg.Room.EmptyTTL), time.Duration(cfg.Room.OwnerReconnectHold), ) hub := ws.NewHub( roomService, cfg.HTTP.AllowedOrigins, time.Duration(cfg.WebSocket.PingInterval), time.Duration(cfg.WebSocket.PongTimeout), time.Duration(cfg.WebSocket.WriteTimeout), ) streamProxy := proxy.New( roomService, cfg.Proxy.Enabled, time.Duration(cfg.Proxy.RequestTimeout), cfg.Proxy.MaxIdleConns, cfg.Proxy.ResponseHeaderBytes, ) api := httpapi.New(roomService, hub, streamProxy) server := &http.Server{ Addr: cfg.HTTP.Addr, Handler: api.Routes(), ReadHeaderTimeout: 5 * time.Second, } go func() { log.Printf("synctv server listening on %s", cfg.HTTP.Addr) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %v", err) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) <-stop shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := server.Shutdown(shutdownCtx); err != nil { log.Printf("shutdown: %v", err) } }