1
Fork 0

Start on migrating database integration to gorm

This commit is contained in:
viktorstrate 2020-11-23 19:39:44 +01:00
parent 8781ab3777
commit 27b2f95a7b
19 changed files with 214 additions and 197 deletions

View File

@ -11,7 +11,9 @@
"mode": "auto",
"program": "${workspaceRoot}/server.go",
"cwd": "${workspaceRoot}",
"env": {},
"env": {
"PATH": "${env:PATH}:/Applications/darktable.app/Contents/MacOS/"
},
"args": []
}
]

View File

@ -1,27 +1,19 @@
package database
import (
"context"
"database/sql"
"log"
"net/url"
"os"
"time"
"github.com/pkg/errors"
"github.com/viktorstrate/photoview/api/graphql/models"
// Load mysql driver
_ "github.com/go-sql-driver/mysql"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database/mysql"
// Migrate from file
_ "github.com/golang-migrate/migrate/source/file"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// SetupDatabase connects to the database using environment variables
func SetupDatabase() (*sql.DB, error) {
func SetupDatabase() (*gorm.DB, error) {
address, err := url.Parse(os.Getenv("MYSQL_URL"))
if err != nil {
@ -40,62 +32,46 @@ func SetupDatabase() (*sql.DB, error) {
log.Printf("Connecting to database: %s", address)
var db *sql.DB
db, err = sql.Open("mysql", address.String())
db, err := gorm.Open(mysql.Open(address.String()), &gorm.Config{})
if err != nil {
return nil, errors.New("Could not connect to database, exiting")
return nil, errors.Wrap(err, "could not connect to database")
}
tryCount := 0
// var db *sql.DB
for {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// db, err = sql.Open("mysql", address.String())
// if err != nil {
// return nil, errors.New("Could not connect to database, exiting")
// }
if err := db.PingContext(ctx); err != nil {
if tryCount < 4 {
tryCount++
log.Printf("WARN: Could not ping database: %s, Will retry after 1 second", err)
time.Sleep(time.Second)
continue
} else {
return nil, errors.Wrap(err, "Could not ping database, exiting")
}
}
// tryCount := 0
break
}
// for {
// ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
// defer cancel()
db.SetMaxOpenConns(80)
// if err := db.PingContext(ctx); err != nil {
// if tryCount < 4 {
// tryCount++
// log.Printf("WARN: Could not ping database: %s, Will retry after 1 second", err)
// time.Sleep(time.Second)
// continue
// } else {
// return nil, errors.Wrap(err, "Could not ping database, exiting")
// }
// }
// break
// }
// db.SetMaxOpenConns(80)
return db, nil
}
func MigrateDatabase(db *sql.DB) error {
driver, err := mysql.WithInstance(db, &mysql.Config{})
if err != nil {
return err
}
func MigrateDatabase(db *gorm.DB) error {
m, err := migrate.NewWithDatabaseInstance(
"file://database/migrations",
"mysql",
driver,
)
if err != nil {
return err
}
if err := m.Up(); err != nil {
if err.Error() == "no change" {
log.Println("Database is up to date")
} else {
return err
}
} else {
log.Println("Database migrated")
}
db.AutoMigrate(&models.User{}, &models.AccessToken{})
return nil
}

View File

@ -31,4 +31,6 @@ require (
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd // indirect
gopkg.in/vansante/go-ffprobe.v2 v2.0.2
gopkg.in/yaml.v2 v2.3.0 // indirect
gorm.io/driver/mysql v1.0.3
gorm.io/gorm v1.20.7
)

View File

@ -58,6 +58,10 @@ github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCO
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -176,5 +180,10 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg=
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.7 h1:rMS4CL3pNmYq1V5/X+nHHjh1Dx6dnf27+Cai5zabo+M=
gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=

View File

@ -2,7 +2,6 @@ package auth
import (
"context"
"database/sql"
"errors"
"log"
"net/http"
@ -10,6 +9,7 @@ import (
"github.com/99designs/gqlgen/handler"
"github.com/viktorstrate/photoview/api/graphql/models"
"gorm.io/gorm"
)
var ErrUnauthorized = errors.New("unauthorized")
@ -23,7 +23,7 @@ type contextKey struct {
}
// Middleware decodes the share session cookie and packs the session into context
func Middleware(db *sql.DB) func(http.Handler) http.Handler {
func Middleware(db *gorm.DB) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -66,7 +66,7 @@ func UserFromContext(ctx context.Context) *models.User {
return raw
}
func AuthWebsocketInit(db *sql.DB) func(context.Context, handler.InitPayload) (context.Context, error) {
func AuthWebsocketInit(db *gorm.DB) func(context.Context, handler.InitPayload) (context.Context, error) {
return func(ctx context.Context, initPayload handler.InitPayload) (context.Context, error) {
bearer, exists := initPayload["Authorization"].(string)

View File

@ -2,14 +2,14 @@ package api
import (
"context"
"database/sql"
"errors"
"github.com/99designs/gqlgen/graphql"
"github.com/viktorstrate/photoview/api/graphql/auth"
"gorm.io/gorm"
)
func IsAdmin(database *sql.DB) func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
func IsAdmin(database *gorm.DB) func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
return func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
user := auth.UserFromContext(ctx)

View File

@ -1,48 +1,59 @@
package models
import (
"database/sql"
"github.com/pkg/errors"
"gorm.io/gorm"
)
func initializeSiteInfoRow(db *sql.DB) (*SiteInfo, error) {
_, err := db.Exec("INSERT INTO site_info (initial_setup, periodic_scan_interval, concurrent_workers) VALUES (true, 0, 3)")
if err != nil {
return nil, errors.Wrap(err, "initialize site_info row")
}
// func initializeSiteInfoRow(db *gorm.DB) (*SiteInfo, error) {
// _, err := db.Exec("INSERT INTO site_info (initial_setup, periodic_scan_interval, concurrent_workers) VALUES (true, 0, 3)")
// if err != nil {
// return nil, errors.Wrap(err, "initialize site_info row")
// }
siteInfo := &SiteInfo{}
// siteInfo := &SiteInfo{}
row := db.QueryRow("SELECT * FROM site_info")
if err := row.Scan(&siteInfo.InitialSetup, &siteInfo.PeriodicScanInterval, &siteInfo.ConcurrentWorkers); err != nil {
return nil, errors.Wrap(err, "get site_info row after initialization")
}
// row := db.QueryRow("SELECT * FROM site_info")
// if err := row.Scan(&siteInfo.InitialSetup, &siteInfo.PeriodicScanInterval, &siteInfo.ConcurrentWorkers); err != nil {
// return nil, errors.Wrap(err, "get site_info row after initialization")
// }
return siteInfo, nil
}
// return siteInfo, nil
// }
// GetSiteInfo gets the site info row from the database, and creates it if it does not exist
func GetSiteInfo(db *sql.DB) (*SiteInfo, error) {
rows, err := db.Query("SELECT * FROM site_info")
defer rows.Close()
if err != nil {
return nil, err
func GetSiteInfo(db *gorm.DB) (*SiteInfo, error) {
var siteInfo SiteInfo
result := db.FirstOrCreate(&siteInfo, SiteInfo{
InitialSetup: true,
PeriodicScanInterval: 0,
ConcurrentWorkers: 3,
})
if result.Error != nil {
return nil, errors.Wrap(result.Error, "get site info from database")
}
siteInfo := &SiteInfo{}
// rows, err := db.Query("SELECT * FROM site_info")
// defer rows.Close()
// if err != nil {
// return nil, err
// }
if !rows.Next() {
// Entry does not exist
siteInfo, err = initializeSiteInfoRow(db)
if err != nil {
return nil, err
}
} else {
if err := rows.Scan(&siteInfo.InitialSetup, &siteInfo.PeriodicScanInterval, &siteInfo.ConcurrentWorkers); err != nil {
return nil, err
}
}
// siteInfo := &SiteInfo{}
return siteInfo, nil
// if !rows.Next() {
// // Entry does not exist
// siteInfo, err = initializeSiteInfoRow(db)
// if err != nil {
// return nil, err
// }
// } else {
// if err := rows.Scan(&siteInfo.InitialSetup, &siteInfo.PeriodicScanInterval, &siteInfo.ConcurrentWorkers); err != nil {
// return nil, err
// }
// }
return &siteInfo, nil
}

View File

@ -2,7 +2,6 @@ package models
import (
"crypto/rand"
"database/sql"
"fmt"
"log"
"os"
@ -10,63 +9,68 @@ import (
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
type User struct {
UserID int
Username string
Password *string
RootPath string
Admin bool
gorm.Model
Username string `gorm:"unique,size:128"`
Password *string `gorm:"size:256`
RootPath string `gorm:"size:512`
Admin bool `gorm:"default:false"`
}
func (u *User) ID() int {
return u.UserID
}
// func (u *User) ID() int {
// return u.UserID
// }
type AccessToken struct {
Value string
gorm.Model
UserID uint
User User `gorm:"constraint:OnDelete:CASCADE;"`
Value string `gorm:"size:24`
Expire time.Time
}
var ErrorInvalidUserCredentials = errors.New("invalid credentials")
func NewUserFromRow(row *sql.Row) (*User, error) {
user := User{}
// func NewUserFromRow(row *sql.Row) (*User, error) {
// user := User{}
if err := row.Scan(&user.UserID, &user.Username, &user.Password, &user.RootPath, &user.Admin); err != nil {
return nil, errors.Wrap(err, "failed to scan user from database")
}
// if err := row.Scan(&user.UserID, &user.Username, &user.Password, &user.RootPath, &user.Admin); err != nil {
// return nil, errors.Wrap(err, "failed to scan user from database")
// }
return &user, nil
}
// return &user, nil
// }
func NewUsersFromRows(rows *sql.Rows) ([]*User, error) {
users := make([]*User, 0)
// func NewUsersFromRows(rows *sql.Rows) ([]*User, error) {
// users := make([]*User, 0)
for rows.Next() {
var user User
if err := rows.Scan(&user.UserID, &user.Username, &user.Password, &user.RootPath, &user.Admin); err != nil {
return nil, errors.Wrap(err, "failed to scan users from database")
}
users = append(users, &user)
}
// for rows.Next() {
// var user User
// if err := rows.Scan(&user.UserID, &user.Username, &user.Password, &user.RootPath, &user.Admin); err != nil {
// return nil, errors.Wrap(err, "failed to scan users from database")
// }
// users = append(users, &user)
// }
rows.Close()
// rows.Close()
return users, nil
}
// return users, nil
// }
func AuthorizeUser(database *sql.DB, username string, password string) (*User, error) {
row := database.QueryRow("SELECT * FROM user WHERE username = ?", username)
func AuthorizeUser(db *gorm.DB, username string, password string) (*User, error) {
// row := database.QueryRow("SELECT * FROM user WHERE username = ?", username)
user, err := NewUserFromRow(row)
if err != nil {
if err == sql.ErrNoRows {
var user User
result := db.Where("username = ?", username).First(&user)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, ErrorInvalidUserCredentials
} else {
return nil, err
}
return nil, errors.Wrap(result.Error, "failed to get user by username when authorizing")
}
if user.Password == nil {
@ -81,7 +85,7 @@ func AuthorizeUser(database *sql.DB, username string, password string) (*User, e
}
}
return user, nil
return &user, nil
}
var ErrorInvalidRootPath = errors.New("invalid root path")
@ -96,11 +100,17 @@ func ValidRootPath(rootPath string) bool {
return true
}
func RegisterUser(database *sql.Tx, username string, password *string, rootPath string, admin bool) (*User, error) {
func RegisterUser(db *gorm.DB, username string, password *string, rootPath string, admin bool) (*User, error) {
if !ValidRootPath(rootPath) {
return nil, ErrorInvalidRootPath
}
user := User{
Username: username,
RootPath: rootPath,
Admin: admin,
}
if password != nil {
hashedPassBytes, err := bcrypt.GenerateFromPassword([]byte(*password), 12)
if err != nil {
@ -108,29 +118,18 @@ func RegisterUser(database *sql.Tx, username string, password *string, rootPath
}
hashedPass := string(hashedPassBytes)
if _, err := database.Exec("INSERT INTO user (username, password, root_path, admin) VALUES (?, ?, ?, ?)", username, hashedPass, rootPath, admin); err != nil {
return nil, errors.Wrap(err, "insert new user with password into database")
}
} else {
if _, err := database.Exec("INSERT INTO user (username, root_path, admin) VALUES (?, ?, ?)", username, rootPath, admin); err != nil {
return nil, errors.Wrap(err, "insert user without password into database")
}
user.Password = &hashedPass
}
row := database.QueryRow("SELECT * FROM user WHERE username = ?", username)
if row == nil {
return nil, ErrorInvalidUserCredentials
result := db.Create(&user)
if result.Error != nil {
return nil, errors.Wrap(result.Error, "insert new user with password into database")
}
user, err := NewUserFromRow(row)
if err != nil {
return nil, err
}
return user, nil
return &user, nil
}
func (user *User) GenerateAccessToken(database *sql.Tx) (*AccessToken, error) {
func (user *User) GenerateAccessToken(db *gorm.DB) (*AccessToken, error) {
bytes := make([]byte, 24)
if _, err := rand.Read(bytes); err != nil {
return nil, errors.New(fmt.Sprintf("Could not generate token: %s\n", err.Error()))
@ -142,38 +141,56 @@ func (user *User) GenerateAccessToken(database *sql.Tx) (*AccessToken, error) {
token_value := string(bytes)
expire := time.Now().Add(14 * 24 * time.Hour)
expireString := expire.UTC().Format("2006-01-02 15:04:05")
// expireString := expire.UTC().Format("2006-01-02 15:04:05")
if _, err := database.Exec("INSERT INTO access_token (value, expire, user_id) VALUES (?, ?, ?)", token_value, expireString, user.UserID); err != nil {
return nil, err
}
// if _, err := database.Exec("INSERT INTO access_token (value, expire, user_id) VALUES (?, ?, ?)", token_value, expireString, user.UserID); err != nil {
// return nil, err
// }
token := AccessToken{
UserID: user.ID,
Value: token_value,
Expire: expire,
}
result := db.Create(&token)
if result.Error != nil {
return nil, errors.Wrap(result.Error, "saving access token to database")
}
return &token, nil
}
func VerifyTokenAndGetUser(database *sql.DB, token string) (*User, error) {
func VerifyTokenAndGetUser(db *gorm.DB, token string) (*User, error) {
now := time.Now().UTC().Format("2006-01-02 15:04:05")
row := database.QueryRow("SELECT (user_id) FROM access_token WHERE expire > ? AND value = ?", now, token)
// row := database.QueryRow("SELECT (user_id) FROM access_token WHERE expire > ? AND value = ?", now, token)
var userId string
if err := row.Scan(&userId); err != nil {
log.Println(err.Error())
return nil, err
var accessToken AccessToken
result := db.Where("expire > ? AND value = ?", now, token).First(&accessToken)
if result.Error != nil {
return nil, result.Error
}
row = database.QueryRow("SELECT * FROM user WHERE user_id = ?", userId)
user, err := NewUserFromRow(row)
if err != nil {
return nil, err
// var userId string
// if err := row.Scan(&userId); err != nil {
// log.Println(err.Error())
// return nil, err
// }
// row = db.QueryRow("SELECT * FROM user WHERE user_id = ?", userId)
// user, err := NewUserFromRow(row)
// if err != nil {
// return nil, err
// }
var user User
result = db.First(&user, accessToken.ID)
if result.Error != nil {
return nil, result.Error
}
return user, nil
return &user, nil
}

View File

@ -2,16 +2,16 @@ package resolvers
import (
"context"
"database/sql"
api "github.com/viktorstrate/photoview/api/graphql"
"github.com/viktorstrate/photoview/api/graphql/models"
"gorm.io/gorm"
)
//go:generate go run github.com/99designs/gqlgen
type Resolver struct {
Database *sql.DB
Database *gorm.DB
}
func (r *Resolver) Mutation() api.MutationResolver {

View File

@ -6,6 +6,7 @@ import (
"time"
"github.com/pkg/errors"
"gorm.io/gorm"
api "github.com/viktorstrate/photoview/api/graphql"
"github.com/viktorstrate/photoview/api/graphql/auth"
@ -261,7 +262,7 @@ func hashSharePassword(password *string) (*string, error) {
return hashed_password, nil
}
func getUserToken(db *sql.DB, user *models.User, tokenValue string) (*models.ShareToken, error) {
func getUserToken(db *gorm.DB, user *models.User, tokenValue string) (*models.ShareToken, error) {
row := db.QueryRow(`
SELECT share_token.* FROM share_token, user WHERE
share_token.value = ? AND

View File

@ -8,9 +8,10 @@ import (
"github.com/viktorstrate/photoview/api/graphql/auth"
"github.com/viktorstrate/photoview/api/graphql/models"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
func authenticateMedia(media *models.Media, db *sql.DB, r *http.Request) (success bool, responseMessage string, responseStatus int, errorMessage error) {
func authenticateMedia(media *models.Media, db *gorm.DB, r *http.Request) (success bool, responseMessage string, responseStatus int, errorMessage error) {
user := auth.UserFromContext(r.Context())
if user != nil {

View File

@ -1,7 +1,6 @@
package routes
import (
"database/sql"
"log"
"net/http"
"os"
@ -9,12 +8,13 @@ import (
"strconv"
"github.com/gorilla/mux"
"gorm.io/gorm"
"github.com/viktorstrate/photoview/api/graphql/models"
"github.com/viktorstrate/photoview/api/scanner"
)
func RegisterPhotoRoutes(db *sql.DB, router *mux.Router) {
func RegisterPhotoRoutes(db *gorm.DB, router *mux.Router) {
router.HandleFunc("/{name}", func(w http.ResponseWriter, r *http.Request) {
media_name := mux.Vars(r)["name"]

View File

@ -1,7 +1,6 @@
package routes
import (
"database/sql"
"log"
"net/http"
"os"
@ -11,9 +10,10 @@ import (
"github.com/gorilla/mux"
"github.com/viktorstrate/photoview/api/graphql/models"
"github.com/viktorstrate/photoview/api/scanner"
"gorm.io/gorm"
)
func RegisterVideoRoutes(db *sql.DB, router *mux.Router) {
func RegisterVideoRoutes(db *gorm.DB, router *mux.Router) {
router.HandleFunc("/{name}", func(w http.ResponseWriter, r *http.Request) {
media_name := mux.Vars(r)["name"]

View File

@ -9,9 +9,10 @@ import (
"github.com/pkg/errors"
"github.com/viktorstrate/photoview/api/graphql/models"
"gorm.io/gorm"
)
func CleanupMedia(db *sql.DB, albumId int, albumMedia []*models.Media) []error {
func CleanupMedia(db *gorm.DB, albumId int, albumMedia []*models.Media) []error {
albumMediaIds := make([]interface{}, len(albumMedia))
for i, photo := range albumMedia {
albumMediaIds[i] = photo.MediaID
@ -72,7 +73,7 @@ func CleanupMedia(db *sql.DB, albumId int, albumMedia []*models.Media) []error {
return deleteErrors
}
func deleteOldUserAlbums(db *sql.DB, scannedAlbums []*models.Album, user *models.User) []error {
func deleteOldUserAlbums(db *gorm.DB, scannedAlbums []*models.Album, user *models.User) []error {
if len(scannedAlbums) == 0 {
return nil
}

View File

@ -1,22 +1,23 @@
package scanner
import (
"database/sql"
"log"
"sync"
"time"
"gorm.io/gorm"
)
type periodicScanner struct {
ticker *time.Ticker
ticker_changed chan bool
mutex *sync.Mutex
db *sql.DB
db *gorm.DB
}
var mainPeriodicScanner *periodicScanner = nil
func getPeriodicScanInterval(db *sql.DB) (time.Duration, error) {
func getPeriodicScanInterval(db *gorm.DB) (time.Duration, error) {
row := db.QueryRow("SELECT periodic_scan_interval FROM site_info")
var intervalSeconds int
@ -27,7 +28,7 @@ func getPeriodicScanInterval(db *sql.DB) (time.Duration, error) {
return time.Duration(intervalSeconds) * time.Second, nil
}
func InitializePeriodicScanner(db *sql.DB) error {
func InitializePeriodicScanner(db *gorm.DB) error {
if mainPeriodicScanner != nil {
panic("periodic scanner has already been initialized")
}

View File

@ -1,7 +1,6 @@
package scanner
import (
"database/sql"
"fmt"
"log"
"sync"
@ -11,6 +10,7 @@ import (
"github.com/viktorstrate/photoview/api/graphql/models"
"github.com/viktorstrate/photoview/api/graphql/notification"
"github.com/viktorstrate/photoview/api/utils"
"gorm.io/gorm"
)
type ScannerJob struct {
@ -18,7 +18,7 @@ type ScannerJob struct {
cache *AlbumScannerCache
}
func (job *ScannerJob) Run(db *sql.DB) {
func (job *ScannerJob) Run(db *gorm.DB) {
scanAlbum(job.album, job.cache, db)
}
@ -31,13 +31,13 @@ type ScannerQueue struct {
idle_chan chan bool
in_progress []ScannerJob
up_next []ScannerJob
db *sql.DB
db *gorm.DB
settings ScannerQueueSettings
}
var global_scanner_queue ScannerQueue
func InitializeScannerQueue(db *sql.DB) error {
func InitializeScannerQueue(db *gorm.DB) error {
var concurrentWorkers int
{
@ -146,14 +146,11 @@ func (queue *ScannerQueue) notify() bool {
}
func AddAllToQueue() error {
rows, err := global_scanner_queue.db.Query("SELECT * FROM user")
if err != nil {
return errors.Wrap(err, "get all users from database")
}
users, err := models.NewUsersFromRows(rows)
if err != nil {
return errors.Wrap(err, "parse all users from db")
var users []*models.User
result := global_scanner_queue.db.Find(&users)
if result.Error != nil {
return errors.Wrap(result.Error, "get all users from database")
}
for _, user := range users {
@ -167,7 +164,7 @@ func AddUserToQueue(user *models.User) error {
album_cache := MakeAlbumCache()
albums, album_errors := findAlbumsForUser(global_scanner_queue.db, user, album_cache)
for _, err := range album_errors {
return errors.Wrapf(err, "find albums for user (user_id: %d)", user.UserID)
return errors.Wrapf(err, "find albums for user (user_id: %d)", user.ID)
}
global_scanner_queue.mutex.Lock()

View File

@ -1,7 +1,6 @@
package scanner
import (
"database/sql"
"fmt"
"io/ioutil"
"path"
@ -10,9 +9,10 @@ import (
"github.com/viktorstrate/photoview/api/graphql/models"
"github.com/viktorstrate/photoview/api/graphql/notification"
"github.com/viktorstrate/photoview/api/utils"
"gorm.io/gorm"
)
func scanAlbum(album *models.Album, cache *AlbumScannerCache, db *sql.DB) {
func scanAlbum(album *models.Album, cache *AlbumScannerCache, db *gorm.DB) {
album_notify_key := utils.GenerateToken()
notifyThrottle := utils.NewThrottle(500 * time.Millisecond)
@ -85,7 +85,7 @@ func scanAlbum(album *models.Album, cache *AlbumScannerCache, db *sql.DB) {
}
}
func findMediaForAlbum(album *models.Album, cache *AlbumScannerCache, db *sql.DB, onScanPhoto func(photo *models.Media, newPhoto bool)) ([]*models.Media, error) {
func findMediaForAlbum(album *models.Album, cache *AlbumScannerCache, db *gorm.DB, onScanPhoto func(photo *models.Media, newPhoto bool)) ([]*models.Media, error) {
albumPhotos := make([]*models.Media, 0)

View File

@ -2,7 +2,6 @@ package scanner
import (
"container/list"
"database/sql"
"fmt"
"io/ioutil"
"log"
@ -13,9 +12,10 @@ import (
"github.com/viktorstrate/photoview/api/graphql/models"
"github.com/viktorstrate/photoview/api/graphql/notification"
"github.com/viktorstrate/photoview/api/utils"
"gorm.io/gorm"
)
func findAlbumsForUser(db *sql.DB, user *models.User, album_cache *AlbumScannerCache) ([]*models.Album, []error) {
func findAlbumsForUser(db *gorm.DB, user *models.User, album_cache *AlbumScannerCache) ([]*models.Album, []error) {
// Check if user directory exists on the file system
if _, err := os.Stat(user.RootPath); err != nil {

View File

@ -35,7 +35,6 @@ func main() {
if err != nil {
log.Panicf("Could not connect to database: %s\n", err)
}
defer db.Close()
// Migrate database
if err := database.MigrateDatabase(db); err != nil {