Files
RenewCMS/api/dependecyInjection.go
T

502 lines
27 KiB
Go

package api
import (
domainAPIKey "RenewCMS/internal/domain/apikey"
domainArticle "RenewCMS/internal/domain/article"
domainAudit "RenewCMS/internal/domain/audit"
domainAuthor "RenewCMS/internal/domain/author"
domainImage "RenewCMS/internal/domain/image"
domainInvite "RenewCMS/internal/domain/invite"
domainMail "RenewCMS/internal/domain/mail"
domainPurge "RenewCMS/internal/domain/purge"
domainSite "RenewCMS/internal/domain/site"
domainUpdate "RenewCMS/internal/domain/update"
domainUser "RenewCMS/internal/domain/user"
"RenewCMS/internal/infrastructure/auditing"
"RenewCMS/internal/infrastructure/config"
"RenewCMS/internal/infrastructure/hashing"
"RenewCMS/internal/infrastructure/imaging"
"RenewCMS/internal/infrastructure/mailer"
"RenewCMS/internal/infrastructure/markdown"
"RenewCMS/internal/infrastructure/persistence/database"
persistence "RenewCMS/internal/infrastructure/persistence/repositories"
"RenewCMS/internal/infrastructure/scheduler"
"RenewCMS/internal/infrastructure/storage"
"RenewCMS/internal/infrastructure/update"
"RenewCMS/internal/infrastructure/usage"
"RenewCMS/internal/infrastructure/useCases"
"context"
"crypto/ed25519"
"log"
"net/http"
"os"
"path/filepath"
"runtime"
"sync"
"time"
"github.com/go-chi/jwtauth/v5"
)
type UseCases struct {
apiKeyAuthOnce sync.Once
apiKeyAuthMiddleware func(http.Handler) http.Handler
Token *jwtauth.JWTAuth
PurgeScheduler *scheduler.Runner
ActivityCleanupScheduler *scheduler.Runner
CreateArticleUseCase *useCases.CreateArticleUseCase
GetArticleUseCase *useCases.GetArticleUseCase
ListArticlesUseCase *useCases.ListArticlesUseCase
UpdateArticleUseCase *useCases.UpdateArticleUseCase
ResolveArticleSEOUseCase *useCases.ResolveArticleSEOUseCase
CheckArticleSEOUseCase *useCases.CheckArticleSEOUseCase
ListSitemapUseCase *useCases.ListSitemapUseCase
DeleteArticleUseCase *useCases.DeleteArticleUseCase
ListAuthorsUseCase *useCases.ListAuthorsUseCase
CreateAuthorUseCase *useCases.CreateAuthorUseCase
CreateMyAuthorUseCase *useCases.CreateMyAuthorUseCase
UpdateAuthorUseCase *useCases.UpdateAuthorUseCase
DeleteAuthorUseCase *useCases.DeleteAuthorUseCase
GetMyAuthorUseCase *useCases.GetMyAuthorUseCase
ListSitesUseCase *useCases.ListSitesUseCase
CreateSiteUseCase *useCases.CreateSiteUseCase
UpdateSiteUseCase *useCases.UpdateSiteUseCase
SetDefaultSiteUseCase *useCases.SetDefaultSiteUseCase
DeleteSiteUseCase *useCases.DeleteSiteUseCase
GetUserUseCase *useCases.GetUserUseCase
CreateUserUseCase *useCases.CreateUserUseCase
AuthenticateUserUseCase *useCases.AuthenticateUserUseCase
VerifyUserUseCase *useCases.VerifyUserUseCase
CancelRegistrationUseCase *useCases.CancelRegistrationUseCase
RequestPasswordResetUseCase *useCases.RequestPasswordResetUseCase
ResetPasswordUseCase *useCases.ResetPasswordUseCase
UpdateUserProfileUseCase *useCases.UpdateUserProfileUseCase
ListUsersUseCase *useCases.ListUsersUseCase
CreateInviteUseCase *useCases.CreateInviteUseCase
CancelInviteUseCase *useCases.CancelInviteUseCase
RenewInviteUseCase *useCases.RenewInviteUseCase
ListUsersAndInvitesUseCase *useCases.ListUsersAndInvitesUseCase
GetInviteUseCase *useCases.GetInviteUseCase
AcceptInviteUseCase *useCases.AcceptInviteUseCase
SendMailUseCase *useCases.SendMailUseCase
CreateImageUseCase *useCases.CreateImageUseCase
OpenMediaUseCase *useCases.OpenMediaUseCase
ListMediaUseCase *useCases.ListMediaUseCase
RenameMediaUseCase *useCases.RenameMediaUseCase
DeleteMediaUseCase *useCases.DeleteMediaUseCase
MergeMediaUseCase *useCases.MergeMediaUseCase
GetMediaUsageUseCase *useCases.GetMediaUsageUseCase
GetPurgeSettingsUseCase *useCases.GetPurgeSettingsUseCase
UpdatePurgeSettingsUseCase *useCases.UpdatePurgeSettingsUseCase
PreviewPurgeUseCase *useCases.PreviewPurgeUseCase
RunPurgeUseCase *useCases.RunPurgeUseCase
GetSettingsUseCase *useCases.GetSettingsUseCase
GetUpdateStatusUseCase *useCases.GetUpdateStatusUseCase
CheckForUpdateUseCase *useCases.CheckForUpdateUseCase
StartUpdateDownloadUseCase *useCases.StartUpdateDownloadUseCase
RequestRestartUseCase *useCases.RequestRestartUseCase
RecordRunningInfoUseCase *useCases.RecordRunningInfoUseCase
CreateAPIKeyUseCase *useCases.CreateAPIKeyUseCase
ListAPIKeysUseCase *useCases.ListAPIKeysUseCase
RevokeAPIKeyUseCase *useCases.RevokeAPIKeyUseCase
AuthenticateAPIKeyUseCase *useCases.AuthenticateAPIKeyUseCase
ListActivityUseCase *useCases.ListActivityUseCase
GetActivitySummaryUseCase *useCases.GetActivitySummaryUseCase
ExportActivityUseCase *useCases.ExportActivityUseCase
GetActivityRetentionUseCase *useCases.GetActivityRetentionUseCase
UpdateActivityRetentionUseCase *useCases.UpdateActivityRetentionUseCase
ListVariantsUseCase *useCases.ListVariantsUseCase
CreateVariantUseCase *useCases.CreateVariantUseCase
UpdateVariantUseCase *useCases.UpdateVariantUseCase
SetVariantEnabledUseCase *useCases.SetVariantEnabledUseCase
DeleteVariantUseCase *useCases.DeleteVariantUseCase
PurgeVariantUseCase *useCases.PurgeVariantUseCase
ServeVariantUseCase *useCases.ServeVariantUseCase
ListImageVariantsUseCase *useCases.ListImageVariantsUseCase
GenerateImageVariantUseCase *useCases.GenerateImageVariantUseCase
GenerateAllImageVariantsUseCase *useCases.GenerateAllImageVariantsUseCase
PurgeImageVariantUseCase *useCases.PurgeImageVariantUseCase
GenerateVariantsOnUploadUseCase *useCases.GenerateVariantsOnUploadUseCase
GetVariantCacheStatsUseCase *useCases.GetVariantCacheStatsUseCase
PurgeVariantCacheUseCase *useCases.PurgeVariantCacheUseCase
VariantUsageTracker *usage.Tracker
}
func (c *UseCases) RunSchedulers(ctx context.Context) {
var running sync.WaitGroup
for _, runner := range []*scheduler.Runner{c.PurgeScheduler, c.ActivityCleanupScheduler} {
if runner == nil {
continue
}
running.Add(1)
go func() {
defer running.Done()
runner.Run(ctx)
}()
}
running.Wait()
}
type Repositories struct {
ArticleRepo domainArticle.Repository
SiteRepo domainSite.Repository
AuthorRepo domainAuthor.Repository
UserRepo domainUser.Repository
ImageRepo domainImage.Repository
VariantRepo domainImage.VariantRepository
VariantFileRepo domainImage.VariantFileRepository
VariantCacheRepo domainImage.VariantCacheRepository
VariantUsageRepo domainImage.VariantUsageRepository
VariantRenderer domainImage.VariantRenderer
InviteRepo domainInvite.Repository
APIKeyRepo domainAPIKey.Repository
PurgeSettingsRepo domainPurge.Repository
AuditRepo domainAudit.Repository
AuditSettingsRepo domainAudit.SettingsRepository
MailRepo domainMail.Repository
ReleaseFeed domainUpdate.ReleaseFeed
UpdateStore domainUpdate.StatusStore
UpdateJobs domainUpdate.JobStore
UpdateHelper domainUpdate.HelperDetector
AssetFetcher domainUpdate.AssetFetcher
SignatureVerifier domainUpdate.SignatureVerifier
StagedRunner domainUpdate.StagedBinaryRunner
DatabaseBackup domainUpdate.DatabaseBackup
UpdateResults domainUpdate.ResultStore
RestartRequests domainUpdate.RestartRequestStore
RunningInfo domainUpdate.RunningInfoStore
}
const (
updateStatusFileName = "update-status.json"
updateJobFileName = "update-job.json"
updateHelperFileName = "update-helper.json"
updatesDirName = "updates"
backupsDirName = "backups"
)
func imageStorageConfig(settings config.Settings) storage.Config {
if settings.Storage.Driver == config.StorageDriverS3 {
s3 := settings.Storage.S3
return storage.Config{
Driver: storage.DriverS3,
S3: storage.S3Config{
Bucket: s3.Bucket,
Region: s3.Region,
Endpoint: s3.Endpoint,
AccessKeyID: s3.AccessKeyID,
SecretAccessKey: s3.SecretAccessKey,
KeyPrefix: s3.KeyPrefix,
PathStyle: s3.PathStyle,
TLS: s3.TLS,
},
}
}
return storage.Config{Driver: storage.DriverLocal, Location: settings.UploadDir}
}
func openImageStorage(settings config.Settings) domainImage.Storage {
imageStorage, err := storage.Open(imageStorageConfig(settings))
if err != nil {
panic("Unable to open the image storage: " + err.Error())
}
return imageStorage
}
func databaseConfig(settings config.Settings) database.Config {
switch settings.Database.Driver {
case config.DatabaseDriverMySQL:
return mysqlDatabaseConfig(settings.Database)
case config.DatabaseDriverPostgres:
return postgresDatabaseConfig(settings.Database)
case "", config.DatabaseDriverSQLite:
return database.Config{Driver: database.DriverSQLite, Source: settings.DBFile}
default:
return database.Config{Driver: settings.Database.Driver}
}
}
func mysqlDatabaseConfig(settings config.DatabaseSettings) database.Config {
return database.Config{
Driver: database.DriverMySQL,
Source: database.MySQLDSN(database.MySQLConfig{
Host: settings.Host,
Port: settings.Port,
User: settings.User,
Password: settings.Password,
Name: settings.Name,
TLS: settings.TLS,
}),
Pool: &database.PoolSettings{
MaxOpenConns: settings.MaxOpenConns,
MaxIdleConns: settings.MaxIdleConns,
ConnMaxLifetime: settings.ConnMaxLifetime,
},
}
}
func postgresDatabaseConfig(settings config.DatabaseSettings) database.Config {
return database.Config{
Driver: database.DriverPostgres,
Source: database.PostgresDSN(database.PostgresConfig{
Host: settings.Host,
Port: settings.Port,
User: settings.User,
Password: settings.Password,
Name: settings.Name,
SSLMode: settings.SSLMode,
}),
Pool: &database.PoolSettings{
MaxOpenConns: settings.MaxOpenConns,
MaxIdleConns: settings.MaxIdleConns,
ConnMaxLifetime: settings.ConnMaxLifetime,
},
}
}
func openDatabase(settings config.Settings) *database.Connection {
connection, err := database.Connect(databaseConfig(settings))
if err != nil {
panic("Unable to open the database: " + err.Error())
}
if err := database.Migrate(connection.DB, settings.PublicURL); err != nil {
panic("Failed to migrate database: " + err.Error())
}
return connection
}
func releasePublicKey() ed25519.PublicKey {
key, err := update.EmbeddedPublicKey()
if err != nil {
panic("Unable to read the embedded release key: " + err.Error())
}
return key
}
func getRepositories(connection *database.Connection, settings config.Settings) *Repositories {
db := connection.DB
dataDir := settings.DataDir()
variantFiles := persistence.NewVariantFileRepository(db)
return &Repositories{
ArticleRepo: persistence.NewArticleRepository(db),
SiteRepo: persistence.NewSiteRepository(db),
AuthorRepo: persistence.NewAuthorRepository(db),
UserRepo: persistence.NewUserRepository(db),
ImageRepo: persistence.NewImageRepository(db),
VariantRepo: persistence.NewVariantRepository(db),
VariantFileRepo: variantFiles,
VariantCacheRepo: variantFiles,
VariantUsageRepo: persistence.NewVariantUsageRepository(db),
VariantRenderer: imaging.NewVariantRenderer(),
InviteRepo: persistence.NewInviteRepository(db),
APIKeyRepo: persistence.NewAPIKeyRepository(db),
PurgeSettingsRepo: persistence.NewPurgeSettingsRepository(db),
AuditRepo: persistence.NewAuditEventRepository(db),
AuditSettingsRepo: persistence.NewAuditSettingsRepository(db),
MailRepo: mailer.NewMailRepository(settings.Smtp),
ReleaseFeed: update.NewGiteaReleaseFeed(settings.UpdateFeedURL),
UpdateStore: update.NewJSONStatusStore(filepath.Join(dataDir, updateStatusFileName)),
UpdateJobs: update.NewJSONJobStore(filepath.Join(dataDir, updateJobFileName)),
UpdateHelper: update.NewContainerHelperDetector(update.NewFileHelperDetector(filepath.Join(dataDir, updateHelperFileName)), settings.Container),
AssetFetcher: update.NewHTTPAssetFetcher(settings.UpdateFeedURL),
SignatureVerifier: update.NewEd25519SignatureVerifier(releasePublicKey()),
StagedRunner: update.NewExecStagedBinaryRunner(),
DatabaseBackup: connection.NewBackup(filepath.Join(dataDir, backupsDirName), time.Now),
UpdateResults: update.NewJSONResultStore(filepath.Join(dataDir, domainUpdate.ResultFileName)),
RestartRequests: update.NewJSONRestartRequestStore(filepath.Join(dataDir, domainUpdate.RestartRequestFileName)),
RunningInfo: update.NewJSONRunningInfoStore(filepath.Join(dataDir, domainUpdate.RunningInfoFileName)),
}
}
func getUseCases(repos *Repositories, imageStorage domainImage.Storage, settings config.Settings) *UseCases {
hasher := hashing.NewBcryptHasher()
renderer := markdown.NewConverter()
keyGenerator := hashing.NewSHA256KeyGenerator()
recorder := auditing.NewRecorder(repos.AuditRepo, time.Now, log.Default())
mergeMedia := useCases.NewMergeMediaUseCase(repos.ImageRepo, repos.ArticleRepo, imageStorage, repos.VariantFileRepo, recorder, repos.SiteRepo, repos.AuthorRepo)
runPurge := useCases.NewRunPurgeUseCase(repos.ImageRepo, repos.ArticleRepo, mergeMedia, repos.PurgeSettingsRepo, time.Now, log.Default(), recorder, repos.SiteRepo, repos.AuthorRepo)
purgeScheduler := useCases.NewPurgeSchedulerUseCase(repos.PurgeSettingsRepo, runPurge, recorder)
activityCleanup := useCases.NewCleanupActivityUseCase(repos.AuditRepo, repos.AuditSettingsRepo, recorder)
usageTracker := usage.NewTracker(repos.VariantUsageRepo, time.Now)
serveVariant := useCases.NewServeVariantUseCase(repos.VariantRepo, repos.VariantFileRepo, repos.ImageRepo, imageStorage, repos.VariantRenderer, useCases.ServeVariantLimits{MaxSourceBytes: settings.ImageVariantMaxSourceBytes, MaxSourcePixels: settings.ImageVariantMaxSourcePixels, MaxConcurrentRenders: settings.ImageVariantMaxConcurrentRenders}).WithUsageTracker(usageTracker)
return &UseCases{
PurgeScheduler: scheduler.NewSystemRunner(purgeScheduler, log.Default()),
ActivityCleanupScheduler: scheduler.NewSystemCleanupRunner(activityCleanup, log.Default()),
Token: jwtauth.New("HS256", []byte(settings.JWTSecret), nil),
CreateArticleUseCase: useCases.NewCreateArticleUseCase(repos.ArticleRepo, renderer, recorder, repos.SiteRepo, repos.AuthorRepo),
GetArticleUseCase: useCases.NewGetArticleUseCase(repos.ArticleRepo, renderer),
ListArticlesUseCase: useCases.NewListArticlesUseCase(repos.ArticleRepo, renderer, repos.SiteRepo),
UpdateArticleUseCase: useCases.NewUpdateArticleUseCase(repos.ArticleRepo, renderer, recorder, repos.SiteRepo, repos.AuthorRepo, repos.ImageRepo),
DeleteArticleUseCase: useCases.NewDeleteArticleUseCase(repos.ArticleRepo, recorder),
ResolveArticleSEOUseCase: useCases.NewResolveArticleSEOUseCase(repos.ArticleRepo, repos.SiteRepo, repos.ImageRepo),
CheckArticleSEOUseCase: useCases.NewCheckArticleSEOUseCase(repos.ArticleRepo, repos.SiteRepo, repos.ImageRepo),
ListSitemapUseCase: useCases.NewListSitemapUseCase(repos.ArticleRepo, repos.SiteRepo),
ListAuthorsUseCase: useCases.NewListAuthorsUseCase(repos.AuthorRepo, repos.UserRepo),
CreateAuthorUseCase: useCases.NewCreateAuthorUseCase(repos.AuthorRepo, repos.UserRepo, repos.ImageRepo, recorder),
CreateMyAuthorUseCase: useCases.NewCreateMyAuthorUseCase(repos.AuthorRepo, repos.UserRepo, recorder),
UpdateAuthorUseCase: useCases.NewUpdateAuthorUseCase(repos.AuthorRepo, repos.UserRepo, repos.ImageRepo, recorder),
DeleteAuthorUseCase: useCases.NewDeleteAuthorUseCase(repos.AuthorRepo, recorder),
GetMyAuthorUseCase: useCases.NewGetMyAuthorUseCase(repos.AuthorRepo),
ListSitesUseCase: useCases.NewListSitesUseCase(repos.SiteRepo),
CreateSiteUseCase: useCases.NewCreateSiteUseCase(repos.SiteRepo, repos.ImageRepo, recorder),
UpdateSiteUseCase: useCases.NewUpdateSiteUseCase(repos.SiteRepo, repos.ImageRepo, recorder),
SetDefaultSiteUseCase: useCases.NewSetDefaultSiteUseCase(repos.SiteRepo, recorder),
DeleteSiteUseCase: useCases.NewDeleteSiteUseCase(repos.SiteRepo, recorder),
GetUserUseCase: useCases.NewGetUserUseCase(repos.UserRepo),
CreateUserUseCase: useCases.NewCreateUserUseCase(repos.UserRepo, hasher, repos.MailRepo, settings.PublicURL, recorder),
AuthenticateUserUseCase: useCases.NewAuthenticateUserUseCase(repos.UserRepo, hasher, recorder),
VerifyUserUseCase: useCases.NewVerifyUserUseCase(repos.UserRepo, hasher, recorder),
CancelRegistrationUseCase: useCases.NewCancelRegistrationUseCase(repos.UserRepo),
RequestPasswordResetUseCase: useCases.NewRequestPasswordResetUseCase(repos.UserRepo, hasher, repos.MailRepo, settings.PublicURL, recorder),
ResetPasswordUseCase: useCases.NewResetPasswordUseCase(repos.UserRepo, hasher, repos.APIKeyRepo, time.Now, recorder),
UpdateUserProfileUseCase: useCases.NewUpdateUserProfileUseCase(repos.UserRepo, recorder),
ListUsersUseCase: useCases.NewListUsersUseCase(repos.UserRepo),
CreateInviteUseCase: useCases.NewCreateInviteUseCase(repos.UserRepo, repos.InviteRepo, hasher, repos.MailRepo, settings.PublicURL, recorder),
CancelInviteUseCase: useCases.NewCancelInviteUseCase(repos.InviteRepo, recorder),
RenewInviteUseCase: useCases.NewRenewInviteUseCase(repos.UserRepo, repos.InviteRepo, hasher, repos.MailRepo, settings.PublicURL, recorder),
ListUsersAndInvitesUseCase: useCases.NewListUsersAndInvitesUseCase(repos.UserRepo, repos.InviteRepo),
GetInviteUseCase: useCases.NewGetInviteUseCase(repos.InviteRepo, hasher),
AcceptInviteUseCase: useCases.NewAcceptInviteUseCase(repos.UserRepo, repos.InviteRepo, hasher, recorder),
SendMailUseCase: useCases.NewSendMailUseCase(repos.MailRepo),
CreateImageUseCase: useCases.NewCreateImageUseCase(repos.ImageRepo, imageStorage, recorder),
OpenMediaUseCase: useCases.NewOpenMediaUseCase(imageStorage),
ListMediaUseCase: useCases.NewListMediaUseCase(repos.ImageRepo, repos.ArticleRepo, repos.UserRepo, repos.VariantFileRepo, repos.SiteRepo, repos.AuthorRepo),
RenameMediaUseCase: useCases.NewRenameMediaUseCase(repos.ImageRepo, recorder),
DeleteMediaUseCase: useCases.NewDeleteMediaUseCase(repos.ImageRepo, imageStorage, repos.VariantFileRepo, recorder, repos.SiteRepo, repos.AuthorRepo, repos.ArticleRepo),
MergeMediaUseCase: mergeMedia,
GetMediaUsageUseCase: useCases.NewGetMediaUsageUseCase(repos.ImageRepo, repos.ArticleRepo, repos.SiteRepo, repos.AuthorRepo),
GetPurgeSettingsUseCase: useCases.NewGetPurgeSettingsUseCase(repos.PurgeSettingsRepo),
UpdatePurgeSettingsUseCase: useCases.NewUpdatePurgeSettingsUseCase(repos.PurgeSettingsRepo, time.Now),
PreviewPurgeUseCase: useCases.NewPreviewPurgeUseCase(repos.ImageRepo, repos.ArticleRepo, repos.SiteRepo, repos.AuthorRepo),
RunPurgeUseCase: runPurge,
GetSettingsUseCase: useCases.NewGetSettingsUseCase(settings.Version),
GetUpdateStatusUseCase: useCases.NewGetUpdateStatusUseCase(repos.UpdateStore, repos.UpdateJobs, repos.UpdateHelper, repos.UpdateResults, repos.RestartRequests, settings.Version, settings.Container, time.Now),
CheckForUpdateUseCase: useCases.NewCheckForUpdateUseCase(repos.ReleaseFeed, repos.UpdateStore, settings.Version, time.Now, recorder),
StartUpdateDownloadUseCase: startUpdateDownloadUseCase(repos, settings, recorder),
RequestRestartUseCase: useCases.NewRequestRestartUseCase(repos.UpdateStore, repos.UpdateJobs, repos.UpdateHelper, repos.UpdateResults, repos.RestartRequests, settings.Version, time.Now, recorder),
RecordRunningInfoUseCase: useCases.NewRecordRunningInfoUseCase(repos.RunningInfo, settings.Version, os.Getpid(), time.Now),
CreateAPIKeyUseCase: useCases.NewCreateAPIKeyUseCase(repos.APIKeyRepo, keyGenerator, time.Now, recorder),
ListAPIKeysUseCase: useCases.NewListAPIKeysUseCase(repos.APIKeyRepo, repos.UserRepo, time.Now),
RevokeAPIKeyUseCase: useCases.NewRevokeAPIKeyUseCase(repos.APIKeyRepo, repos.UserRepo, time.Now, recorder),
AuthenticateAPIKeyUseCase: useCases.NewAuthenticateAPIKeyUseCase(repos.APIKeyRepo, keyGenerator, repos.UserRepo, time.Now),
ListActivityUseCase: useCases.NewListActivityUseCase(repos.AuditRepo, repos.UserRepo, repos.ArticleRepo, repos.ImageRepo, repos.APIKeyRepo, time.Now, repos.SiteRepo, repos.AuthorRepo),
GetActivitySummaryUseCase: useCases.NewGetActivitySummaryUseCase(repos.AuditRepo, time.Now),
ExportActivityUseCase: useCases.NewExportActivityUseCase(repos.AuditRepo, time.Now),
GetActivityRetentionUseCase: useCases.NewGetActivityRetentionUseCase(repos.AuditSettingsRepo, repos.AuditRepo, time.Now),
UpdateActivityRetentionUseCase: useCases.NewUpdateActivityRetentionUseCase(repos.AuditSettingsRepo, repos.AuditRepo, recorder, time.Now),
ListVariantsUseCase: useCases.NewListVariantsUseCase(repos.VariantRepo, repos.VariantFileRepo),
CreateVariantUseCase: useCases.NewCreateVariantUseCase(repos.VariantRepo, repos.VariantRenderer, time.Now, recorder),
UpdateVariantUseCase: useCases.NewUpdateVariantUseCase(repos.VariantRepo, repos.VariantFileRepo, imageStorage, repos.VariantRenderer, time.Now, recorder),
SetVariantEnabledUseCase: useCases.NewSetVariantEnabledUseCase(repos.VariantRepo, repos.VariantFileRepo, time.Now, recorder),
DeleteVariantUseCase: useCases.NewDeleteVariantUseCase(repos.VariantRepo, repos.VariantFileRepo, imageStorage, recorder),
PurgeVariantUseCase: useCases.NewPurgeVariantUseCase(repos.VariantRepo, repos.VariantFileRepo, imageStorage, recorder),
ServeVariantUseCase: serveVariant,
ListImageVariantsUseCase: useCases.NewListImageVariantsUseCase(repos.ImageRepo, repos.VariantRepo, repos.VariantFileRepo, repos.VariantRenderer),
GenerateImageVariantUseCase: useCases.NewGenerateImageVariantUseCase(repos.ImageRepo, repos.VariantRepo, repos.VariantFileRepo, repos.VariantRenderer, serveVariant),
GenerateAllImageVariantsUseCase: useCases.NewGenerateAllImageVariantsUseCase(repos.ImageRepo, repos.VariantRepo, repos.VariantFileRepo, repos.VariantRenderer, serveVariant, recorder),
PurgeImageVariantUseCase: useCases.NewPurgeImageVariantUseCase(repos.ImageRepo, repos.VariantRepo, repos.VariantFileRepo, imageStorage, recorder),
GenerateVariantsOnUploadUseCase: useCases.NewGenerateVariantsOnUploadUseCase(repos.VariantRepo, serveVariant, log.Default()),
GetVariantCacheStatsUseCase: useCases.NewGetVariantCacheStatsUseCase(repos.VariantRepo, repos.VariantFileRepo, repos.VariantCacheRepo, repos.ImageRepo, repos.VariantUsageRepo, usageTracker, time.Now),
PurgeVariantCacheUseCase: useCases.NewPurgeVariantCacheUseCase(repos.VariantRepo, repos.ImageRepo, repos.VariantCacheRepo, repos.VariantFileRepo, imageStorage, time.Now, recorder),
VariantUsageTracker: usageTracker,
}
}
func startUpdateDownloadUseCase(repos *Repositories, settings config.Settings, recorder domainAudit.Recorder) *useCases.StartUpdateDownloadUseCase {
return useCases.NewStartUpdateDownloadUseCase(useCases.StartUpdateDownloadDependencies{
Store: repos.UpdateStore,
Jobs: repos.UpdateJobs,
Helper: repos.UpdateHelper,
Results: repos.UpdateResults,
Requests: repos.RestartRequests,
Fetcher: repos.AssetFetcher,
Verifier: repos.SignatureVerifier,
Runner: repos.StagedRunner,
Backup: repos.DatabaseBackup,
Staging: update.NewOSStagingArea(filepath.Join(settings.DataDir(), updatesDirName)),
Logger: log.Default(),
CurrentVersion: settings.Version,
Platform: domainUpdate.Platform{OS: runtime.GOOS, Arch: runtime.GOARCH},
FeedURL: settings.UpdateFeedURL,
Now: time.Now,
Recorder: recorder,
})
}
func backfillImageMetadata(imageRepo domainImage.Repository, imageStorage domainImage.Storage, settings config.Settings) error {
run := func(readable domainImage.Storage) error {
return useCases.NewBackfillImageMetadataUseCase(imageRepo, readable).Run()
}
if settings.Storage.Driver == config.StorageDriverS3 {
return storage.RunBackfillReportingReads(imageStorage, log.Default(), run)
}
return run(imageStorage)
}
func InitContainer(settings config.Settings) (*UseCases, func() error) {
imageStorage := openImageStorage(settings)
connection := openDatabase(settings)
repos := getRepositories(connection, settings)
if err := backfillImageMetadata(repos.ImageRepo, imageStorage, settings); err != nil {
panic("Failed to backfill image metadata: " + err.Error())
}
container := getUseCases(repos, imageStorage, settings)
return container, container.runUsageTracker(connection.Close)
}
func (c *UseCases) runUsageTracker(closeDatabase func() error) func() error {
ctx, stop := context.WithCancel(context.Background())
stopped := make(chan struct{})
go func() {
defer close(stopped)
c.VariantUsageTracker.Run(ctx)
}()
return func() error {
stop()
<-stopped
return closeDatabase()
}
}
type BrowserUpdateCommands struct {
Enable *useCases.EnableBrowserUpdatesUseCase
Disable *useCases.DisableBrowserUpdatesUseCase
}
func InitBrowserUpdateCommands() *BrowserUpdateCommands {
units := update.NewSystemdUnits()
dependencies := useCases.ManageBrowserUpdatesDependencies{
Probe: update.NewSystemMachineProbe(),
Locator: units,
Units: units,
Manager: update.NewSystemctlControl(domainUpdate.ServiceUnitName),
Status: update.NewJSONHelperStatusWriter(),
Now: time.Now,
}
return &BrowserUpdateCommands{
Enable: useCases.NewEnableBrowserUpdatesUseCase(dependencies),
Disable: useCases.NewDisableBrowserUpdatesUseCase(dependencies),
}
}
func InitApplyUpdateCommand(options domainUpdate.InstallOptions) *useCases.ApplyRestartRequestUseCase {
layout := domainUpdate.HelperLayout{DataDir: options.DataDir, BinaryPath: options.Binary}
files := update.NewNoFollowFilesystem()
return useCases.NewApplyRestartRequestUseCase(useCases.ApplyRestartRequestDependencies{
Requests: update.NewFSRestartRequestStore(files, layout.RestartRequestPath()),
Results: update.NewFSResultStore(files, layout.ResultPath()),
Running: update.NewJSONRunningInfoStore(filepath.Join(options.DataDir, domainUpdate.RunningInfoFileName)),
Files: files,
Service: update.NewSystemctlControl(options.Service),
Health: update.NewHTTPHealthChecker(options.Port),
Verifier: update.NewEd25519SignatureVerifier(releasePublicKey()),
Clock: update.NewSystemClock(),
Logger: log.Default(),
Layout: layout,
Platform: domainUpdate.Platform{OS: runtime.GOOS, Arch: runtime.GOARCH},
})
}