// Command server is the Amnezia VPN Share Panel HTTP application entrypoint. package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/joho/godotenv" "amnezia-share/internal/config" "amnezia-share/internal/web" _ "amnezia-share/internal/web/handlers" ) func main() { _ = godotenv.Load() cfg := config.Load() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) app, err := web.New(ctx, cfg) cancel() if err != nil { log.Fatalf("не удалось запустить приложение: %v", err) } defer app.Close() srv := &http.Server{ Addr: ":" + cfg.Port, Handler: app.Handler(), ReadHeaderTimeout: 15 * time.Second, ReadTimeout: 2 * time.Minute, WriteTimeout: 3 * time.Minute, IdleTimeout: 90 * time.Second, } go func() { log.Printf("amnezia-share слушает на порту %s (base url: %q)", cfg.Port, cfg.BaseURL) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("сервер остановлен с ошибкой: %v", err) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) <-stop log.Println("получен сигнал остановки, завершаем работу...") shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 15*time.Second) defer shutdownCancel() if err := srv.Shutdown(shutdownCtx); err != nil { log.Printf("ошибка при остановке сервера: %v", err) } log.Println("сервер остановлен.") }