package main import ( "context" "log" "os" "os/signal" "syscall" "tailly_back_v2/internal/config" "tailly_back_v2/internal/http" "tailly_back_v2/internal/repository" "tailly_back_v2/internal/service" "tailly_back_v2/pkg/auth" "tailly_back_v2/pkg/database" "tailly_back_v2/proto" "time" "google.golang.org/grpc" "google.golang.org/grpc/backoff" "google.golang.org/grpc/keepalive" ) func main() { // Загрузка конфигурации cfg, err := config.Load() if err != nil { log.Fatalf("failed to load config: %v", err) } // Инициализация БД db, err := database.NewPostgres(cfg.Database.DSN) if err != nil { log.Fatalf("failed to connect to database: %v", err) } defer db.Close() // Подключение к MessageService gRPC messageConn, err := grpc.Dial( cfg.GRPC.MessageServiceAddress, grpc.WithInsecure(), grpc.WithKeepaliveParams(keepalive.ClientParameters{ Time: 30 * time.Second, Timeout: 10 * time.Second, PermitWithoutStream: true, }), grpc.WithConnectParams(grpc.ConnectParams{ Backoff: backoff.DefaultConfig, MinConnectTimeout: 5 * time.Second, }), grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`), ) if err != nil { log.Fatalf("failed to connect to messages gRPC service: %v", err) } defer messageConn.Close() messageClient := proto.NewMessageServiceClient(messageConn) // Подключение к SubscribeService gRPC subscribeConn, err := grpc.Dial( cfg.GRPC.SubscribeServiceAddress, // Добавьте этот параметр в конфиг grpc.WithInsecure(), grpc.WithKeepaliveParams(keepalive.ClientParameters{ Time: 30 * time.Second, Timeout: 10 * time.Second, PermitWithoutStream: true, }), grpc.WithConnectParams(grpc.ConnectParams{ Backoff: backoff.DefaultConfig, MinConnectTimeout: 5 * time.Second, }), grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`), ) if err != nil { log.Fatalf("failed to connect to subscribe gRPC service: %v", err) } defer subscribeConn.Close() subscribeClient := proto.NewSubscribeServiceClient(subscribeConn) clipConn, err := grpc.Dial( cfg.GRPC.ClipServiceAddress, // Добавьте этот параметр в конфиг grpc.WithInsecure(), grpc.WithKeepaliveParams(keepalive.ClientParameters{ Time: 30 * time.Second, Timeout: 10 * time.Second, PermitWithoutStream: true, }), grpc.WithConnectParams(grpc.ConnectParams{ Backoff: backoff.DefaultConfig, MinConnectTimeout: 5 * time.Second, }), grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`), ) if err != nil { log.Fatalf("failed to connect to clip gRPC service: %v", err) } defer clipConn.Close() clipClient := proto.NewClipServiceClient(clipConn) // Инициализация зависимостей tokenAuth := auth.NewTokenAuth( cfg.Auth.AccessTokenSecret, cfg.Auth.RefreshTokenSecret, cfg.Auth.AccessTokenExpiry, cfg.Auth.RefreshTokenExpiry, ) // Репозитории userRepo := repository.NewUserRepository(db) postRepo := repository.NewPostRepository(db) commentRepo := repository.NewCommentRepository(db) likeRepo := repository.NewLikeRepository(db) auditRepo := repository.NewAuditRepository(db) recoveryRepo := repository.NewRecoveryRepository(db) deviceRepo := repository.NewDeviceRepository(db) sessionRepo := repository.NewSessionRepository(db) // Инициализация MailService mailService, err := service.NewMailService( cfg.SMTP.From, cfg.SMTP.Host, cfg.SMTP.Port, cfg.SMTP.Username, cfg.SMTP.Password, cfg.SMTP.URL, ) if err != nil { log.Fatalf("Failed to create mail service: %v", err) } // Сервисы authService := service.NewAuthService(userRepo, tokenAuth, mailService) userService := service.NewUserService(userRepo) postService := service.NewPostService(postRepo) commentService := service.NewCommentService(commentRepo, postRepo) likeService := service.NewLikeService(likeRepo, postRepo) auditService := service.NewAuditService(auditRepo) recoveryService := service.NewRecoveryService(recoveryRepo, userRepo, sessionRepo, deviceRepo, mailService) sessionService := service.NewSessionService(sessionRepo, deviceRepo, userRepo, mailService) // Создаем структуру Services services := &service.Services{ Auth: authService, User: userService, Post: postService, Comment: commentService, Like: likeService, Audit: auditService, Recovery: recoveryService, Session: sessionService, Mail: mailService, Messages: messageClient, Subscribe: subscribeClient, Clips: clipClient, } // HTTP сервер server := http.NewServer(cfg, services, tokenAuth, db) // Запуск сервера в отдельной горутине go func() { log.Println("server started") if err := server.Run(); err != nil { log.Printf("server error: %v", err) } }() // Ожидание сигнала завершения quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit // Graceful shutdown ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { log.Printf("server shutdown error: %v", err) } log.Println("server stopped") }