package app import ( "time" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "gorm.io/gorm" "stream.api/internal/config" "stream.api/internal/database/model" appv1 "stream.api/internal/gen/proto/app/v1" "stream.api/internal/middleware" "stream.api/internal/video" "stream.api/pkg/cache" "stream.api/pkg/logger" "stream.api/pkg/storage" "stream.api/pkg/token" ) 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 { AuthServiceServer AccountServiceServer PreferencesServiceServer UsageServiceServer NotificationsServiceServer DomainsServiceServer AdTemplatesServiceServer PlayerConfigsServiceServer PlansServiceServer PaymentsServiceServer VideosServiceServer AdminServiceServer } type appServices struct { appv1.UnimplementedAuthServiceServer appv1.UnimplementedAccountServiceServer appv1.UnimplementedPreferencesServiceServer appv1.UnimplementedUsageServiceServer appv1.UnimplementedNotificationsServiceServer appv1.UnimplementedDomainsServiceServer appv1.UnimplementedAdTemplatesServiceServer appv1.UnimplementedPlayerConfigsServiceServer appv1.UnimplementedPlansServiceServer appv1.UnimplementedPaymentsServiceServer appv1.UnimplementedVideosServiceServer appv1.UnimplementedAdminServiceServer db *gorm.DB logger logger.Logger authenticator *middleware.Authenticator tokenProvider token.Provider cache cache.Cache storageProvider storage.Provider videoService *video.Service agentRuntime video.AgentRuntime googleOauth *oauth2.Config googleStateTTL time.Duration googleUserInfoURL string frontendBaseURL string } 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 cache.Cache, t token.Provider, db *gorm.DB, l logger.Logger, cfg *config.Config, videoService *video.Service, agentRuntime video.AgentRuntime) *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, } } frontendBaseURL := "" if cfg != nil { frontendBaseURL = cfg.Frontend.BaseURL } service := &appServices{ db: db, logger: l, authenticator: middleware.NewAuthenticator(db, l, cfg.Internal.Marker), tokenProvider: t, cache: c, storageProvider: storageProvider, videoService: videoService, agentRuntime: agentRuntime, googleOauth: googleOauth, googleStateTTL: googleStateTTL, googleUserInfoURL: defaultGoogleUserInfoURL, frontendBaseURL: frontendBaseURL, } return &Services{ AuthServiceServer: service, AccountServiceServer: service, PreferencesServiceServer: service, UsageServiceServer: service, NotificationsServiceServer: service, DomainsServiceServer: service, AdTemplatesServiceServer: service, PlayerConfigsServiceServer: service, PlansServiceServer: service, PaymentsServiceServer: service, VideosServiceServer: service, AdminServiceServer: service, } } type AuthServiceServer interface { appv1.AuthServiceServer } type AccountServiceServer interface { appv1.AccountServiceServer } type PreferencesServiceServer interface { appv1.PreferencesServiceServer } type UsageServiceServer interface { appv1.UsageServiceServer } type NotificationsServiceServer interface { appv1.NotificationsServiceServer } type DomainsServiceServer interface { appv1.DomainsServiceServer } type AdTemplatesServiceServer interface { appv1.AdTemplatesServiceServer } type PlayerConfigsServiceServer interface { appv1.PlayerConfigsServiceServer } type PlansServiceServer interface { appv1.PlansServiceServer } type PaymentsServiceServer interface { appv1.PaymentsServiceServer } type VideosServiceServer interface { appv1.VideosServiceServer } type AdminServiceServer interface { appv1.AdminServiceServer }