haixunMaster/haixun-backend/internal/svc/service_context.go

195 lines
6.2 KiB
Go
Raw Normal View History

2026-06-23 09:54:27 +00:00
package svc
import (
"context"
"fmt"
"os"
"time"
"haixun-backend/internal/config"
libmongo "haixun-backend/internal/library/mongo"
libredis "haixun-backend/internal/library/redis"
"haixun-backend/internal/library/validate"
"haixun-backend/internal/middleware"
aisettings "haixun-backend/internal/model/ai/usecase"
authrepodomain "haixun-backend/internal/model/auth/domain/repository"
authdomain "haixun-backend/internal/model/auth/domain/usecase"
authrepo "haixun-backend/internal/model/auth/repository"
authuc "haixun-backend/internal/model/auth/usecase"
jobrepo "haixun-backend/internal/model/job/repository"
jobusecase "haixun-backend/internal/model/job/usecase"
memberdomain "haixun-backend/internal/model/member/domain/usecase"
memberrepo "haixun-backend/internal/model/member/repository"
memberuc "haixun-backend/internal/model/member/usecase"
permissiondomain "haixun-backend/internal/model/permission/domain/usecase"
permissionrepo "haixun-backend/internal/model/permission/repository"
permissionuc "haixun-backend/internal/model/permission/usecase"
settingrepo "haixun-backend/internal/model/setting/repository"
settingusecase "haixun-backend/internal/model/setting/usecase"
jobworker "haixun-backend/internal/worker/job"
goredis "github.com/redis/go-redis/v9"
"github.com/zeromicro/go-zero/rest"
)
type ServiceContext struct {
Config config.Config
Validator *validate.Validate
Mongo *libmongo.Client
Redis *goredis.Client
Setting settingusecase.UseCase
AI aisettings.UseCase
Job jobusecase.UseCase
AuthToken authdomain.TokenUseCase
Member memberdomain.UseCase
Permission permissiondomain.UseCase
// Middlewares mounted per route group via generate/api `middleware:` directive.
AuthJWT rest.Middleware
MemberAuth rest.Middleware
stopWorker context.CancelFunc
stopScheduler context.CancelFunc
stopReaper context.CancelFunc
}
func NewServiceContext(c config.Config) *ServiceContext {
ctx := context.Background()
mongoClient, err := libmongo.NewClient(ctx, c.Mongo)
if err != nil {
panic(err)
}
redisClient := libredis.NewClient(c.Redis)
settingRepository := settingrepo.NewMongoRepository(mongoClient.Database())
if err := settingRepository.EnsureIndexes(ctx); err != nil {
panic(err)
}
settingUseCase := settingusecase.NewUseCase(settingRepository)
var tokenRevokeStore authrepodomain.TokenRevokeStore
if redisClient != nil {
tokenRevokeStore = authrepo.NewRedisTokenRevokeStore(redisClient)
}
authTokenUseCase := authuc.NewTokenUseCase(c.Auth, tokenRevokeStore)
memberRepository := memberrepo.NewMongoRepository(mongoClient.Database())
if err := memberRepository.EnsureIndexes(ctx); err != nil {
panic(err)
}
memberUseCase := memberuc.NewUseCase(memberRepository, authTokenUseCase)
permissionRepository := permissionrepo.NewMongoPermissionRepository(mongoClient.Database())
rolePermissionRepository := permissionrepo.NewMongoRolePermissionRepository(mongoClient.Database())
if err := permissionRepository.EnsureIndexes(ctx); err != nil {
panic(err)
}
if err := rolePermissionRepository.EnsureIndexes(ctx); err != nil {
panic(err)
}
permissionUseCase := permissionuc.NewUseCase(permissionRepository, rolePermissionRepository)
if err := permissionUseCase.EnsureDefaultPermissions(ctx); err != nil {
panic(err)
}
jobTemplateRepository := jobrepo.NewMongoTemplateRepository(mongoClient.Database())
jobRunRepository := jobrepo.NewMongoRunRepository(mongoClient.Database())
jobScheduleRepository := jobrepo.NewMongoScheduleRepository(mongoClient.Database())
jobEventRepository := jobrepo.NewMongoEventRepository(mongoClient.Database())
jobQueueRepository := jobrepo.NewRedisQueueRepository(redisClient)
if err := jobTemplateRepository.EnsureIndexes(ctx); err != nil {
panic(err)
}
if err := jobRunRepository.EnsureIndexes(ctx); err != nil {
panic(err)
}
if err := jobScheduleRepository.EnsureIndexes(ctx); err != nil {
panic(err)
}
if err := jobEventRepository.EnsureIndexes(ctx); err != nil {
panic(err)
}
jobUseCase := jobusecase.NewUseCase(jobTemplateRepository, jobRunRepository, jobScheduleRepository, jobEventRepository, jobQueueRepository)
if err := jobUseCase.EnsureDemoTemplate(ctx); err != nil {
panic(err)
}
sc := &ServiceContext{
Config: c,
Validator: validate.New(),
Mongo: mongoClient,
Redis: redisClient,
Setting: settingUseCase,
AI: aisettings.NewUseCase(),
Job: jobUseCase,
AuthToken: authTokenUseCase,
Member: memberUseCase,
Permission: permissionUseCase,
}
hostname, _ := os.Hostname()
if c.JobWorker.Enabled && redisClient != nil {
workerType := c.JobWorker.WorkerType
if workerType == "" {
workerType = "go"
}
workerID := c.JobWorker.WorkerID
if workerID == "" {
workerID = fmt.Sprintf("%s-%s-worker", hostname, workerType)
}
workerCtx, cancel := context.WithCancel(context.Background())
sc.stopWorker = cancel
runner := jobworker.NewRunner(workerID, workerType, jobUseCase)
go runner.Start(workerCtx)
}
if c.JobScheduler.Enabled && redisClient != nil {
schedulerHolder := fmt.Sprintf("%s-scheduler", hostname)
interval := time.Duration(c.JobScheduler.IntervalSeconds) * time.Second
if interval <= 0 {
interval = time.Minute
}
schedulerCtx, cancel := context.WithCancel(context.Background())
sc.stopScheduler = cancel
scheduler := jobworker.NewScheduler(schedulerHolder, jobUseCase)
go scheduler.Start(schedulerCtx, interval)
}
if c.JobReaper.Enabled && redisClient != nil {
interval := time.Duration(c.JobReaper.IntervalSeconds) * time.Second
if interval <= 0 {
interval = 30 * time.Second
}
reaperCtx, cancel := context.WithCancel(context.Background())
sc.stopReaper = cancel
reaper := jobworker.NewReaper(jobUseCase)
go reaper.Start(reaperCtx, interval)
}
sc.AuthJWT = middleware.NewAuthJWTMiddleware(sc.AuthToken, sc.Config.Auth).Handle
sc.MemberAuth = middleware.NewMemberAuthMiddleware(sc.AuthToken, sc.Config.Auth).Handle
return sc
}
func (sc *ServiceContext) Close(ctx context.Context) {
if sc == nil {
return
}
if sc.stopWorker != nil {
sc.stopWorker()
}
if sc.stopScheduler != nil {
sc.stopScheduler()
}
if sc.stopReaper != nil {
sc.stopReaper()
}
_ = sc.Mongo.Close(ctx)
if sc.Redis != nil {
_ = sc.Redis.Close()
}
}