template-monorepo/internal/svc/service_context.go

105 lines
3.1 KiB
Go

// 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()
}
}