package app import ( "context" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5/pgxpool" log "github.com/sirupsen/logrus" "merch-api/config" "merch-api/internal/merch" "merch-api/internal/task" "merch-api/internal/user" "merch-api/pkg/authCheck" "merch-api/pkg/authReg" "merch-api/pkg/dbase" "merch-api/pkg/router" "merch-api/pkg/utils" "net" "time" ) const pkgLogHeader string = "Application |" type App struct { cfg config.Config router *router.Router modules []Module dbPool *pgxpool.Pool tasker *task.Handler serviceId int32 } func New(ctx context.Context, cfg config.Config) *App { newApp := &App{ cfg: cfg, } //check if service is registered serviceId, registered := newApp.isRegistered(ctx, cfg) if !registered { log.Fatalf("%v auth registration check failed", pkgLogHeader) } newApp.serviceId = serviceId //providers u := utils.New() dbPool, err := dbase.ConnectPool(ctx, dbase.Deps{ Host: cfg.DBase.Host, Port: cfg.DBase.Port, Username: cfg.DBase.Username, Password: cfg.DBase.Password, DBName: cfg.DBase.DBName, }) if err != nil { log.WithError(err).Fatalf("%v failed to connect database", pkgLogHeader) } newApp.dbPool = dbPool sessionCheckProvider := authCheck.New(authCheck.Deps{ Addr: net.JoinHostPort(cfg.Auth.Host, cfg.Auth.Port), Timeout: cfg.Auth.Timeout, }) //providers with deps userProv := user.New(user.Deps{ DB: dbPool, Utils: u, }) newApp.modules = append(newApp.modules, userProv) newApp.router = router.NewRouter(router.Deps{ Host: cfg.Http.Host, Port: cfg.Http.Port, Prefix: cfg.Http.Prefix, GinMode: cfg.Http.GinMode, UserProvider: userProv, AuthProvider: sessionCheckProvider, ServiceId: serviceId, }) m := merch.New(merch.Deps{ DB: dbPool, Utils: u, }) newApp.modules = append(newApp.modules, m) newApp.tasker = task.New(task.Deps{ Addr: "", MerchProvider: m, }) return newApp } func (app *App) Run(ctx context.Context) error { log.Infof("%v starting...", pkgLogHeader) //getting middlewares for modules routes registration mws := app.router.MWSet() baseGroup := app.router.BaseGroup() app.collectRoutes(baseGroup, mws) errCh := make(chan error, 10) go func() { if err := app.router.Run(); err != nil { errCh <- err } }() go func() { if err := app.tasker.Serve(); err != nil { errCh <- err } }() select { case <-ctx.Done(): app.shutdown(ctx) case err := <-errCh: return err } return nil } func (app *App) shutdown(ctx context.Context) { log.Infof("%v shutting down...", pkgLogHeader) shutdownCtx, shutdownCancel := context.WithTimeout(ctx, 15*time.Second) defer shutdownCancel() app.dbPool.Close() if err := app.router.Shutdown(shutdownCtx); err != nil { log.WithError(err).Warnf("%v error shutting down application", pkgLogHeader) } app.tasker.Shutdown() log.Infof("%v shutdown complete", pkgLogHeader) } func (app *App) collectRoutes(group *gin.RouterGroup, mw *router.Middlewares) { for _, m := range app.modules { m.RegisterRoutes(group, mw) } log.Infof("%v routes registered", pkgLogHeader) } func (app *App) isRegistered(ctx context.Context, cfg config.Config) (int32, bool) { log.Infof("%v checking registration in auth service...", pkgLogHeader) registrar := authReg.New(authReg.Deps{ Addr: net.JoinHostPort(cfg.Auth.Host, cfg.Auth.Port), Timeout: cfg.Auth.Timeout, }) response, err := registrar.AuthenticateOrRegister(ctx, &authReg.RegRequest{ Name: cfg.Auth.Name, Description: cfg.Auth.Description, BaseCode: cfg.Auth.BaseCode, EndCode: cfg.Auth.EndCode, SecretHash: cfg.Auth.SecretHash, Status: cfg.Auth.Status, }) if err != nil { log.WithError(err).Errorf("%v error checking registration in auth service", pkgLogHeader) return 0, false } if response == nil { log.Errorf("%v error checking registration in auth service", pkgLogHeader) return 0, false } if response.AlreadyRegistered == true && response.ServiceId > 0 { log.Infof("%v service registered", pkgLogHeader) return response.ServiceId, true } log.Errorf("%v something went wrong in auth registration check", pkgLogHeader) return 0, false }