127 lines
3.9 KiB
Go
127 lines
3.9 KiB
Go
package app
|
||
|
||
import (
|
||
"context"
|
||
"log/slog"
|
||
|
||
"github.com/go-redis/redis/v8"
|
||
"gorm.io/gorm"
|
||
|
||
"pay-bridge/internal/repository"
|
||
"pay-bridge/internal/service"
|
||
"pay-bridge/pkg/config"
|
||
"pay-bridge/pkg/sequence"
|
||
)
|
||
|
||
// App 应用容器,持有所有初始化完成的 service 实例
|
||
type App struct {
|
||
Cfg *config.Config
|
||
|
||
// 对外暴露供 router 使用的 service
|
||
AdminAuthSvc *service.AdminAuthService
|
||
AppSvc *service.AppService
|
||
TradeSvc *service.TradeService
|
||
RefundSvc *service.RefundService
|
||
NotifySvc *service.NotifyService
|
||
MatchSvc *service.PaymentMatchService
|
||
MerchantSvc *service.MerchantService
|
||
ReconSvc *service.ReconciliationService
|
||
ChannelSvc *service.ChannelService
|
||
|
||
// 内部资源
|
||
db *gorm.DB
|
||
rdb *redis.Client
|
||
}
|
||
|
||
// New 初始化所有基础设施和 service,返回就绪的 App 实例
|
||
func New(cfg *config.Config) (*App, error) {
|
||
a := &App{Cfg: cfg}
|
||
|
||
if err := a.initInfra(); err != nil {
|
||
return nil, err
|
||
}
|
||
a.initServices()
|
||
return a, nil
|
||
}
|
||
|
||
// Start 启动后台任务(notify poller 等)
|
||
func (a *App) Start(ctx context.Context) {
|
||
a.NotifySvc.StartPoller(ctx, a.Cfg.Notify.PollerInterval, a.Cfg.Notify.PollerBatch)
|
||
}
|
||
|
||
// Shutdown 优雅关闭:关闭 DB 和 Redis 连接
|
||
func (a *App) Shutdown(ctx context.Context) {
|
||
if a.rdb != nil {
|
||
if err := a.rdb.Close(); err != nil {
|
||
slog.Error("redis close error", "err", err)
|
||
}
|
||
}
|
||
if a.db != nil {
|
||
sqlDB, err := a.db.DB()
|
||
if err == nil {
|
||
if err := sqlDB.Close(); err != nil {
|
||
slog.Error("db close error", "err", err)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// initInfra 初始化 DB 和 Redis
|
||
func (a *App) initInfra() error {
|
||
db, err := config.NewDB(a.Cfg.Database)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
a.db = db
|
||
|
||
rdb, err := config.NewRedis(a.Cfg.Redis)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
a.rdb = rdb
|
||
return nil
|
||
}
|
||
|
||
// initServices 按依赖顺序构建 repo → service
|
||
func (a *App) initServices() {
|
||
encKey := a.Cfg.Security.FieldEncryptKey
|
||
|
||
// Repositories
|
||
adminUserRepo := repository.NewAdminUserRepository(a.db)
|
||
appRepo := repository.NewAppRepository(a.db)
|
||
tradeRepo := repository.NewTradeOrderRepository(a.db)
|
||
refundRepo := repository.NewRefundOrderRepository(a.db)
|
||
notifyRepo := repository.NewNotifyLogRepository(a.db)
|
||
channelCfgRepo := repository.NewChannelConfigRepository(a.db)
|
||
seqRepo := repository.NewSequenceRepository(a.db)
|
||
profitSharingRepo := repository.NewProfitSharingRepository(a.db)
|
||
serviceFeeRepo := repository.NewServiceFeeRepository(a.db)
|
||
matchRepo := repository.NewPaymentMatchRepository(a.db)
|
||
merchantRepo := repository.NewMerchantRepository(a.db)
|
||
wechatRepo := repository.NewWechatRepository(a.db)
|
||
reconRepo := repository.NewReconciliationRepository(a.db)
|
||
|
||
// JWT expire hours
|
||
jwtExpireHours := a.Cfg.JWT.ExpireHours
|
||
if jwtExpireHours == 0 {
|
||
jwtExpireHours = 24
|
||
}
|
||
|
||
// Services
|
||
a.AdminAuthSvc = service.NewAdminAuthService(adminUserRepo, a.Cfg.JWT.Secret, jwtExpireHours)
|
||
a.ChannelSvc = service.NewChannelService(channelCfgRepo, encKey, a.Cfg.Channels)
|
||
seqSvc := sequence.NewService(seqRepo)
|
||
a.AppSvc = service.NewAppService(appRepo, encKey)
|
||
a.NotifySvc = service.NewNotifyService(notifyRepo, tradeRepo, a.Cfg.Notify.HTTPTimeout)
|
||
a.MerchantSvc = service.NewMerchantService(merchantRepo, a.ChannelSvc)
|
||
a.TradeSvc = service.NewTradeService(tradeRepo, a.ChannelSvc, seqSvc, a.rdb, a.NotifySvc, a.MerchantSvc)
|
||
a.RefundSvc = service.NewRefundService(refundRepo, tradeRepo, a.ChannelSvc, seqSvc, a.NotifySvc)
|
||
a.MatchSvc = service.NewPaymentMatchService(matchRepo, tradeRepo, a.NotifySvc, a.TradeSvc)
|
||
a.ReconSvc = service.NewReconciliationService(reconRepo, tradeRepo, a.ChannelSvc, appRepo)
|
||
|
||
// 以下 service 目前未直接暴露给 router,但已初始化供将来扩展使用
|
||
_ = service.NewProfitSharingService(profitSharingRepo, tradeRepo, a.ChannelSvc, seqSvc, a.rdb)
|
||
_ = service.NewServiceFeeService(serviceFeeRepo, tradeRepo, a.ChannelSvc)
|
||
_ = service.NewWechatService(wechatRepo, encKey)
|
||
}
|