mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Manager refactor, part 1 (#4298)
* Move BackupDatabase and AnonymiseDatabase to internal/manager * Rename config.Instance to config.Config * Rename FFMPEG * Rework manager and initialization process * Fix Makefile * Tweak phasher * Fix config races * Fix setup error not clearing
This commit is contained in:
@@ -505,19 +505,10 @@ func (r *mutationResolver) ConfigureDlna(ctx context.Context, input ConfigDLNAIn
|
||||
c.Set(config.DLNAVideoSortOrder, input.VideoSortOrder)
|
||||
}
|
||||
|
||||
currentDLNAEnabled := c.GetDLNADefaultEnabled()
|
||||
if input.Enabled != nil && *input.Enabled != currentDLNAEnabled {
|
||||
refresh := false
|
||||
if input.Enabled != nil {
|
||||
c.Set(config.DLNADefaultEnabled, *input.Enabled)
|
||||
|
||||
// start/stop the DLNA service as needed
|
||||
dlnaService := manager.GetInstance().DLNAService
|
||||
if !*input.Enabled && dlnaService.IsRunning() {
|
||||
dlnaService.Stop(nil)
|
||||
} else if *input.Enabled && !dlnaService.IsRunning() {
|
||||
if err := dlnaService.Start(nil); err != nil {
|
||||
logger.Warnf("error starting DLNA service: %v", err)
|
||||
}
|
||||
}
|
||||
refresh = true
|
||||
}
|
||||
|
||||
if input.Interfaces != nil {
|
||||
@@ -528,6 +519,10 @@ func (r *mutationResolver) ConfigureDlna(ctx context.Context, input ConfigDLNAIn
|
||||
return makeConfigDLNAResult(), err
|
||||
}
|
||||
|
||||
if refresh {
|
||||
manager.GetInstance().RefreshDLNA()
|
||||
}
|
||||
|
||||
return makeConfigDLNAResult(), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -12,7 +10,6 @@ import (
|
||||
"github.com/stashapp/stash/internal/identify"
|
||||
"github.com/stashapp/stash/internal/manager"
|
||||
"github.com/stashapp/stash/internal/manager/config"
|
||||
"github.com/stashapp/stash/pkg/fsutil"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
)
|
||||
|
||||
@@ -110,31 +107,10 @@ func (r *mutationResolver) BackupDatabase(ctx context.Context, input BackupDatab
|
||||
// if download is true, then backup to temporary file and return a link
|
||||
download := input.Download != nil && *input.Download
|
||||
mgr := manager.GetInstance()
|
||||
database := mgr.Database
|
||||
var backupPath string
|
||||
if download {
|
||||
if err := fsutil.EnsureDir(mgr.Paths.Generated.Downloads); err != nil {
|
||||
return nil, fmt.Errorf("could not create backup directory %v: %w", mgr.Paths.Generated.Downloads, err)
|
||||
}
|
||||
f, err := os.CreateTemp(mgr.Paths.Generated.Downloads, "backup*.sqlite")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
backupPath = f.Name()
|
||||
f.Close()
|
||||
} else {
|
||||
backupDirectoryPath := mgr.Config.GetBackupDirectoryPathOrDefault()
|
||||
if backupDirectoryPath != "" {
|
||||
if err := fsutil.EnsureDir(backupDirectoryPath); err != nil {
|
||||
return nil, fmt.Errorf("could not create backup directory %v: %w", backupDirectoryPath, err)
|
||||
}
|
||||
}
|
||||
backupPath = database.DatabaseBackupPath(backupDirectoryPath)
|
||||
}
|
||||
|
||||
err := database.Backup(backupPath)
|
||||
backupPath, backupName, err := mgr.BackupDatabase(download)
|
||||
if err != nil {
|
||||
logger.Errorf("Error backing up database: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -147,8 +123,7 @@ func (r *mutationResolver) BackupDatabase(ctx context.Context, input BackupDatab
|
||||
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
|
||||
fn := filepath.Base(database.DatabaseBackupPath(""))
|
||||
ret := baseURL + "/downloads/" + downloadHash + "/" + fn
|
||||
ret := baseURL + "/downloads/" + downloadHash + "/" + backupName
|
||||
return &ret, nil
|
||||
} else {
|
||||
logger.Infof("Successfully backed up database to: %s", backupPath)
|
||||
@@ -158,33 +133,11 @@ func (r *mutationResolver) BackupDatabase(ctx context.Context, input BackupDatab
|
||||
}
|
||||
|
||||
func (r *mutationResolver) AnonymiseDatabase(ctx context.Context, input AnonymiseDatabaseInput) (*string, error) {
|
||||
// if download is true, then backup to temporary file and return a link
|
||||
// if download is true, then save to temporary file and return a link
|
||||
download := input.Download != nil && *input.Download
|
||||
mgr := manager.GetInstance()
|
||||
database := mgr.Database
|
||||
var outPath string
|
||||
if download {
|
||||
if err := fsutil.EnsureDir(mgr.Paths.Generated.Downloads); err != nil {
|
||||
return nil, fmt.Errorf("could not create backup directory %v: %w", mgr.Paths.Generated.Downloads, err)
|
||||
}
|
||||
f, err := os.CreateTemp(mgr.Paths.Generated.Downloads, "anonymous*.sqlite")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outPath = f.Name()
|
||||
f.Close()
|
||||
} else {
|
||||
backupDirectoryPath := mgr.Config.GetBackupDirectoryPathOrDefault()
|
||||
if backupDirectoryPath != "" {
|
||||
if err := fsutil.EnsureDir(backupDirectoryPath); err != nil {
|
||||
return nil, fmt.Errorf("could not create backup directory %v: %w", backupDirectoryPath, err)
|
||||
}
|
||||
}
|
||||
outPath = database.AnonymousDatabasePath(backupDirectoryPath)
|
||||
}
|
||||
|
||||
err := database.Anonymise(outPath)
|
||||
outPath, outName, err := mgr.AnonymiseDatabase(download)
|
||||
if err != nil {
|
||||
logger.Errorf("Error anonymising database: %v", err)
|
||||
return nil, err
|
||||
@@ -199,8 +152,7 @@ func (r *mutationResolver) AnonymiseDatabase(ctx context.Context, input Anonymis
|
||||
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
|
||||
fn := filepath.Base(database.DatabaseBackupPath(""))
|
||||
ret := baseURL + "/downloads/" + downloadHash + "/" + fn
|
||||
ret := baseURL + "/downloads/" + downloadHash + "/" + outName
|
||||
return &ret, nil
|
||||
} else {
|
||||
logger.Infof("Successfully anonymised database to: %s", outPath)
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/stashapp/stash/internal/manager"
|
||||
"github.com/stashapp/stash/internal/manager/task"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
@@ -14,13 +13,9 @@ func refreshPackageType(typeArg PackageType) {
|
||||
mgr := manager.GetInstance()
|
||||
|
||||
if typeArg == PackageTypePlugin {
|
||||
if err := mgr.PluginCache.LoadPlugins(); err != nil {
|
||||
logger.Errorf("Error reading plugin configs: %v", err)
|
||||
}
|
||||
mgr.RefreshPluginCache()
|
||||
} else if typeArg == PackageTypeScraper {
|
||||
if err := mgr.ScraperCache.ReloadScrapers(); err != nil {
|
||||
logger.Errorf("Error reading scraper configs: %v", err)
|
||||
}
|
||||
mgr.RefreshScraperCache()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/stashapp/stash/internal/manager"
|
||||
"github.com/stashapp/stash/internal/manager/config"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/plugin"
|
||||
"github.com/stashapp/stash/pkg/sliceutil"
|
||||
)
|
||||
@@ -17,11 +16,7 @@ func (r *mutationResolver) RunPluginTask(ctx context.Context, pluginID string, t
|
||||
}
|
||||
|
||||
func (r *mutationResolver) ReloadPlugins(ctx context.Context) (bool, error) {
|
||||
err := manager.GetInstance().PluginCache.LoadPlugins()
|
||||
if err != nil {
|
||||
logger.Errorf("Error reading plugin configs: %v", err)
|
||||
}
|
||||
|
||||
manager.GetInstance().RefreshPluginCache()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,6 @@ import (
|
||||
)
|
||||
|
||||
func (r *mutationResolver) ReloadScrapers(ctx context.Context) (bool, error) {
|
||||
err := manager.GetInstance().ScraperCache.ReloadScrapers()
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
manager.GetInstance().RefreshScraperCache()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
type downloadsRoutes struct{}
|
||||
|
||||
func getDownloadsRoutes() chi.Router {
|
||||
return downloadsRoutes{}.Routes()
|
||||
}
|
||||
|
||||
func (rs downloadsRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -31,14 +31,6 @@ type imageRoutes struct {
|
||||
fileGetter models.FileGetter
|
||||
}
|
||||
|
||||
func getImageRoutes(repo models.Repository) chi.Router {
|
||||
return imageRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
imageFinder: repo.Image,
|
||||
fileGetter: repo.File,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs imageRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -76,7 +68,7 @@ func (rs imageRoutes) Thumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
Preset: manager.GetInstance().Config.GetPreviewPreset().String(),
|
||||
}
|
||||
|
||||
encoder := image.NewThumbnailEncoder(manager.GetInstance().FFMPEG, manager.GetInstance().FFProbe, clipPreviewOptions)
|
||||
encoder := image.NewThumbnailEncoder(manager.GetInstance().FFMpeg, manager.GetInstance().FFProbe, clipPreviewOptions)
|
||||
data, err := encoder.GetThumbnail(f, models.DefaultGthumbWidth)
|
||||
if err != nil {
|
||||
// don't log for unsupported image format
|
||||
|
||||
@@ -25,13 +25,6 @@ type movieRoutes struct {
|
||||
movieFinder MovieFinder
|
||||
}
|
||||
|
||||
func getMovieRoutes(repo models.Repository) chi.Router {
|
||||
return movieRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
movieFinder: repo.Movie,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs movieRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -23,13 +23,6 @@ type performerRoutes struct {
|
||||
performerFinder PerformerFinder
|
||||
}
|
||||
|
||||
func getPerformerRoutes(repo models.Repository) chi.Router {
|
||||
return performerRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
performerFinder: repo.Performer,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs performerRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -15,12 +15,6 @@ type pluginRoutes struct {
|
||||
pluginCache *plugin.Cache
|
||||
}
|
||||
|
||||
func getPluginRoutes(pluginCache *plugin.Cache) chi.Router {
|
||||
return pluginRoutes{
|
||||
pluginCache: pluginCache,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs pluginRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -51,17 +51,6 @@ type sceneRoutes struct {
|
||||
tagFinder SceneMarkerTagFinder
|
||||
}
|
||||
|
||||
func getSceneRoutes(repo models.Repository) chi.Router {
|
||||
return sceneRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
sceneFinder: repo.Scene,
|
||||
fileGetter: repo.File,
|
||||
captionFinder: repo.File,
|
||||
sceneMarkerFinder: repo.SceneMarker,
|
||||
tagFinder: repo.Tag,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -24,13 +24,6 @@ type studioRoutes struct {
|
||||
studioFinder StudioFinder
|
||||
}
|
||||
|
||||
func getStudioRoutes(repo models.Repository) chi.Router {
|
||||
return studioRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
studioFinder: repo.Studio,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs studioRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -24,13 +24,6 @@ type tagRoutes struct {
|
||||
tagFinder TagFinder
|
||||
}
|
||||
|
||||
func getTagRoutes(repo models.Repository) chi.Router {
|
||||
return tagRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
tagFinder: repo.Tag,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (rs tagRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
||||
@@ -46,25 +46,65 @@ const (
|
||||
playgroundEndpoint = "/playground"
|
||||
)
|
||||
|
||||
var uiBox = ui.UIBox
|
||||
var loginUIBox = ui.LoginUIBox
|
||||
type Server struct {
|
||||
http.Server
|
||||
displayAddress string
|
||||
|
||||
func Start() error {
|
||||
c := config.GetInstance()
|
||||
manager *manager.Manager
|
||||
}
|
||||
|
||||
initCustomPerformerImages(c.GetCustomPerformerImageLocation())
|
||||
// Called at startup
|
||||
func Initialize() (*Server, error) {
|
||||
mgr := manager.GetInstance()
|
||||
cfg := mgr.Config
|
||||
|
||||
initCustomPerformerImages(cfg.GetCustomPerformerImageLocation())
|
||||
|
||||
displayHost := cfg.GetHost()
|
||||
if displayHost == "0.0.0.0" {
|
||||
displayHost = "localhost"
|
||||
}
|
||||
displayAddress := displayHost + ":" + strconv.Itoa(cfg.GetPort())
|
||||
|
||||
address := cfg.GetHost() + ":" + strconv.Itoa(cfg.GetPort())
|
||||
tlsConfig, err := makeTLSConfig(cfg)
|
||||
if err != nil {
|
||||
// assume we don't want to start with a broken TLS configuration
|
||||
return nil, fmt.Errorf("error loading TLS config: %v", err)
|
||||
}
|
||||
|
||||
if tlsConfig != nil {
|
||||
displayAddress = "https://" + displayAddress + "/"
|
||||
} else {
|
||||
displayAddress = "http://" + displayAddress + "/"
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
server := &Server{
|
||||
Server: http.Server{
|
||||
Addr: address,
|
||||
Handler: r,
|
||||
TLSConfig: tlsConfig,
|
||||
// disable http/2 support by default
|
||||
// when http/2 is enabled, we are unable to hijack and close
|
||||
// the connection/request. This is necessary to stop running
|
||||
// streams when deleting a scene file.
|
||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||
},
|
||||
displayAddress: displayAddress,
|
||||
manager: mgr,
|
||||
}
|
||||
|
||||
r.Use(middleware.Heartbeat("/healthz"))
|
||||
r.Use(cors.AllowAll().Handler)
|
||||
r.Use(authenticateHandler())
|
||||
visitedPluginHandler := manager.GetInstance().SessionStore.VisitedPluginHandler()
|
||||
visitedPluginHandler := mgr.SessionStore.VisitedPluginHandler()
|
||||
r.Use(visitedPluginHandler)
|
||||
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
if c.GetLogAccess() {
|
||||
if cfg.GetLogAccess() {
|
||||
httpLogger := httplog.NewLogger("Stash", httplog.Options{
|
||||
Concise: true,
|
||||
})
|
||||
@@ -83,7 +123,7 @@ func Start() error {
|
||||
return errors.New(message)
|
||||
}
|
||||
|
||||
repo := manager.GetInstance().Repository
|
||||
repo := mgr.Repository
|
||||
|
||||
dataloaders := loaders.Middleware{
|
||||
Repository: repo,
|
||||
@@ -91,10 +131,10 @@ func Start() error {
|
||||
|
||||
r.Use(dataloaders.Middleware)
|
||||
|
||||
pluginCache := manager.GetInstance().PluginCache
|
||||
sceneService := manager.GetInstance().SceneService
|
||||
imageService := manager.GetInstance().ImageService
|
||||
galleryService := manager.GetInstance().GalleryService
|
||||
pluginCache := mgr.PluginCache
|
||||
sceneService := mgr.SceneService
|
||||
imageService := mgr.ImageService
|
||||
galleryService := mgr.GalleryService
|
||||
resolver := &Resolver{
|
||||
repository: repo,
|
||||
sceneService: sceneService,
|
||||
@@ -117,7 +157,7 @@ func Start() error {
|
||||
gqlSrv.AddTransport(gqlTransport.GET{})
|
||||
gqlSrv.AddTransport(gqlTransport.POST{})
|
||||
gqlSrv.AddTransport(gqlTransport.MultipartForm{
|
||||
MaxUploadSize: c.GetMaxUploadSize(),
|
||||
MaxUploadSize: cfg.GetMaxUploadSize(),
|
||||
})
|
||||
|
||||
gqlSrv.SetQueryCache(gqlLru.New(1000))
|
||||
@@ -134,7 +174,7 @@ func Start() error {
|
||||
// chain the visited plugin handler
|
||||
// also requires the dataloader middleware
|
||||
gqlHandler := visitedPluginHandler(dataloaders.Middleware(http.HandlerFunc(gqlHandlerFunc)))
|
||||
manager.GetInstance().PluginCache.RegisterGQLHandler(gqlHandler)
|
||||
pluginCache.RegisterGQLHandler(gqlHandler)
|
||||
|
||||
r.HandleFunc(gqlEndpoint, gqlHandlerFunc)
|
||||
r.HandleFunc(playgroundEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -143,23 +183,23 @@ func Start() error {
|
||||
gqlPlayground.Handler("GraphQL playground", endpoint)(w, r)
|
||||
})
|
||||
|
||||
r.Mount("/performer", getPerformerRoutes(repo))
|
||||
r.Mount("/scene", getSceneRoutes(repo))
|
||||
r.Mount("/image", getImageRoutes(repo))
|
||||
r.Mount("/studio", getStudioRoutes(repo))
|
||||
r.Mount("/movie", getMovieRoutes(repo))
|
||||
r.Mount("/tag", getTagRoutes(repo))
|
||||
r.Mount("/downloads", getDownloadsRoutes())
|
||||
r.Mount("/plugin", getPluginRoutes(pluginCache))
|
||||
r.Mount("/performer", server.getPerformerRoutes())
|
||||
r.Mount("/scene", server.getSceneRoutes())
|
||||
r.Mount("/image", server.getImageRoutes())
|
||||
r.Mount("/studio", server.getStudioRoutes())
|
||||
r.Mount("/movie", server.getMovieRoutes())
|
||||
r.Mount("/tag", server.getTagRoutes())
|
||||
r.Mount("/downloads", server.getDownloadsRoutes())
|
||||
r.Mount("/plugin", server.getPluginRoutes())
|
||||
|
||||
r.HandleFunc("/css", cssHandler(c))
|
||||
r.HandleFunc("/javascript", javascriptHandler(c))
|
||||
r.HandleFunc("/customlocales", customLocalesHandler(c))
|
||||
r.HandleFunc("/css", cssHandler(cfg))
|
||||
r.HandleFunc("/javascript", javascriptHandler(cfg))
|
||||
r.HandleFunc("/customlocales", customLocalesHandler(cfg))
|
||||
|
||||
staticLoginUI := statigz.FileServer(loginUIBox.(fs.ReadDirFS))
|
||||
staticLoginUI := statigz.FileServer(ui.LoginUIBox.(fs.ReadDirFS))
|
||||
|
||||
r.Get(loginEndpoint, handleLogin(loginUIBox))
|
||||
r.Post(loginEndpoint, handleLoginPost(loginUIBox))
|
||||
r.Get(loginEndpoint, handleLogin())
|
||||
r.Post(loginEndpoint, handleLoginPost())
|
||||
r.Get(logoutEndpoint, handleLogout())
|
||||
r.HandleFunc(loginEndpoint+"/*", func(w http.ResponseWriter, r *http.Request) {
|
||||
r.URL.Path = strings.TrimPrefix(r.URL.Path, loginEndpoint)
|
||||
@@ -168,13 +208,13 @@ func Start() error {
|
||||
})
|
||||
|
||||
// Serve static folders
|
||||
customServedFolders := c.GetCustomServedFolders()
|
||||
customServedFolders := cfg.GetCustomServedFolders()
|
||||
if customServedFolders != nil {
|
||||
r.Mount("/custom", getCustomRoutes(customServedFolders))
|
||||
}
|
||||
|
||||
customUILocation := c.GetCustomUILocation()
|
||||
staticUI := statigz.FileServer(uiBox.(fs.ReadDirFS))
|
||||
customUILocation := cfg.GetCustomUILocation()
|
||||
staticUI := statigz.FileServer(ui.UIBox.(fs.ReadDirFS))
|
||||
|
||||
// Serve the web app
|
||||
r.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -190,8 +230,8 @@ func Start() error {
|
||||
}
|
||||
|
||||
if ext == ".html" || ext == "" {
|
||||
themeColor := c.GetThemeColor()
|
||||
data, err := fs.ReadFile(uiBox, "index.html")
|
||||
themeColor := cfg.GetThemeColor()
|
||||
data, err := fs.ReadFile(ui.UIBox, "index.html")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -217,51 +257,91 @@ func Start() error {
|
||||
}
|
||||
})
|
||||
|
||||
displayHost := c.GetHost()
|
||||
if displayHost == "0.0.0.0" {
|
||||
displayHost = "localhost"
|
||||
}
|
||||
displayAddress := displayHost + ":" + strconv.Itoa(c.GetPort())
|
||||
|
||||
address := c.GetHost() + ":" + strconv.Itoa(c.GetPort())
|
||||
tlsConfig, err := makeTLSConfig(c)
|
||||
if err != nil {
|
||||
// assume we don't want to start with a broken TLS configuration
|
||||
panic(fmt.Errorf("error loading TLS config: %v", err))
|
||||
}
|
||||
|
||||
server := &http.Server{
|
||||
Addr: address,
|
||||
Handler: r,
|
||||
TLSConfig: tlsConfig,
|
||||
// disable http/2 support by default
|
||||
// when http/2 is enabled, we are unable to hijack and close
|
||||
// the connection/request. This is necessary to stop running
|
||||
// streams when deleting a scene file.
|
||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||
}
|
||||
|
||||
logger.Infof("stash version: %s\n", build.VersionString())
|
||||
logger.Infof("stash version: %s", build.VersionString())
|
||||
go printLatestVersion(context.TODO())
|
||||
logger.Infof("stash is listening on " + address)
|
||||
if tlsConfig != nil {
|
||||
displayAddress = "https://" + displayAddress + "/"
|
||||
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
logger.Infof("stash is listening on " + s.Addr)
|
||||
logger.Infof("stash is running at " + s.displayAddress)
|
||||
|
||||
if s.TLSConfig != nil {
|
||||
return s.ListenAndServeTLS("", "")
|
||||
} else {
|
||||
displayAddress = "http://" + displayAddress + "/"
|
||||
return s.ListenAndServe()
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof("stash is running at " + displayAddress)
|
||||
if tlsConfig != nil {
|
||||
err = server.ListenAndServeTLS("", "")
|
||||
} else {
|
||||
err = server.ListenAndServe()
|
||||
func (s *Server) Shutdown() {
|
||||
err := s.Server.Shutdown(context.TODO())
|
||||
if err != nil {
|
||||
logger.Errorf("Error shutting down http server: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !errors.Is(err, http.ErrServerClosed) {
|
||||
return err
|
||||
}
|
||||
func (s *Server) getPerformerRoutes() chi.Router {
|
||||
repo := s.manager.Repository
|
||||
return performerRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
performerFinder: repo.Performer,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
return nil
|
||||
func (s *Server) getSceneRoutes() chi.Router {
|
||||
repo := s.manager.Repository
|
||||
return sceneRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
sceneFinder: repo.Scene,
|
||||
fileGetter: repo.File,
|
||||
captionFinder: repo.File,
|
||||
sceneMarkerFinder: repo.SceneMarker,
|
||||
tagFinder: repo.Tag,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (s *Server) getImageRoutes() chi.Router {
|
||||
repo := s.manager.Repository
|
||||
return imageRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
imageFinder: repo.Image,
|
||||
fileGetter: repo.File,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (s *Server) getStudioRoutes() chi.Router {
|
||||
repo := s.manager.Repository
|
||||
return studioRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
studioFinder: repo.Studio,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (s *Server) getMovieRoutes() chi.Router {
|
||||
repo := s.manager.Repository
|
||||
return movieRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
movieFinder: repo.Movie,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (s *Server) getTagRoutes() chi.Router {
|
||||
repo := s.manager.Repository
|
||||
return tagRoutes{
|
||||
routes: routes{txnManager: repo.TxnManager},
|
||||
tagFinder: repo.Tag,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func (s *Server) getDownloadsRoutes() chi.Router {
|
||||
return downloadsRoutes{}.Routes()
|
||||
}
|
||||
|
||||
func (s *Server) getPluginRoutes() chi.Router {
|
||||
return pluginRoutes{
|
||||
pluginCache: s.manager.PluginCache,
|
||||
}.Routes()
|
||||
}
|
||||
|
||||
func copyFile(w io.Writer, path string) error {
|
||||
@@ -290,7 +370,7 @@ func serveFiles(w http.ResponseWriter, r *http.Request, paths []string) {
|
||||
utils.ServeStaticContent(w, r, buffer.Bytes())
|
||||
}
|
||||
|
||||
func cssHandler(c *config.Instance) func(w http.ResponseWriter, r *http.Request) {
|
||||
func cssHandler(c *config.Config) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var paths []string
|
||||
|
||||
@@ -308,7 +388,7 @@ func cssHandler(c *config.Instance) func(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func javascriptHandler(c *config.Instance) func(w http.ResponseWriter, r *http.Request) {
|
||||
func javascriptHandler(c *config.Config) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var paths []string
|
||||
|
||||
@@ -326,7 +406,7 @@ func javascriptHandler(c *config.Instance) func(w http.ResponseWriter, r *http.R
|
||||
}
|
||||
}
|
||||
|
||||
func customLocalesHandler(c *config.Instance) func(w http.ResponseWriter, r *http.Request) {
|
||||
func customLocalesHandler(c *config.Config) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
buffer := bytes.Buffer{}
|
||||
|
||||
@@ -351,7 +431,7 @@ func customLocalesHandler(c *config.Instance) func(w http.ResponseWriter, r *htt
|
||||
}
|
||||
}
|
||||
|
||||
func makeTLSConfig(c *config.Instance) (*tls.Config, error) {
|
||||
func makeTLSConfig(c *config.Config) (*tls.Config, error) {
|
||||
c.InitTLS()
|
||||
certFile, keyFile := c.GetTLSFiles()
|
||||
|
||||
|
||||
@@ -14,12 +14,13 @@ import (
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/session"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
"github.com/stashapp/stash/ui"
|
||||
)
|
||||
|
||||
const returnURLParam = "returnURL"
|
||||
|
||||
func getLoginPage(loginUIBox fs.FS) []byte {
|
||||
data, err := fs.ReadFile(loginUIBox, "login.html")
|
||||
func getLoginPage() []byte {
|
||||
data, err := fs.ReadFile(ui.LoginUIBox, "login.html")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -31,8 +32,8 @@ type loginTemplateData struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
func serveLoginPage(loginUIBox fs.FS, w http.ResponseWriter, r *http.Request, returnURL string, loginError string) {
|
||||
loginPage := string(getLoginPage(loginUIBox))
|
||||
func serveLoginPage(w http.ResponseWriter, r *http.Request, returnURL string, loginError string) {
|
||||
loginPage := string(getLoginPage())
|
||||
prefix := getProxyPrefix(r)
|
||||
loginPage = strings.ReplaceAll(loginPage, "/%BASE_URL%", prefix)
|
||||
|
||||
@@ -57,7 +58,7 @@ func serveLoginPage(loginUIBox fs.FS, w http.ResponseWriter, r *http.Request, re
|
||||
utils.ServeStaticContent(w, r, buffer.Bytes())
|
||||
}
|
||||
|
||||
func handleLogin(loginUIBox fs.FS) http.HandlerFunc {
|
||||
func handleLogin() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
returnURL := r.URL.Query().Get(returnURLParam)
|
||||
|
||||
@@ -71,11 +72,11 @@ func handleLogin(loginUIBox fs.FS) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
serveLoginPage(loginUIBox, w, r, returnURL, "")
|
||||
serveLoginPage(w, r, returnURL, "")
|
||||
}
|
||||
}
|
||||
|
||||
func handleLoginPost(loginUIBox fs.FS) http.HandlerFunc {
|
||||
func handleLoginPost() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.FormValue(returnURLParam)
|
||||
if url == "" {
|
||||
@@ -92,7 +93,7 @@ func handleLoginPost(loginUIBox fs.FS) http.HandlerFunc {
|
||||
|
||||
if errors.As(err, &invalidCredentialsError) {
|
||||
// serve login page with an error
|
||||
serveLoginPage(loginUIBox, w, r, url, "Username or password is invalid")
|
||||
serveLoginPage(w, r, url, "Username or password is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user