1
Fork 0

Refactor handling of environment variables

This commit is contained in:
viktorstrate 2021-01-17 16:50:48 +01:00
parent 9098bf38d1
commit 107da91700
No known key found for this signature in database
GPG Key ID: 3F855605109C1E8A
15 changed files with 105 additions and 41 deletions

2
.gitignore vendored
View File

@ -1,7 +1,7 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
cache/
photo_cache/
media_cache/
/photos_path
photoview.db

View File

@ -2,13 +2,14 @@ package database
import (
"context"
"fmt"
"log"
"net/url"
"os"
"time"
"github.com/photoview/photoview/api/database/drivers"
"github.com/photoview/photoview/api/graphql/models"
"github.com/photoview/photoview/api/utils"
"github.com/pkg/errors"
"gorm.io/driver/mysql"
@ -18,13 +19,14 @@ import (
)
func getMysqlAddress() (*url.URL, error) {
address, err := url.Parse(os.Getenv("PHOTOVIEW_MYSQL_URL"))
if err != nil {
return nil, errors.Wrap(err, "Could not parse mysql url")
addressString := utils.EnvMysqlURL.GetValue()
if addressString == "" {
return nil, errors.New(fmt.Sprintf("Environment variable %s missing, exiting", utils.EnvMysqlURL.GetName()))
}
if address.String() == "" {
return nil, errors.New("Environment variable PHOTOVIEW_MYSQL_URL missing, exiting")
address, err := url.Parse(addressString)
if err != nil {
return nil, errors.Wrap(err, "Could not parse mysql url")
}
queryValues := address.Query()
@ -36,7 +38,7 @@ func getMysqlAddress() (*url.URL, error) {
}
func getSqliteAddress() (*url.URL, error) {
path := os.Getenv("PHOTOVIEW_SQLITE_PATH")
path := utils.EnvSqlitePath.GetValue()
if path == "" {
path = "photoview.db"
}
@ -62,8 +64,12 @@ func SetupDatabase() (*gorm.DB, error) {
config := gorm.Config{}
// Enable database debug logging
// Configure database logging
if utils.DevelopmentMode() {
config.Logger = logger.Default.LogMode(logger.Info)
} else {
config.Logger = logger.Default.LogMode(logger.Warn)
}
var databaseDialect gorm.Dialector
switch drivers.DatabaseDriver() {

View File

@ -1,10 +1,12 @@
package drivers
import (
"os"
"strings"
"github.com/photoview/photoview/api/utils"
)
// DatabaseDriverType represents the name of a database driver
type DatabaseDriverType string
const (
@ -15,7 +17,7 @@ const (
func DatabaseDriver() DatabaseDriverType {
var driver DatabaseDriverType
driverString := strings.ToLower(os.Getenv("PHOTOVIEW_DATABASE_DRIVER"))
driverString := strings.ToLower(utils.EnvDatabaseDriver.GetValue())
switch driverString {
case "mysql":

View File

@ -13,6 +13,9 @@ PHOTOVIEW_LISTEN_PORT=4001
PHOTOVIEW_API_ENDPOINT=http://localhost:4001/
PHOTOVIEW_UI_ENDPOINT=http://localhost:1234/
# Path where media should be cached, defaults to ./media_cache
# PHOTOVIEW_MEDIA_CACHE=./media_cache
# Set to 1 for the server to also serve the built static ui files
PHOTOVIEW_SERVE_UI=0
# When PHOTOVIEW_SERVE_UI is 1, PHOTOVIEW_PUBLIC_ENDPOINT is used instead of PHOTOVIEW_API_ENDPOINT and PHOTOVIEW_UI_ENDPOINT

View File

@ -20,6 +20,10 @@ func (r *queryResolver) MyAlbums(ctx context.Context, filter *models.Filter, onl
return nil, err
}
if len(user.Albums) == 0 {
return nil, nil
}
userAlbumIDs := make([]int, len(user.Albums))
for i, album := range user.Albums {
userAlbumIDs[i] = album.ID

View File

@ -335,7 +335,7 @@ func (r *mutationResolver) UserRemoveRootAlbum(ctx context.Context, userID int,
if deletedAlbumIDs != nil {
// Delete albums from cache
for _, id := range deletedAlbumIDs {
cacheAlbumPath := path.Join(scanner.PhotoCache(), strconv.Itoa(id))
cacheAlbumPath := path.Join(scanner.MediaCachePath(), strconv.Itoa(id))
if err := os.RemoveAll(cacheAlbumPath); err != nil {
return nil, err

View File

@ -41,7 +41,7 @@ func RegisterPhotoRoutes(db *gorm.DB, router *mux.Router) {
var cachedPath string
if mediaURL.Purpose == models.PhotoThumbnail || mediaURL.Purpose == models.PhotoHighRes || mediaURL.Purpose == models.VideoThumbnail {
cachedPath = path.Join(scanner.PhotoCache(), strconv.Itoa(int(media.AlbumID)), strconv.Itoa(int(mediaURL.MediaID)), mediaURL.MediaName)
cachedPath = path.Join(scanner.MediaCachePath(), strconv.Itoa(int(media.AlbumID)), strconv.Itoa(int(mediaURL.MediaID)), mediaURL.MediaName)
} else if mediaURL.Purpose == models.MediaOriginal {
cachedPath = media.Path
} else {

View File

@ -40,7 +40,7 @@ func RegisterVideoRoutes(db *gorm.DB, router *mux.Router) {
var cachedPath string
if mediaURL.Purpose == models.VideoWeb {
cachedPath = path.Join(scanner.PhotoCache(), strconv.Itoa(int(media.AlbumID)), strconv.Itoa(int(mediaURL.MediaID)), mediaURL.MediaName)
cachedPath = path.Join(scanner.MediaCachePath(), strconv.Itoa(int(media.AlbumID)), strconv.Itoa(int(mediaURL.MediaID)), mediaURL.MediaName)
} else {
log.Printf("ERROR: Can not handle media_purpose for video: %s\n", mediaURL.Purpose)
w.WriteHeader(http.StatusInternalServerError)

View File

@ -36,7 +36,7 @@ func CleanupMedia(db *gorm.DB, albumId int, albumMedia []*models.Media) []error
for _, media := range mediaList {
mediaIDs = append(mediaIDs, media.ID)
cachePath := path.Join(PhotoCache(), strconv.Itoa(int(albumId)), strconv.Itoa(int(media.ID)))
cachePath := path.Join(MediaCachePath(), strconv.Itoa(int(albumId)), strconv.Itoa(int(media.ID)))
err := os.RemoveAll(cachePath)
if err != nil {
deleteErrors = append(deleteErrors, errors.Wrapf(err, "delete unused cache folder (%s)", cachePath))
@ -84,7 +84,7 @@ func deleteOldUserAlbums(db *gorm.DB, scannedAlbums []*models.Album, user *model
deleteAlbumIDs := make([]int, len(albums))
for i, album := range albums {
deleteAlbumIDs[i] = album.ID
cachePath := path.Join(PhotoCache(), strconv.Itoa(int(album.ID)))
cachePath := path.Join(MediaCachePath(), strconv.Itoa(int(album.ID)))
err := os.RemoveAll(cachePath)
if err != nil {
deleteErrors = append(deleteErrors, errors.Wrapf(err, "delete unused cache folder (%s)", cachePath))

View File

@ -202,14 +202,14 @@ func processPhoto(tx *gorm.DB, imageData *EncodeMediaData, photoCachePath *strin
func makeMediaCacheDir(media *models.Media) (*string, error) {
// Make root cache dir if not exists
if _, err := os.Stat(PhotoCache()); os.IsNotExist(err) {
if err := os.Mkdir(PhotoCache(), os.ModePerm); err != nil {
if _, err := os.Stat(MediaCachePath()); os.IsNotExist(err) {
if err := os.Mkdir(MediaCachePath(), os.ModePerm); err != nil {
return nil, errors.Wrap(err, "could not make root image cache directory")
}
}
// Make album cache dir if not exists
albumCachePath := path.Join(PhotoCache(), strconv.Itoa(int(media.AlbumID)))
albumCachePath := path.Join(MediaCachePath(), strconv.Itoa(int(media.AlbumID)))
if _, err := os.Stat(albumCachePath); os.IsNotExist(err) {
if err := os.Mkdir(albumCachePath, os.ModePerm); err != nil {
return nil, errors.Wrap(err, "could not make album image cache directory")

View File

@ -207,10 +207,11 @@ func ScannerError(format string, args ...interface{}) {
})
}
func PhotoCache() string {
photoCache := os.Getenv("PHOTO_CACHE")
// MediaCachePath returns the path for where the media cache is located on the file system
func MediaCachePath() string {
photoCache := utils.EnvMediaCachePath.GetValue()
if photoCache == "" {
photoCache = "./photo_cache"
photoCache = "./media_cache"
}
return photoCache

View File

@ -3,7 +3,6 @@ package main
import (
"log"
"net/http"
"os"
"path"
"github.com/gorilla/handlers"
@ -29,7 +28,7 @@ func main() {
log.Println("No .env file found")
}
devMode := os.Getenv("PHOTOVIEW_DEVELOPMENT_MODE") == "1"
devMode := utils.DevelopmentMode()
db, err := database.SetupDatabase()
if err != nil {
@ -92,7 +91,7 @@ func main() {
videoRouter := endpointRouter.PathPrefix("/video").Subrouter()
routes.RegisterVideoRoutes(db, videoRouter)
shouldServeUI := os.Getenv("PHOTOVIEW_SERVE_UI") == "1"
shouldServeUI := utils.ShouldServeUI()
if shouldServeUI {
spa := routes.NewSpaHandler("/ui", "index.html")
@ -111,7 +110,7 @@ func main() {
log.Printf("Photoview UI public endpoint ready at %s\n", uiEndpoint.String())
if !shouldServeUI {
log.Printf("Notice: UI is not served by the the api (PHOTOVIEW_SERVE_UI=0)")
log.Printf("Notice: UI is not served by the the api (%s=0)", utils.EnvServeUI.GetName())
}
}

View File

@ -4,7 +4,6 @@ import (
"fmt"
"log"
"net/url"
"os"
"path"
"strconv"
)
@ -12,7 +11,7 @@ import (
func ApiListenUrl() *url.URL {
const defaultPort = "4001"
shouldServeUI := os.Getenv("PHOTOVIEW_SERVE_UI") == "1"
shouldServeUI := ShouldServeUI()
apiPrefix := "/"
if shouldServeUI {
@ -21,19 +20,19 @@ func ApiListenUrl() *url.URL {
var listenAddr string
listenAddr = os.Getenv("PHOTOVIEW_LISTEN_IP")
listenAddr = EnvListenIP.GetValue()
if listenAddr == "" {
listenAddr = "127.0.0.1"
}
listenPortStr := os.Getenv("PHOTOVIEW_LISTEN_PORT")
listenPortStr := EnvListenPort.GetValue()
if listenPortStr == "" {
listenPortStr = defaultPort
}
listenPort, err := strconv.Atoi(listenPortStr)
if err != nil {
log.Fatalf("PHOTOVIEW_LISTEN_PORT must be a number: '%s'\n%s", listenPortStr, err)
log.Fatalf("%s must be a number: '%s'\n%s", EnvListenPort.GetName(), listenPortStr, err)
}
apiUrl, err := url.Parse(fmt.Sprintf("http://%s:%d", listenAddr, listenPort))
@ -46,16 +45,16 @@ func ApiListenUrl() *url.URL {
}
func ApiEndpointUrl() *url.URL {
apiEndpointStr := os.Getenv("PHOTOVIEW_API_ENDPOINT")
apiEndpointStr := EnvAPIEndpoint.GetValue()
shouldServeUI := os.Getenv("PHOTOVIEW_SERVE_UI") == "1"
shouldServeUI := ShouldServeUI()
if shouldServeUI {
apiEndpointStr = os.Getenv("PHOTOVIEW_PUBLIC_ENDPOINT")
apiEndpointStr = EnvPublicEndpoint.GetValue()
}
apiEndpointUrl, err := url.Parse(apiEndpointStr)
if err != nil {
log.Fatalf("ERROR: Environment variable PHOTOVIEW_API_ENDPOINT is not a proper url")
log.Fatalf("ERROR: Environment variable %s is not a proper url (%s)", EnvAPIEndpoint.GetName(), EnvAPIEndpoint.GetValue())
}
if shouldServeUI {
@ -66,16 +65,16 @@ func ApiEndpointUrl() *url.URL {
}
func UiEndpointUrl() *url.URL {
uiEndpointStr := os.Getenv("PHOTOVIEW_UI_ENDPOINT")
uiEndpointStr := EnvUIEndpoint.GetValue()
shouldServeUI := os.Getenv("PHOTOVIEW_SERVE_UI") == "1"
shouldServeUI := ShouldServeUI()
if shouldServeUI {
uiEndpointStr = os.Getenv("PHOTOVIEW_PUBLIC_ENDPOINT")
uiEndpointStr = EnvPublicEndpoint.GetValue()
}
uiEndpointUrl, err := url.Parse(uiEndpointStr)
if err != nil {
log.Fatalf("ERROR: Environment variable PHOTOVIEW_UI_ENDPOINT is not a proper url")
log.Fatalf("ERROR: Environment variable %s is not a proper url (%s)", EnvUIEndpoint.GetName(), EnvUIEndpoint.GetValue())
}
return uiEndpointUrl

View File

@ -0,0 +1,50 @@
package utils
import "os"
// EnvironmentVariable represents the name of an environment variable used to configure Photoview
type EnvironmentVariable string
// General options
const (
EnvDevelopmentMode EnvironmentVariable = "PHOTOVIEW_DEVELOPMENT_MODE"
EnvServeUI EnvironmentVariable = "PHOTOVIEW_SERVE_UI"
EnvMediaCachePath EnvironmentVariable = "PHOTOVIEW_MEDIA_CACHE"
)
// Network related
const (
EnvListenIP EnvironmentVariable = "PHOTOVIEW_LISTEN_IP"
EnvListenPort EnvironmentVariable = "PHOTOVIEW_LISTEN_PORT"
EnvAPIEndpoint EnvironmentVariable = "PHOTOVIEW_API_ENDPOINT"
EnvUIEndpoint EnvironmentVariable = "PHOTOVIEW_UI_ENDPOINT"
EnvPublicEndpoint EnvironmentVariable = "PHOTOVIEW_PUBLIC_ENDPOINT"
)
// Database related
const (
EnvDatabaseDriver EnvironmentVariable = "PHOTOVIEW_DATABASE_DRIVER"
EnvMysqlURL EnvironmentVariable = "PHOTOVIEW_MYSQL_URL"
EnvSqlitePath EnvironmentVariable = "PHOTOVIEW_SQLITE_PATH"
)
// GetName returns the name of the environment variable itself
func (v EnvironmentVariable) GetName() string {
return string(v)
}
// GetValue returns the value of the environment
func (v EnvironmentVariable) GetValue() string {
return os.Getenv(string(v))
}
// ShouldServeUI whether or not the "serve ui" option is enabled
func ShouldServeUI() bool {
return EnvServeUI.GetValue() == "1"
}
// DevelopmentMode describes whether or not the server is running in development mode,
// and should thus print debug informations and enable other features related to developing.
func DevelopmentMode() bool {
return EnvDevelopmentMode.GetValue() == "1"
}

View File

@ -24,7 +24,7 @@ services:
- PHOTOVIEW_MYSQL_URL=photoview:photosecret@tcp(db)/photoview
- PHOTOVIEW_LISTEN_IP=photoview
- PHOTOVIEW_LISTEN_PORT=80
- PHOTO_CACHE=/app/cache
- PHOTOVIEW_MEDIA_CACHE=/app/cache
# Change This: The publicly exposed url
# For example if the server is available from the domain example.com,