126 lines
3.0 KiB
Go
126 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"git.kirlllll.ru/volontery/backend/internal/api"
|
|
"git.kirlllll.ru/volontery/backend/internal/config"
|
|
"git.kirlllll.ru/volontery/backend/internal/pkg/jwt"
|
|
"git.kirlllll.ru/volontery/backend/internal/repository"
|
|
"git.kirlllll.ru/volontery/backend/internal/service"
|
|
)
|
|
|
|
func main() {
|
|
if err := run(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func run() error {
|
|
// Загрузка конфигурации
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load config: %w", err)
|
|
}
|
|
|
|
log.Printf("Starting server in %s mode", cfg.AppEnv)
|
|
|
|
// Подключение к базе данных
|
|
ctx := context.Background()
|
|
pool, err := config.NewDBPool(ctx, cfg.DatabaseURL)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to connect to database: %w", err)
|
|
}
|
|
defer pool.Close()
|
|
|
|
log.Println("Connected to database")
|
|
|
|
// Инициализация репозиториев
|
|
repos := repository.New(pool)
|
|
|
|
// Инициализация JWT менеджера
|
|
jwtManager := jwt.NewManager(
|
|
cfg.JWTSecret,
|
|
cfg.JWTAccessTokenTTL,
|
|
cfg.JWTRefreshTokenTTL,
|
|
)
|
|
|
|
// Инициализация сервисов
|
|
authService := service.NewAuthService(
|
|
repos.User,
|
|
repos.Auth,
|
|
repos.RBAC,
|
|
jwtManager,
|
|
)
|
|
|
|
userService := service.NewUserService(
|
|
repos.User,
|
|
repos.RBAC,
|
|
)
|
|
|
|
requestService := service.NewRequestService(
|
|
repos.Request,
|
|
)
|
|
|
|
// Создание HTTP сервера
|
|
server := api.NewServer(
|
|
cfg,
|
|
authService,
|
|
userService,
|
|
requestService,
|
|
jwtManager,
|
|
)
|
|
|
|
// Настройка HTTP сервера
|
|
addr := fmt.Sprintf("%s:%s", cfg.ServerHost, cfg.ServerPort)
|
|
httpServer := &http.Server{
|
|
Addr: addr,
|
|
Handler: server,
|
|
ReadTimeout: 15 * time.Second,
|
|
WriteTimeout: 15 * time.Second,
|
|
IdleTimeout: 60 * time.Second,
|
|
}
|
|
|
|
// Канал для обработки ошибок сервера
|
|
serverErrors := make(chan error, 1)
|
|
|
|
// Запуск HTTP сервера в горутине
|
|
go func() {
|
|
log.Printf("Server listening on %s", addr)
|
|
serverErrors <- httpServer.ListenAndServe()
|
|
}()
|
|
|
|
// Канал для обработки сигналов завершения
|
|
shutdown := make(chan os.Signal, 1)
|
|
signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)
|
|
|
|
// Блокируемся до получения сигнала завершения или ошибки сервера
|
|
select {
|
|
case err := <-serverErrors:
|
|
return fmt.Errorf("server error: %w", err)
|
|
|
|
case sig := <-shutdown:
|
|
log.Printf("Received signal %v, starting graceful shutdown", sig)
|
|
|
|
// Даем 30 секунд на завершение активных запросов
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
if err := httpServer.Shutdown(ctx); err != nil {
|
|
httpServer.Close()
|
|
return fmt.Errorf("failed to gracefully shutdown server: %w", err)
|
|
}
|
|
|
|
log.Println("Server stopped gracefully")
|
|
}
|
|
|
|
return nil
|
|
}
|