package app import ( "amocrm/internal/controllers" "amocrm/internal/initialize" "amocrm/internal/repository" "amocrm/internal/server/http" "amocrm/internal/service" "amocrm/internal/workers/tokens" amoClient2 "amocrm/pkg/amoClient" "amocrm/pkg/closer" pena_social_auth "amocrm/pkg/pena-social-auth" "context" "errors" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils" "time" "go.uber.org/zap" ) func Run(ctx context.Context, config initialize.Config, logger *zap.Logger) error { defer func() { if r := recover(); r != nil { logger.Error("Recovered from a panic", zap.Any("error", r)) } }() logger.Info("App started", zap.Any("config", config)) ctx, cancel := context.WithCancel(ctx) defer cancel() shutdownGroup := closer.NewCloserGroup() mdb, err := initialize.MongoDB(ctx, config) if err != nil { logger.Error("failed initialize mongo") return err } encrypt := utils.NewEncrypt(config.PubKey, config.PrivKey) socialAithClient := pena_social_auth.NewClient(pena_social_auth.Deps{ PenaSocialAuthURL: config.PenaSocialAuthURL, Logger: logger, ReturnURL: config.ReturnURL, }) rateLimiter := amoClient2.NewRateLimiter(ctx, 6, 1500*time.Millisecond) amoClient := amoClient2.NewAmoClient(amoClient2.AmoDeps{ BaseApiURL: config.ApiURL, UserInfoURL: config.UserInfoURL, Logger: logger, RedirectionURL: config.ReturnURL, IntegrationID: config.IntegrationID, IntegrationSecret: config.IntegrationSecret, RateLimiter: rateLimiter, }) repo := repository.NewRepository(repository.Deps{ MdbUser: mdb.Collection("amoUsers"), Tokens: mdb.Collection("tokens"), Logger: logger, }) svc := service.NewService(service.Deps{ Repository: repo, Logger: logger, SocialAuthClient: socialAithClient, AmoClient: amoClient, Encrypt: encrypt, }) controller := controllers.NewController(controllers.Deps{ Service: svc, Logger: logger, }) tokenUpdater := tokens.NewRefreshWC(tokens.Deps{ Repo: repo, AmoClient: amoClient, Logger: logger, }) go tokenUpdater.Start(ctx) server := http.NewServer(http.ServerConfig{ Controllers: []http.Controller{ controller, }, }) go func() { if err := server.Start(config.HTTPHost + ":" + config.HTTPPort); err != nil { logger.Error("Server startup error", zap.Error(err)) cancel() } }() server.ListRoutes() shutdownGroup.Add(closer.CloserFunc(server.Shutdown)) shutdownGroup.Add(closer.CloserFunc(mdb.Client().Disconnect)) shutdownGroup.Add(closer.CloserFunc(rateLimiter.Stop)) shutdownGroup.Add(closer.CloserFunc(tokenUpdater.Stop)) <-ctx.Done() timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 10*time.Second) defer timeoutCancel() if err := shutdownGroup.Call(timeoutCtx); err != nil { if errors.Is(err, context.DeadlineExceeded) { logger.Error("Shutdown timed out", zap.Error(err)) } else { logger.Error("Failed to shutdown services gracefully", zap.Error(err)) } return err } logger.Info("Application has stopped") return nil }