periodically clean sessions
This commit is contained in:
@@ -70,6 +70,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
var g run.Group
|
var g run.Group
|
||||||
g.Add(server.StartHTTP(*listenAddr))
|
g.Add(server.StartHTTP(*listenAddr))
|
||||||
|
g.Add(server.StartSessionClean(10 * time.Minute))
|
||||||
if *scanInterval > 0 {
|
if *scanInterval > 0 {
|
||||||
tickerDur := time.Duration(*scanInterval) * time.Minute
|
tickerDur := time.Duration(*scanInterval) * time.Minute
|
||||||
g.Add(server.StartScanTicker(tickerDur))
|
g.Add(server.StartScanTicker(tickerDur))
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
|
|
||||||
"github.com/Masterminds/sprig"
|
"github.com/Masterminds/sprig"
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/gorilla/securecookie"
|
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/oxtoacart/bpool"
|
"github.com/oxtoacart/bpool"
|
||||||
"github.com/wader/gormstore"
|
"github.com/wader/gormstore"
|
||||||
@@ -85,12 +84,7 @@ type Controller struct {
|
|||||||
sessDB *gormstore.Store
|
sessDB *gormstore.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(b *ctrlbase.Controller) *Controller {
|
func New(b *ctrlbase.Controller, sessDB *gormstore.Store) *Controller {
|
||||||
sessionKey := []byte(b.DB.GetSetting("session_key"))
|
|
||||||
if len(sessionKey) == 0 {
|
|
||||||
sessionKey = securecookie.GenerateRandomKey(32)
|
|
||||||
b.DB.SetSetting("session_key", string(sessionKey))
|
|
||||||
}
|
|
||||||
tmplBase := template.
|
tmplBase := template.
|
||||||
New("layout").
|
New("layout").
|
||||||
Funcs(sprig.FuncMap()).
|
Funcs(sprig.FuncMap()).
|
||||||
@@ -100,9 +94,6 @@ func New(b *ctrlbase.Controller) *Controller {
|
|||||||
})
|
})
|
||||||
tmplBase = extendFromPaths(tmplBase, prefixPartials)
|
tmplBase = extendFromPaths(tmplBase, prefixPartials)
|
||||||
tmplBase = extendFromPaths(tmplBase, prefixLayouts)
|
tmplBase = extendFromPaths(tmplBase, prefixLayouts)
|
||||||
sessDB := gormstore.New(b.DB.DB, sessionKey)
|
|
||||||
sessDB.SessionOpts.HttpOnly = true
|
|
||||||
sessDB.SessionOpts.SameSite = http.SameSiteLaxMode
|
|
||||||
return &Controller{
|
return &Controller{
|
||||||
Controller: b,
|
Controller: b,
|
||||||
buffPool: bpool.NewBufferPool(64),
|
buffPool: bpool.NewBufferPool(64),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/gorilla/securecookie"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
|
|
||||||
"gopkg.in/gormigrate.v1"
|
"gopkg.in/gormigrate.v1"
|
||||||
@@ -101,6 +102,15 @@ func (db *DB) SetSetting(key, value string) {
|
|||||||
FirstOrCreate(&Setting{})
|
FirstOrCreate(&Setting{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) GetOrCreateKey(key string) string {
|
||||||
|
value := db.GetSetting(key)
|
||||||
|
if value == "" {
|
||||||
|
value = string(securecookie.GenerateRandomKey(32))
|
||||||
|
db.SetSetting(key, value)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
func (db *DB) GetUserFromName(name string) *User {
|
func (db *DB) GetUserFromName(name string) *User {
|
||||||
user := &User{}
|
user := &User{}
|
||||||
err := db.
|
err := db.
|
||||||
@@ -113,27 +123,21 @@ func (db *DB) GetUserFromName(name string) *User {
|
|||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) WithTx(cb func(*gorm.DB)) {
|
|
||||||
tx := db.Begin()
|
|
||||||
defer tx.Commit()
|
|
||||||
cb(tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChunkFunc func(*gorm.DB, []int64) error
|
type ChunkFunc func(*gorm.DB, []int64) error
|
||||||
|
|
||||||
func (db *DB) WithTxChunked(data []int64, cb ChunkFunc) error {
|
func (db *DB) TransactionChunked(data []int64, cb ChunkFunc) error {
|
||||||
// https://sqlite.org/limits.html
|
// https://sqlite.org/limits.html
|
||||||
const size = 999
|
const size = 999
|
||||||
tx := db.Begin()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer tx.Commit()
|
for i := 0; i < len(data); i += size {
|
||||||
for i := 0; i < len(data); i += size {
|
end := i + size
|
||||||
end := i + size
|
if end > len(data) {
|
||||||
if end > len(data) {
|
end = len(data)
|
||||||
end = len(data)
|
}
|
||||||
|
if err := cb(tx, data[i:end]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := cb(tx, data[i:end]); err != nil {
|
return nil
|
||||||
return err
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ func (s *Scanner) cleanTracks() (int, error) {
|
|||||||
missing = append(missing, int64(prev))
|
missing = append(missing, int64(prev))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = s.db.WithTxChunked(missing, func(tx *gorm.DB, chunk []int64) error {
|
err = s.db.TransactionChunked(missing, func(tx *gorm.DB, chunk []int64) error {
|
||||||
return tx.Where(chunk).Delete(&db.Track{}).Error
|
return tx.Where(chunk).Delete(&db.Track{}).Error
|
||||||
})
|
})
|
||||||
return len(missing), err
|
return len(missing), err
|
||||||
@@ -125,7 +125,7 @@ func (s *Scanner) cleanFolders() (int, error) {
|
|||||||
missing = append(missing, int64(prev))
|
missing = append(missing, int64(prev))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = s.db.WithTxChunked(missing, func(tx *gorm.DB, chunk []int64) error {
|
err = s.db.TransactionChunked(missing, func(tx *gorm.DB, chunk []int64) error {
|
||||||
return tx.Where(chunk).Delete(&db.Album{}).Error
|
return tx.Where(chunk).Delete(&db.Album{}).Error
|
||||||
})
|
})
|
||||||
return len(missing), err
|
return len(missing), err
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/wader/gormstore"
|
||||||
|
|
||||||
"go.senan.xyz/gonic/server/assets"
|
"go.senan.xyz/gonic/server/assets"
|
||||||
"go.senan.xyz/gonic/server/ctrladmin"
|
"go.senan.xyz/gonic/server/ctrladmin"
|
||||||
@@ -30,6 +31,7 @@ type Server struct {
|
|||||||
scanner *scanner.Scanner
|
scanner *scanner.Scanner
|
||||||
jukebox *jukebox.Jukebox
|
jukebox *jukebox.Jukebox
|
||||||
router *mux.Router
|
router *mux.Router
|
||||||
|
sessDB *gormstore.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(opts Options) *Server {
|
func New(opts Options) *Server {
|
||||||
@@ -51,7 +53,13 @@ func New(opts Options) *Server {
|
|||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.Use(base.WithLogging)
|
r.Use(base.WithLogging)
|
||||||
r.Use(base.WithCORS)
|
r.Use(base.WithCORS)
|
||||||
ctrlAdmin := ctrladmin.New(base)
|
//
|
||||||
|
sessKey := opts.DB.GetOrCreateKey("session_key")
|
||||||
|
sessDB := gormstore.New(opts.DB.DB, []byte(sessKey))
|
||||||
|
sessDB.SessionOpts.HttpOnly = true
|
||||||
|
sessDB.SessionOpts.SameSite = http.SameSiteLaxMode
|
||||||
|
//
|
||||||
|
ctrlAdmin := ctrladmin.New(base, sessDB)
|
||||||
ctrlSubsonic := &ctrlsubsonic.Controller{
|
ctrlSubsonic := &ctrlsubsonic.Controller{
|
||||||
Controller: base,
|
Controller: base,
|
||||||
CachePath: opts.CachePath,
|
CachePath: opts.CachePath,
|
||||||
@@ -65,6 +73,7 @@ func New(opts Options) *Server {
|
|||||||
scanner: scanner,
|
scanner: scanner,
|
||||||
jukebox: jukebox,
|
jukebox: jukebox,
|
||||||
router: r,
|
router: r,
|
||||||
|
sessDB: sessDB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,3 +243,26 @@ func (s *Server) StartJukebox() (FuncExecute, FuncInterrupt) {
|
|||||||
s.jukebox.Quit()
|
s.jukebox.Quit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) StartSessionClean(dur time.Duration) (FuncExecute, FuncInterrupt) {
|
||||||
|
ticker := time.NewTicker(dur)
|
||||||
|
done := make(chan struct{})
|
||||||
|
waitFor := func() error {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return nil
|
||||||
|
case <-ticker.C:
|
||||||
|
s.sessDB.Cleanup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return func() error {
|
||||||
|
log.Printf("starting job 'session clean'\n")
|
||||||
|
return waitFor()
|
||||||
|
}, func(_ error) {
|
||||||
|
// stop job
|
||||||
|
ticker.Stop()
|
||||||
|
done <- struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user