server

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2026 License: MIT Imports: 53 Imported by: 0

Documentation

Overview

Package server provides the core HTTP server, routing, middleware, and handlers for the web application. This file holds route registration.

Package server provides the core HTTP server, routing, middleware, and handlers for the web application. It integrates all the sub-packages like database, caching, and background workers to serve the photo gallery.

Index

Constants

View Source
const (
	// SQLiteDriverName is the name of the SQLite driver to use
	SQLiteDriverName = "sqlite3"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {
	*InfrastructureService
	*ConfigManager
	*AuthService
	*HandlerManager
	*RuntimeManager
	*SubsystemManager
	// contains filtered or unexported fields
}

App holds the shared state and resources for the entire application. It manages database connections, worker pools, queues, caching, application context, and a task scheduler for recurring and one-time tasks.

Lock Ordering: To prevent deadlocks, always acquire locks in this order when holding multiple locks: 1. configMu 2. httpServerMu Never acquire a lower-ordered lock while holding a higher-ordered one.

func New

func New(opt getopt.Opt, version string) *App

New creates and initializes a new App instance. It sets up the application context, session secret, importer factory, and other core components.

func (*App) AddCommonTemplateData added in v0.8.0

func (app *App) AddCommonTemplateData(w http.ResponseWriter, r *http.Request, data map[string]any, partial bool) map[string]any

addCommonTemplateData adds common template data (auth state, CSRF token, theme, and gallery statistics) to template data map. When partial is true, skips GalleryStats (expensive getGalleryStatistics) since partials (HTMX swaps, modals, toasts) don't include the about modal. Full pages need GalleryStats for the about modal in the layout.

func (*App) ApplyConfig added in v0.8.0

func (app *App) ApplyConfig()

reconfigurePoolsFromConfig recreates database pools with the loaded configuration. This must be called AFTER loadConfig() to ensure the newly loaded config values (from database, YAML, or CLI/env) are applied to the connection pools. This enforces the precedence: Defaults -> DB -> Env -> CLI. applyConfig applies configuration values to App struct fields.

func (*App) CheckAccountLockout added in v0.8.0

func (app *App) CheckAccountLockout(ctx context.Context, username string) (bool, error)

checkAccountLockout checks if an account is locked and returns true if locked, false otherwise. If the lockout has expired, it clears the lockout.

func (*App) ClearLoginAttempts added in v0.8.0

func (app *App) ClearLoginAttempts(ctx context.Context, username string) error

clearLoginAttempts clears failed login attempts for a username (called on successful login).

func (*App) GetUser added in v0.8.0

func (app *App) GetUser(ctx context.Context, username string) (*session.User, error)

getUser retrieves the stored user details from the database for authentication. It returns a session.User struct containing the username and the stored password hash.

func (*App) ImagesDir added in v0.8.0

func (app *App) ImagesDir() string

ImagesDir returns the current images directory path.

func (*App) IncrementETag

func (app *App) IncrementETag() (string, error)

IncrementETag loads current ETag, increments it, saves to database, and returns new value.

func (*App) InitForBatchLoad added in v0.3.0

func (app *App) InitForBatchLoad(opt getopt.Opt) error

InitForBatchLoad performs minimal initialization for cache batch load CLI. Sets root dir, opens DB pools, loads config, initializes HTTP cache, builds handler chain. No server start, no discovery, no worker pool.

func (*App) InitForIncrementETag

func (app *App) InitForIncrementETag(opt getopt.Opt) error

InitForIncrementETag initializes minimal app state for --increment-etag command. Similar to InitForUnlock, this sets up only what's needed for ETag operations.

func (*App) InitForUnlock

func (app *App) InitForUnlock() error

Run orchestrates the application startup sequence. It initializes the root directory, logging, database, configuration, and command-line parsing. It then starts the background worker pool and file discovery process before This is a minimal initialization that does not require config to be loaded.

func (*App) InvalidateHTTPCache added in v0.8.0

func (app *App) InvalidateHTTPCache()

invalidateHTTPCache clears all HTTP cache entries. Called when ETag version changes to avoid serving stale responses that may contain old cache-busting URLs.

func (*App) LogProfileLocation

func (app *App) LogProfileLocation()

LogProfileLocation logs the profile directory and stops the profiler if active. This should be called before shutdown to ensure profile location is logged to both console and file.

func (*App) RecordFailedLoginAttempt added in v0.8.0

func (app *App) RecordFailedLoginAttempt(ctx context.Context, username string) error

recordFailedLoginAttempt records a failed login attempt and locks the account after 3 failures.

func (*App) ResetStats added in v0.8.0

func (app *App) ResetStats()

ResetStats resets the file processing statistics counters.

func (*App) RestartRequired

func (app *App) RestartRequired() bool

RestartRequired reports whether a restart is required for pending configuration changes to take effect.

func (*App) Run

func (app *App) Run(minPoolWorkers, maxPoolWorkers int) error

func (*App) RunCacheBatchLoad added in v0.3.0

func (app *App) RunCacheBatchLoad() int

RunCacheBatchLoad runs the batch load and returns the exit code: 0 success, 1 error, 2 blocked.

func (*App) Serve

func (app *App) Serve() error

Serve initializes the session store and starts the HTTP server on the configured port. It runs until the server encounters a fatal error, a process restart is requested (which shuts down the server so Serve returns), or the app context is cancelled.

func (*App) ServerError added in v0.8.0

func (app *App) ServerError(w http.ResponseWriter, r *http.Request, err error)

serverError logs an error and sends a generic 500 Internal Server Error response to the client.

func (*App) SetPreloadEnabled added in v0.8.0

func (app *App) SetPreloadEnabled(enabled bool)

SetPreloadEnabled enables or disables the cache preload manager. Safe to call even if preloadManager is nil (logs a warning).

func (*App) SetRestartRequired added in v0.8.0

func (app *App) SetRestartRequired(b bool)

SetRestartRequired marks the application as needing a restart for configuration changes to take effect.

func (*App) Shutdown

func (app *App) Shutdown()

Shutdown gracefully shuts down the application. It drains the WriteBatcher first, then cancels the main context, waits for background goroutines and the worker pool to finish, closes database connections, and closes the log file. Shutdown gracefully stops all background goroutines, closes the write batcher, database pools, and logger. It is safe to call multiple times.

func (*App) StartCacheBatchLoad added in v0.8.0

func (app *App) StartCacheBatchLoad() (interfaces.StartCacheBatchLoadResult, error)

StartCacheBatchLoad attempts to start cache batch load. Returns blocked=true when discovery is active (caller should return 409). Starts the run in a goroutine on success.

func (*App) TriggerDiscovery added in v0.8.0

func (app *App) TriggerDiscovery()

walkImageDir starts a background process to recursively scan the images directory. It delegates to files.WalkImageDir with app-specific deps. Updates module_state for "discovery" so batch load can guard against concurrent discovery.

func (*App) UnlockAccount

func (app *App) UnlockAccount(username string) error

UnlockAccount unlocks a locked account by clearing failed attempts and removing the lockout.

func (*App) UpdateConfigWithPrecedence added in v0.7.0

func (app *App) UpdateConfigWithPrecedence(c *config.Config, changedFields []string)

func (*App) UpdatePassword added in v0.8.0

func (app *App) UpdatePassword(ctx context.Context, passwordHash string) error

UpdatePassword updates the admin password hash in the config table. Uses gallerydb-generated queries (no inline SQL).

func (*App) UpdateUsername added in v0.8.0

func (app *App) UpdateUsername(ctx context.Context, username string) error

UpdateUsername updates the admin username in the config table. Uses gallerydb-generated queries (no inline SQL).

type AuthService added in v0.8.0

type AuthService struct {
	// contains filtered or unexported fields
}

AuthService owns session management, authentication, and CSRF.

func NewAuthService added in v0.8.0

func NewAuthService(sessionSecret string) *AuthService

func (*AuthService) CSRFTokenForPage added in v0.8.0

func (s *AuthService) CSRFTokenForPage(w http.ResponseWriter, r *http.Request, authenticated bool) string

func (*AuthService) CheckAccountLockout added in v0.8.0

func (s *AuthService) CheckAccountLockout(ctx context.Context, username string, pool *dbconnpool.DbSQLConnPool) (bool, error)

func (*AuthService) ClearLoginAttempts added in v0.8.0

func (s *AuthService) ClearLoginAttempts(ctx context.Context, username string, pool *dbconnpool.DbSQLConnPool) error

func (*AuthService) EnsureCSRFToken added in v0.8.0

func (s *AuthService) EnsureCSRFToken(w http.ResponseWriter, r *http.Request) string

func (*AuthService) EnsureSession added in v0.8.0

func (s *AuthService) EnsureSession(getOptionsConfig func() *session.OptionsConfig)

func (*AuthService) GetAdminUsername added in v0.8.0

func (s *AuthService) GetAdminUsername(ctx context.Context, pool *dbconnpool.DbSQLConnPool) (string, error)

func (*AuthService) GetEffectiveTheme added in v0.8.0

func (s *AuthService) GetEffectiveTheme(r *http.Request, getThemes func() []string, defaultTheme string) string

func (*AuthService) GetUser added in v0.8.0

func (s *AuthService) GetUser(ctx context.Context, username string, roPool, rwPool *dbconnpool.DbSQLConnPool) (*session.User, error)

func (*AuthService) IsAuthenticated added in v0.8.0

func (s *AuthService) IsAuthenticated(w http.ResponseWriter, r *http.Request) bool

func (*AuthService) RecordFailedLoginAttempt added in v0.8.0

func (s *AuthService) RecordFailedLoginAttempt(ctx context.Context, username string,
	pool *dbconnpool.DbSQLConnPool, lockoutDuration int64,
	sched *scheduler.Scheduler,
	unlockFn func(ctx context.Context, username string) error,
) error

func (*AuthService) UnlockAccountFromTask added in v0.8.0

func (s *AuthService) UnlockAccountFromTask(ctx context.Context, username string, pool *dbconnpool.DbSQLConnPool) error

type BatchedWrite

type BatchedWrite struct {
	File       *files.File               // File metadata + EXIF + thumbnails
	CacheEntry *cachelite.HTTPCacheEntry // HTTP cache entries
}

BatchedWrite is a union type for all high-volume database writes. Exactly one field should be non-nil per instance.

func (*BatchedWrite) GobDecode added in v0.3.0

func (bw *BatchedWrite) GobDecode(data []byte) error

GobDecode deserializes BatchedWrite from the gob-safe wire format, reconstructing the files.File (including its Thumbnail) and cache entry from their separately-encoded blobs.

func (BatchedWrite) GobEncode added in v0.3.0

func (bw BatchedWrite) GobEncode() ([]byte, error)

GobEncode serializes BatchedWrite into a gob-safe wire format. Since files.File now has its own GobEncode/GobDecode handling the *bytes.Buffer Thumbnail, we can encode it directly without copying or mutating the caller's object.

func (BatchedWrite) Size

func (bw BatchedWrite) Size() int64

Size returns estimated memory cost in bytes for batch size limiting.

type ConfigManager added in v0.8.0

type ConfigManager struct {
	// contains filtered or unexported fields
}

ConfigManager owns application configuration state and ConfigService.

func NewConfigManager added in v0.8.0

func NewConfigManager() *ConfigManager

func (*ConfigManager) GetConfig added in v0.8.0

func (m *ConfigManager) GetConfig() *config.Config

func (*ConfigManager) GetETagVersion added in v0.8.0

func (m *ConfigManager) GetETagVersion() string

func (*ConfigManager) SetConfig added in v0.8.0

func (m *ConfigManager) SetConfig(cfg *config.Config)

func (*ConfigManager) SetConfigService added in v0.8.0

func (m *ConfigManager) SetConfigService(svc config.ConfigService)

func (*ConfigManager) UpdateConfigWithPrecedence added in v0.8.0

func (m *ConfigManager) UpdateConfigWithPrecedence(cfg *config.Config, changedFields []string, opt getopt.Opt)

type GalleryStats

type GalleryStats struct {
	Folders        string
	Images         string
	ImagesSize     int64
	FirstDiscovery string
	LastDiscovery  string
}

GalleryStats holds statistics about the gallery for display in the about modal.

type HandlerManager added in v0.8.0

type HandlerManager struct {
	// contains filtered or unexported fields
}

func NewHandlerManager added in v0.8.0

func NewHandlerManager() *HandlerManager

func (*HandlerManager) Build added in v0.8.0

func (m *HandlerManager) Build(
	templateFS fs.FS,
	app interfaces.ServerDeps,
	authSvc auth.AuthService,
	sm session.SessionManager,
	dbRoPool, dbRwPool *dbconnpool.DbSQLConnPool,
	ctx context.Context,
	configService config.ConfigService,
	getETagVersion func() string,
	metricsCollector *metrics.Collector,
) error

Build creates all handler instances using ServerDeps.

func (*HandlerManager) SetPreloadService added in v0.8.0

func (m *HandlerManager) SetPreloadService(pm cachepreload.PreloadService)

type InfrastructureService added in v0.8.0

type InfrastructureService struct {
	ImporterFactory func(conn *sql.Conn, q *gallerydb.CustomQueries) files.Importer
	// contains filtered or unexported fields
}

InfrastructureService owns database pools, HTTP cache, write batcher, and file-system paths. No context is stored — ctx is received as a parameter where needed.

func NewInfrastructureService added in v0.8.0

func NewInfrastructureService() *InfrastructureService

func (*InfrastructureService) CacheMW added in v0.8.0

func (*InfrastructureService) DBRoPool added in v0.8.0

func (*InfrastructureService) DBRwPool added in v0.8.0

func (*InfrastructureService) GetConfigQueries added in v0.8.0

func (s *InfrastructureService) GetConfigQueries(cpc *dbconnpool.CpConn) config.ConfigQueries

func (*InfrastructureService) GetHandlerQueries added in v0.8.0

func (*InfrastructureService) GetMetadataQueries added in v0.8.0

func (*InfrastructureService) IncrementETag added in v0.8.0

func (s *InfrastructureService) IncrementETag(ctx context.Context, cfgService config.ConfigService) (string, error)

func (*InfrastructureService) InitializeHTTPCache added in v0.8.0

func (s *InfrastructureService) InitializeHTTPCache(config *config.Config)

func (*InfrastructureService) InvalidateHTTPCache added in v0.8.0

func (s *InfrastructureService) InvalidateHTTPCache()

func (*InfrastructureService) ReconfigurePools added in v0.8.0

func (s *InfrastructureService) ReconfigurePools(ctx context.Context, config *config.Config) error

ReconfigurePools recreates database pools from loaded config.

func (*InfrastructureService) SetCacheOnGalleryHit added in v0.8.0

func (s *InfrastructureService) SetCacheOnGalleryHit(fn func(ctx context.Context, folderID int64, sessionID, acceptEncoding string))

SetCacheOnGalleryHit replaces the OnGalleryCacheHit callback (wired by SubsystemManager after preloadManager is created).

func (*InfrastructureService) SetupDB added in v0.8.0

func (s *InfrastructureService) SetupDB(ctx context.Context, config *config.Config)

SetupDB creates database pools, write batcher, cache store, and cache size counter. Called early in startup before config is loaded.

func (*InfrastructureService) Shutdown added in v0.8.0

func (s *InfrastructureService) Shutdown()

Shutdown closes the write batcher. The real writeBatcher.Close error branch is unreachable in production because WriteBatcher.Close always returns nil; it is exercised via testHookShutdownWriteBatcher.

func (*InfrastructureService) WriteBatcher added in v0.8.0

type MemoryReclaimerConfig

type MemoryReclaimerConfig struct {
	InitialDelay  time.Duration
	CheckInterval time.Duration
	IdleThreshold time.Duration
	FreeMemFunc   func()
}

MemoryReclaimerConfig holds the configuration for the memory reclaimer.

type RuntimeManager added in v0.8.0

type RuntimeManager struct {
	// contains filtered or unexported fields
}

RuntimeManager owns application lifecycle, HTTP server, and restart state.

func NewRuntimeManager added in v0.8.0

func NewRuntimeManager(parent context.Context) *RuntimeManager

func (*RuntimeManager) ExecRestart added in v0.8.0

func (m *RuntimeManager) ExecRestart()

func (*RuntimeManager) GetGalleryStatsCached added in v0.8.0

func (m *RuntimeManager) GetGalleryStatsCached(discoveryLastStartedAt int64) *GalleryStats

func (*RuntimeManager) IsRestartRequested added in v0.8.0

func (m *RuntimeManager) IsRestartRequested() bool

func (*RuntimeManager) RestartRequired added in v0.8.0

func (m *RuntimeManager) RestartRequired() bool

func (*RuntimeManager) Serve added in v0.8.0

func (m *RuntimeManager) Serve(handler http.Handler, addr string) error

func (*RuntimeManager) SetGalleryStatsCache added in v0.8.0

func (m *RuntimeManager) SetGalleryStatsCache(stats *GalleryStats, at int64)

func (*RuntimeManager) SetRestartRequired added in v0.8.0

func (m *RuntimeManager) SetRestartRequired(b bool)

func (*RuntimeManager) TriggerRestart added in v0.8.0

func (m *RuntimeManager) TriggerRestart()

type SubsystemManager added in v0.8.0

type SubsystemManager struct {
	// contains filtered or unexported fields
}

SubsystemManager owns background processing subsystems.

func NewSubsystemManager added in v0.8.0

func NewSubsystemManager(infra *InfrastructureService) *SubsystemManager

func (*SubsystemManager) ResetStats added in v0.8.0

func (m *SubsystemManager) ResetStats()

func (*SubsystemManager) SetPreloadEnabled added in v0.8.0

func (m *SubsystemManager) SetPreloadEnabled(enabled bool)

func (*SubsystemManager) Shutdown added in v0.8.0

func (m *SubsystemManager) Shutdown()

func (*SubsystemManager) Start added in v0.8.0

func (m *SubsystemManager) Start(
	ctx context.Context,
	cfg *config.Config,
	minPoolWorkers, maxPoolWorkers int,
	imagesDir, normalizedImagesDir string,
	removeImagesDirPrefixFn func(string, string) (string, error),
	getRouter func() http.Handler,
	getHandlerQueries func(*dbconnpool.CpConn) interfaces.HandlerQueries,
	getETagVersion func() string,
)

Start creates all subsystems from config. Call after config is loaded and imagesDir is set but before handler building.

func (*SubsystemManager) StartCacheBatchLoad added in v0.8.0

func (*SubsystemManager) StartPool added in v0.8.0

func (m *SubsystemManager) StartPool(ctx context.Context, poolDone chan struct{}, normalizedImagesDir string, removeImagesDirPrefixFn func(string, string) (string, error), processor files.FileProcessor)

StartPool launches the worker pool goroutine.

func (*SubsystemManager) WireMetrics added in v0.8.0

func (m *SubsystemManager) WireMetrics(collector *metrics.Collector)

Directories

Path Synopsis
Package auth provides authentication services for the application.
Package auth provides authentication services for the application.
Package cachebatch provides batch cache loading with bounded concurrency.
Package cachebatch provides batch cache loading with bounded concurrency.
Package cachepreload provides cache preloading when folders are opened.
Package cachepreload provides cache preloading when folders are opened.
Package compress provides pure functions for content encoding negotiation and compression decision making.
Package compress provides pure functions for content encoding negotiation and compression decision making.
Package conditional provides pure functions for HTTP conditional request matching.
Package conditional provides pure functions for HTTP conditional request matching.
Package files provides file discovery, metadata extraction, and thumbnail generation for the photo gallery.
Package files provides file discovery, metadata extraction, and thumbnail generation for the photo gallery.
Package handlers provides HTTP request handlers for the web application.
Package handlers provides HTTP request handlers for the web application.
Package interfaces holds shared contracts consumed by both the server orchestrator (App) and the handlers package.
Package interfaces holds shared contracts consumed by both the server orchestrator (App) and the handlers package.
Package metrics provides centralized metrics collection for the dashboard.
Package metrics provides centralized metrics collection for the dashboard.
Package pathutil provides path manipulation utilities for the server package.
Package pathutil provides path manipulation utilities for the server package.
Package security provides pure functions for security and lockout calculations.
Package security provides pure functions for security and lockout calculations.
Package session provides session store, CSRF token handling, and session cookie options for the web application.
Package session provides session store, CSRF token handling, and session cookie options for the web application.
Package template provides pure functions for building template data maps.
Package template provides pure functions for building template data maps.
Package ui provides HTML template rendering and cache version management for the application's user interface.
Package ui provides HTML template rendering and cache version management for the application's user interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL