150 lines
4.4 KiB
Go
150 lines
4.4 KiB
Go
package svc
|
||
|
||
import (
|
||
"strings"
|
||
|
||
"apps/backend/internal/config"
|
||
"apps/backend/internal/middleware"
|
||
fsDomain "apps/backend/internal/module/filestorage/domain"
|
||
"apps/backend/internal/module/filestorage/noop"
|
||
"apps/backend/internal/module/filestorage/s3store"
|
||
memberDomain "apps/backend/internal/module/member/domain"
|
||
memberRepo "apps/backend/internal/module/member/repository"
|
||
memberUC "apps/backend/internal/module/member/usecase"
|
||
notifDomain "apps/backend/internal/module/notification/domain"
|
||
notifUC "apps/backend/internal/module/notification/usecase"
|
||
tokenUC "apps/backend/internal/module/token/usecase"
|
||
|
||
"github.com/zeromicro/go-zero/core/logx"
|
||
"github.com/zeromicro/go-zero/rest"
|
||
)
|
||
|
||
// ServiceContext wires goctl middleware + modules.
|
||
//
|
||
// 持久化(關機不丟):
|
||
// - members / settings / refresh_tokens / auth_codes → Mongo
|
||
// Redis(可丟、可重建):
|
||
// - monc 實體快取 only(CacheRedis)
|
||
type ServiceContext struct {
|
||
Config config.Config
|
||
AuthJWT rest.Middleware
|
||
AdminAuth rest.Middleware
|
||
Members memberDomain.Repository
|
||
Auth *memberUC.AuthService
|
||
Token *tokenUC.JWTIssuer
|
||
Notification notifDomain.UseCase
|
||
Storage fsDomain.Storage
|
||
}
|
||
|
||
func NewServiceContext(c config.Config) *ServiceContext {
|
||
if len(c.CacheRedis) == 0 {
|
||
logx.Must(errString("CacheRedis is required for monc entity cache"))
|
||
}
|
||
|
||
repo := memberRepo.NewMoncStore(c.Mongo.URI, c.Mongo.Database, c.CacheRedis)
|
||
logx.Infof("mongo monc ready db=%s redis_cache=%s", c.Mongo.Database, c.CacheRedis[0].Host)
|
||
|
||
issuer := tokenUC.NewJWTIssuer(
|
||
c.Auth.AccessSecret,
|
||
c.Auth.RefreshSecret,
|
||
c.Auth.AccessExpire,
|
||
c.Auth.RefreshExpire,
|
||
)
|
||
cost := c.Bcrypt.Cost
|
||
if cost <= 0 {
|
||
cost = 10
|
||
}
|
||
auth := memberUC.NewAccountService(repo, issuer, cost)
|
||
auth.GoogleClientID = c.OAuth.GoogleClientID
|
||
auth.LineClientID = c.OAuth.LineClientID
|
||
auth.LineClientSecret = c.OAuth.LineClientSecret
|
||
auth.LineRedirectURI = c.OAuth.LineRedirectURI
|
||
|
||
notify := newNotification(c)
|
||
store := newStorage(c)
|
||
|
||
return &ServiceContext{
|
||
Config: c,
|
||
Members: repo,
|
||
Auth: auth,
|
||
Token: issuer,
|
||
Notification: notify,
|
||
Storage: store,
|
||
AuthJWT: middleware.NewAuthJWTMiddleware(issuer, repo).Handle,
|
||
AdminAuth: middleware.NewAdminAuthMiddleware().Handle,
|
||
}
|
||
}
|
||
|
||
// newStorage 只接 MinIO/S3(S3 API);不落本機磁碟。
|
||
func newStorage(c config.Config) fsDomain.Storage {
|
||
os := c.ObjectStorage
|
||
if strings.TrimSpace(os.Endpoint) == "" {
|
||
logx.Error("object storage: Endpoint empty — uploads disabled (MinIO/S3 required)")
|
||
return noop.New()
|
||
}
|
||
s, err := s3store.New(s3store.Config{
|
||
Endpoint: os.Endpoint,
|
||
Region: os.Region,
|
||
Bucket: os.Bucket,
|
||
AccessKey: os.AccessKey,
|
||
SecretKey: os.SecretKey,
|
||
UsePathStyle: os.UsePathStyle,
|
||
PublicBaseURL: os.PublicBaseURL,
|
||
})
|
||
if err != nil {
|
||
logx.Errorf("object storage MinIO/S3 init failed: %v — uploads disabled", err)
|
||
return noop.New()
|
||
}
|
||
logx.Infof("object storage: minio/s3 endpoint=%s bucket=%s", os.Endpoint, os.Bucket)
|
||
return s
|
||
}
|
||
|
||
func newNotification(c config.Config) notifDomain.UseCase {
|
||
base := strings.TrimRight(c.PublicWebBase, "/")
|
||
if base == "" {
|
||
base = "http://127.0.0.1:5173"
|
||
}
|
||
brand := notifDomain.Brand{
|
||
Name: c.Brand.Name,
|
||
Link: base,
|
||
LogoURL: c.Brand.LogoURL,
|
||
Copyright: c.Brand.Copyright,
|
||
}
|
||
if brand.Name == "" {
|
||
brand.Name = "Harbor Desk"
|
||
}
|
||
if brand.LogoURL == "" {
|
||
// apps/web/public/brand-mark.jpg — 郵件客戶端需絕對 URL
|
||
brand.LogoURL = base + "/brand-mark.jpg"
|
||
}
|
||
if brand.Copyright == "" {
|
||
brand.Copyright = "© Harbor Desk"
|
||
}
|
||
|
||
cfg := notifUC.Config{
|
||
Sender: c.Mail.Sender,
|
||
DevExposeCode: c.Mail.DevExposeCode,
|
||
Brand: brand,
|
||
}
|
||
if c.Mail.SMTP.Host != "" {
|
||
cfg.Providers = []notifDomain.EmailDelivery{
|
||
notifUC.NewSMTPDelivery(notifUC.SMTPConfig{
|
||
Host: c.Mail.SMTP.Host,
|
||
Port: c.Mail.SMTP.Port,
|
||
User: c.Mail.SMTP.User,
|
||
Password: c.Mail.SMTP.Password,
|
||
}),
|
||
}
|
||
logx.Infof("notification mail: smtp host=%s port=%d logo=%s expose_code=%v",
|
||
c.Mail.SMTP.Host, c.Mail.SMTP.Port, brand.LogoURL, c.Mail.DevExposeCode)
|
||
} else {
|
||
cfg.Providers = []notifDomain.EmailDelivery{notifUC.NewLogDelivery()}
|
||
logx.Info("notification mail: log-only (set Mail.SMTP.Host to send real email)")
|
||
}
|
||
return notifUC.NewService(cfg)
|
||
}
|
||
|
||
type errString string
|
||
|
||
func (e errString) Error() string { return string(e) }
|