Files
stream.api/internal/service/service_core.go
2026-04-02 11:01:30 +00:00

217 lines
7.1 KiB
Go

package service
import (
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"gorm.io/gorm"
"stream.api/internal/adapters/redis"
appv1 "stream.api/internal/api/proto/app/v1"
"stream.api/internal/config"
"stream.api/internal/database/model"
"stream.api/internal/middleware"
"stream.api/internal/repository"
"stream.api/pkg/logger"
"stream.api/pkg/storage"
)
const adTemplateUpgradeRequiredMessage = "Upgrade required to manage Ads & VAST"
const defaultGoogleUserInfoURL = "https://www.googleapis.com/oauth2/v2/userinfo"
const (
playerConfigFreePlanLimitMessage = "Free plan supports only 1 player config"
playerConfigFreePlanReconciliationMessage = "Delete extra player configs to continue managing player configs on the free plan"
)
const (
walletTransactionTypeTopup = "topup"
walletTransactionTypeSubscriptionDebit = "subscription_debit"
walletTransactionTypeReferralReward = "referral_reward"
paymentMethodWallet = "wallet"
paymentMethodTopup = "topup"
paymentKindSubscription = "subscription"
paymentKindWalletTopup = "wallet_topup"
defaultReferralRewardBps = int32(500)
)
var allowedTermMonths = map[int32]struct{}{
1: {},
3: {},
6: {},
12: {},
}
type Services struct {
appv1.AuthServer
appv1.AccountServer
appv1.NotificationsServer
appv1.DomainsServer
appv1.AdTemplatesServer
appv1.PopupAdsServer
appv1.PlayerConfigsServer
appv1.PlansServer
appv1.PaymentsServer
appv1.VideosServer
appv1.VideoMetadataServer
appv1.AdminServer
}
type authAppService struct{ *appServices }
type accountAppService struct{ *appServices }
type notificationsAppService struct{ *appServices }
type domainsAppService struct{ *appServices }
type adTemplatesAppService struct{ *appServices }
type popupAdsAppService struct{ *appServices }
type playerConfigsAppService struct{ *appServices }
type plansAppService struct{ *appServices }
type paymentsAppService struct{ *appServices }
type videosAppService struct{ *appServices }
type adminAppService struct{ *appServices }
type appServices struct {
appv1.UnimplementedAuthServer
appv1.UnimplementedAccountServer
appv1.UnimplementedNotificationsServer
appv1.UnimplementedDomainsServer
appv1.UnimplementedAdTemplatesServer
appv1.UnimplementedPopupAdsServer
appv1.UnimplementedPlayerConfigsServer
appv1.UnimplementedPlansServer
appv1.UnimplementedPaymentsServer
appv1.UnimplementedVideosServer
appv1.UnimplementedVideoMetadataServer
appv1.UnimplementedAdminServer
db *gorm.DB
logger logger.Logger
authenticator *middleware.Authenticator
cache *redis.RedisAdapter
storageProvider storage.Provider
videoWorkflowService VideoWorkflow
videoRepository VideoRepository
userRepository UserRepository
preferenceRepository UserPreferenceRepository
billingRepository BillingRepository
planRepository PlanRepository
paymentRepository PaymentRepository
accountRepository AccountRepository
notificationRepo NotificationRepository
notificationEvents NotificationEventPublisher
domainRepository DomainRepository
adTemplateRepository AdTemplateRepository
popupAdRepository PopupAdRepository
playerConfigRepo PlayerConfigRepository
agentRuntime AgentRuntime
googleOauth *oauth2.Config
googleStateTTL time.Duration
googleUserInfoURL string
jobRepository JobRepository
}
type paymentInvoiceDetails struct {
PlanName string
TermMonths *int32
PaymentMethod string
ExpiresAt *time.Time
WalletAmount float64
TopupAmount float64
}
type paymentExecutionInput struct {
UserID string
Plan *model.Plan
TermMonths int32
PaymentMethod string
TopupAmount *float64
}
type paymentExecutionResult struct {
Payment *model.Payment
Subscription *model.PlanSubscription
WalletBalance float64
InvoiceID string
}
type referralRewardResult struct {
Granted bool
Amount float64
}
type apiErrorBody struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
}
func NewServices(c *redis.RedisAdapter, db *gorm.DB, l logger.Logger, cfg *config.Config, videoWorkflowService VideoWorkflow, agentRuntime AgentRuntime, notificationEvents NotificationEventPublisher) *Services {
var storageProvider storage.Provider
if cfg != nil {
provider, err := storage.NewS3Provider(cfg)
if err != nil {
l.Error("Failed to initialize S3 provider for gRPC app services", "error", err)
} else {
storageProvider = provider
}
}
googleStateTTL := 10 * time.Minute
googleOauth := &oauth2.Config{}
if cfg != nil {
if cfg.Google.StateTTLMinute > 0 {
googleStateTTL = time.Duration(cfg.Google.StateTTLMinute) * time.Minute
}
googleOauth = &oauth2.Config{
ClientID: cfg.Google.ClientID,
ClientSecret: cfg.Google.ClientSecret,
RedirectURL: cfg.Google.RedirectURL,
Scopes: []string{
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
},
Endpoint: google.Endpoint,
}
}
service := &appServices{
db: db,
logger: l,
authenticator: middleware.NewAuthenticator(db, l, cfg.Internal.Marker, notificationEvents),
cache: c,
storageProvider: storageProvider,
videoWorkflowService: videoWorkflowService,
videoRepository: repository.NewVideoRepository(db),
userRepository: repository.NewUserRepository(db),
preferenceRepository: repository.NewUserPreferenceRepository(db),
billingRepository: repository.NewBillingRepository(db),
planRepository: repository.NewPlanRepository(db),
paymentRepository: repository.NewPaymentRepository(db),
accountRepository: repository.NewAccountRepository(db),
notificationRepo: repository.NewNotificationRepository(db),
notificationEvents: notificationEvents,
domainRepository: repository.NewDomainRepository(db),
adTemplateRepository: repository.NewAdTemplateRepository(db),
popupAdRepository: repository.NewPopupAdRepository(db),
playerConfigRepo: repository.NewPlayerConfigRepository(db),
jobRepository: repository.NewJobRepository(db),
agentRuntime: agentRuntime,
googleOauth: googleOauth,
googleStateTTL: googleStateTTL,
googleUserInfoURL: defaultGoogleUserInfoURL,
}
return &Services{
AuthServer: &authAppService{appServices: service},
AccountServer: &accountAppService{appServices: service},
NotificationsServer: &notificationsAppService{appServices: service},
DomainsServer: &domainsAppService{appServices: service},
AdTemplatesServer: &adTemplatesAppService{appServices: service},
PopupAdsServer: &popupAdsAppService{appServices: service},
PlayerConfigsServer: &playerConfigsAppService{appServices: service},
PlansServer: &plansAppService{appServices: service},
PaymentsServer: &paymentsAppService{appServices: service},
VideosServer: &videosAppService{appServices: service},
VideoMetadataServer: &videosAppService{appServices: service},
AdminServer: &adminAppService{appServices: service},
}
}