176 lines
4.2 KiB
Go
176 lines
4.2 KiB
Go
package periodic_scanner
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/photoview/photoview/api/graphql/models"
|
|
"github.com/photoview/photoview/api/log"
|
|
"github.com/photoview/photoview/api/scanner/scanner_queue"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type ScannerQueue interface {
|
|
AddAllToQueue() error
|
|
}
|
|
|
|
type RealScannerQueue struct{}
|
|
|
|
func (r *RealScannerQueue) AddAllToQueue() error {
|
|
return scanner_queue.AddAllToQueue()
|
|
}
|
|
|
|
type periodicScanner struct {
|
|
ticker *time.Ticker
|
|
tickerLocker sync.Mutex
|
|
ticker_changed chan bool
|
|
done chan struct{}
|
|
db *gorm.DB
|
|
scannerQueue ScannerQueue
|
|
}
|
|
|
|
var mainPeriodicScanner *periodicScanner = nil
|
|
var mainPeriodicScannerLocker sync.Mutex
|
|
|
|
func getPeriodicScanInterval(db *gorm.DB) (time.Duration, error) {
|
|
var siteInfo models.SiteInfo
|
|
if err := db.First(&siteInfo).Error; err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return time.Duration(siteInfo.PeriodicScanInterval) * time.Second, nil
|
|
}
|
|
|
|
func InitializePeriodicScannerWithQueue(db *gorm.DB, queue ScannerQueue) error {
|
|
mainPeriodicScannerLocker.Lock()
|
|
defer mainPeriodicScannerLocker.Unlock()
|
|
|
|
if mainPeriodicScanner != nil {
|
|
return fmt.Errorf("periodic scanner has already been initialized")
|
|
}
|
|
|
|
scanInterval, err := getPeriodicScanInterval(db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
mainPeriodicScanner = &periodicScanner{
|
|
db: db,
|
|
ticker_changed: make(chan bool),
|
|
done: make(chan struct{}),
|
|
tickerLocker: sync.Mutex{},
|
|
scannerQueue: queue,
|
|
}
|
|
|
|
go mainPeriodicScanner.scanIntervalRunner()
|
|
|
|
var newTicker *time.Ticker = nil
|
|
if scanInterval > 0 {
|
|
newTicker = time.NewTicker(scanInterval)
|
|
log.Info(nil, "Periodic scan interval changed: "+scanInterval.String())
|
|
} else {
|
|
log.Info(nil, "Periodic scan interval changed: disabled")
|
|
}
|
|
|
|
mainPeriodicScanner.ticker = newTicker
|
|
|
|
select {
|
|
case mainPeriodicScanner.ticker_changed <- true:
|
|
default:
|
|
// Channel might be full, but that's okay
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func InitializePeriodicScanner(db *gorm.DB) error {
|
|
return InitializePeriodicScannerWithQueue(db, &RealScannerQueue{})
|
|
}
|
|
|
|
func ChangePeriodicScanInterval(duration time.Duration) {
|
|
var newTicker *time.Ticker = nil
|
|
if duration > 0 {
|
|
newTicker = time.NewTicker(duration)
|
|
log.Info(nil, "Periodic scan interval changed: "+duration.String())
|
|
} else {
|
|
log.Info(nil, "Periodic scan interval changed: disabled")
|
|
}
|
|
|
|
mainPeriodicScannerLocker.Lock()
|
|
scanner := mainPeriodicScanner
|
|
mainPeriodicScannerLocker.Unlock()
|
|
if scanner != nil {
|
|
scanner.tickerLocker.Lock()
|
|
defer scanner.tickerLocker.Unlock()
|
|
|
|
if scanner.ticker != nil {
|
|
scanner.ticker.Stop()
|
|
}
|
|
|
|
scanner.ticker = newTicker
|
|
select {
|
|
case scanner.ticker_changed <- true:
|
|
default:
|
|
// Channel might be full, but that's okay
|
|
}
|
|
}
|
|
}
|
|
|
|
// ShutdownPeriodicScanner gracefully shuts down the periodic scanner
|
|
func ShutdownPeriodicScanner() {
|
|
mainPeriodicScannerLocker.Lock()
|
|
defer mainPeriodicScannerLocker.Unlock()
|
|
|
|
if mainPeriodicScanner != nil {
|
|
log.Info(nil, "Shutting down periodic scanner")
|
|
|
|
// Signal the runner goroutine to stop
|
|
close(mainPeriodicScanner.done)
|
|
|
|
// Stop the ticker if it exists
|
|
mainPeriodicScanner.tickerLocker.Lock()
|
|
if mainPeriodicScanner.ticker != nil {
|
|
mainPeriodicScanner.ticker.Stop()
|
|
mainPeriodicScanner.ticker = nil
|
|
}
|
|
mainPeriodicScanner.tickerLocker.Unlock()
|
|
|
|
// Reset the global scanner
|
|
mainPeriodicScanner = nil
|
|
}
|
|
}
|
|
|
|
func (ps *periodicScanner) scanIntervalRunner() {
|
|
for {
|
|
log.Info(nil, "Scan interval runner: Waiting for signal")
|
|
|
|
ps.tickerLocker.Lock()
|
|
ticker := ps.ticker
|
|
ps.tickerLocker.Unlock()
|
|
|
|
if ticker != nil {
|
|
select {
|
|
case <-ps.done:
|
|
log.Info(nil, "Scan interval runner: Shutting down")
|
|
return
|
|
case <-ps.ticker_changed:
|
|
log.Info(nil, "Scan interval runner: New ticker detected")
|
|
case <-ticker.C:
|
|
log.Info(nil, "Scan interval runner: Starting periodic scan")
|
|
if err := ps.scannerQueue.AddAllToQueue(); err != nil {
|
|
log.Error(nil, "Scan interval runner: Failed to add all users to queue", "error", err)
|
|
}
|
|
}
|
|
} else {
|
|
select {
|
|
case <-ps.done:
|
|
log.Info(nil, "Scan interval runner: Shutting down")
|
|
return
|
|
case <-ps.ticker_changed:
|
|
log.Info(nil, "Scan interval runner: New ticker detected")
|
|
}
|
|
}
|
|
}
|
|
}
|