2025-07-10 01:18:05 +07:00

93 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package server
import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"time"
"golang.org/x/net/http2"
"yobble-gateway-go/internal/config"
"yobble-gateway-go/internal/logger"
"yobble-gateway-go/internal/middleware"
"yobble-gateway-go/internal/proxy"
"yobble-gateway-go/pkg/geoip"
)
// Server обертка для http.Server с дополнительными полями.
type Server struct {
httpServer *http.Server
log *slog.Logger
}
// NewServer создает новый экземпляр Server.
func NewServer(cfg *config.Settings, geoIPService *geoip.GeoIPService) *Server {
op := "server.NewServer"
log := logger.NewLoggerWithOp(op)
// Create the main proxy handler
proxyHandler := proxy.NewProxyHandler(cfg, geoIPService)
// Apply middleware chain
chain := middleware.RemoveTrailingSlashMiddleware(
middleware.RealIPMiddleware(
proxyHandler,
),
)
addr := fmt.Sprintf("%s:%s", cfg.Server.Host, cfg.Server.Port)
httpServer := &http.Server{
Addr: addr,
Handler: chain, // Use the chained middleware as the main handler
// TODO: Add ReadHeaderTimeout, ReadTimeout, WriteTimeout, IdleTimeout from config
}
// Explicitly enable HTTP/2
http2.ConfigureServer(httpServer, nil)
return &Server{
httpServer: httpServer,
log: log,
}
}
// Start запускает HTTP/HTTPS сервер в отдельной горутине.
// Он возвращает канал, который будет закрыт, когда сервер завершит работу.
func (s *Server) Start(fullchain, privkey string) <-chan error {
errChan := make(chan error, 1)
s.log.Info("server starting with TLS and HTTP/2", slog.String("address", s.httpServer.Addr))
go func() {
defer close(errChan)
if err := s.httpServer.ListenAndServeTLS(fullchain, privkey); err != nil && !errors.Is(err, http.ErrServerClosed) {
s.log.Error("server failed to listen and serve", slog.Any("error", err))
errChan <- err
}
s.log.Info("server stopped listening")
}()
return errChan
}
// Shutdown gracefully shuts down the server.
func (s *Server) Shutdown(ctx context.Context) error {
s.log.Info("server is shutting down gracefully")
// Give the server a grace period to finish active connections
shutdownCtx, cancel := context.WithTimeout(ctx, 30*time.Second) // TODO: Make timeout configurable
defer cancel()
if err := s.httpServer.Shutdown(shutdownCtx); err != nil {
s.log.Error("server shutdown failed", slog.Any("error", err))
return err
}
s.log.Info("server shutdown complete")
return nil
}