// Code scaffolded by goctl. Safe to edit. // goctl 1.10.1 package svc import ( "context" "gateway/internal/config" redislib "gateway/internal/library/redis" "gateway/internal/library/validate" domrepo "gateway/internal/model/member/domain/repository" dommember "gateway/internal/model/member/domain/usecase" memberusecase "gateway/internal/model/member/usecase" domnotif "gateway/internal/model/notification/domain/usecase" notifusecase "gateway/internal/model/notification/usecase" "gateway/internal/worker/notification_retry" ) type ServiceContext struct { Config config.Config Validator validate.Validate // Redis is the process-wide client (one pool per Addr); nil when Redis.Host is empty. Redis *redislib.Client // Notifier is nil when Mongo is not configured (local scaffold without DB). Notifier domnotif.NotifierUseCase // NotificationAdmin is nil when Mongo is not configured. NotificationAdmin domnotif.AdminNotifierUseCase // NotificationRetry runs async delivery when Mongo + Redis are configured. NotificationRetry *notification_retry.Runner // MemberOTP is the atomic OTP usecase (Generate / Verify / Invalidate). // nil when Redis is not configured. Logic layer composes it with the // Notifier + Profile flips; usecases MUST NOT call other usecases. MemberOTP dommember.OTPUseCase // MemberTOTP is the atomic TOTP usecase; nil when Member.TOTP.SecretKEK // is unset or Redis is missing. MemberTOTP dommember.TOTPUseCase // MemberVerifyRate exposes resend-cooldown / daily-cap helpers for the // logic layer. MemberVerifyRate domrepo.VerifyRateStore // MemberProfile flips BusinessEmail/Phone verified flags; consumed by // the logic layer after a successful OTP confirmation. MemberProfile domrepo.ProfileRepository } func NewServiceContext(c config.Config) *ServiceContext { v, err := validate.NewWithDefaultEN() if err != nil { panic(err) } rds, err := redislib.NewClient(c.Redis) if err != nil { panic(err) } sc := &ServiceContext{ Config: c, Validator: v, Redis: rds, } if c.Mongo.Host != "" { mod, err := notifusecase.NewModuleFromParam(notifusecase.FactoryParam{ MongoConf: &c.Mongo, Redis: rds, Config: c.Notification, }) if err != nil { panic(err) } sc.Notifier = mod.Notifier sc.NotificationAdmin = mod.Admin sc.NotificationRetry = notification_retry.NewRunner(mod.RetryWorker) } if rds != nil && rds.Zero() != nil { memberMod, err := memberusecase.NewModuleFromParam(memberusecase.ModuleParam{ Redis: rds, Config: c.Member, }) if err != nil { panic(err) } sc.MemberOTP = memberMod.OTP sc.MemberTOTP = memberMod.TOTP sc.MemberVerifyRate = memberMod.VerifyRate sc.MemberProfile = memberMod.Profile } return sc } // StartWorkers launches background workers (notification retry, etc.). func (sc *ServiceContext) StartWorkers(ctx context.Context) { if sc.NotificationRetry != nil { sc.NotificationRetry.Start(ctx) } } // StopWorkers waits for background workers to shut down. func (sc *ServiceContext) StopWorkers() { if sc.NotificationRetry != nil { sc.NotificationRetry.Stop() } }