From 92d0b146dfa8fbf52898c55e1ea564e11421f1aa Mon Sep 17 00:00:00 2001 From: kataras Date: Tue, 8 Aug 2017 12:31:42 +0300 Subject: [PATCH] remove MaxAgeSeconds from redis sessiondb - now it derives from the sessions configuration automatically. Add option to use an existing BoltDB connection on boltdb sessiondb. TODO: leveldb sessiondb Former-commit-id: 8cb781bf089ab7b9a09dccc633454db9c6077610 --- .gitignore | 1 + _examples/sessions/database/redis/main.go | 23 ++++++++------ iris.go | 1 - sessions/sessiondb/boltdb/database.go | 33 ++++++++++++++------- sessions/sessiondb/redis/database.go | 20 +++++++++---- sessions/sessiondb/redis/service/config.go | 19 +++++------- sessions/sessiondb/redis/service/service.go | 16 +++++----- 7 files changed, 70 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index e69de29b..600d2d33 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/_examples/sessions/database/redis/main.go b/_examples/sessions/database/redis/main.go index 97370072..503bb7c6 100644 --- a/_examples/sessions/database/redis/main.go +++ b/_examples/sessions/database/redis/main.go @@ -11,15 +11,20 @@ import ( func main() { // replace with your running redis' server settings: - db := redis.New(service.Config{Network: service.DefaultRedisNetwork, - Addr: service.DefaultRedisAddr, - Password: "", - Database: "", - MaxIdle: 0, - MaxActive: 0, - IdleTimeout: service.DefaultRedisIdleTimeout, - Prefix: "", - MaxAgeSeconds: service.DefaultRedisMaxAgeSeconds}) // optionally configure the bridge between your redis server + db := redis.New(service.Config{ + Network: service.DefaultRedisNetwork, + Addr: service.DefaultRedisAddr, + Password: "", + Database: "", + MaxIdle: 0, + MaxActive: 0, + IdleTimeout: service.DefaultRedisIdleTimeout, + Prefix: ""}) // optionally configure the bridge between your redis server + + // close connection when control+C/cmd+C + iris.RegisterOnInterrupt(func() { + db.Close() + }) sess := sessions.New(sessions.Config{Cookie: "sessionscookieid"}) diff --git a/iris.go b/iris.go index 1b3561b0..e810f350 100644 --- a/iris.go +++ b/iris.go @@ -31,7 +31,6 @@ import ( ) const ( - // Version is the current version number of the Iris Web Framework. Version = "8.2.0" ) diff --git a/sessions/sessiondb/boltdb/database.go b/sessions/sessiondb/boltdb/database.go index 4b2292da..64c36151 100644 --- a/sessions/sessiondb/boltdb/database.go +++ b/sessions/sessiondb/boltdb/database.go @@ -4,6 +4,7 @@ import ( "bytes" "os" "path/filepath" + "runtime" "time" "github.com/boltdb/bolt" @@ -21,11 +22,12 @@ var ( // Database the BoltDB(file-based) session storage. type Database struct { - path string // path included the name, i.e sessions/store.db - fileMode os.FileMode // defaults to 0666. - table []byte - Service *bolt.DB // `New` sets it but it can be override exactly after `New`, use with caution. - async bool + table []byte + // Service is the underline BoltDB database connection, + // it's initialized at `New` or `NewFromDB`. + // Can be used to get stats. + Service *bolt.DB + async bool } var ( @@ -58,22 +60,29 @@ func New(path string, fileMode os.FileMode, bucketName string) (*Database, error &bolt.Options{Timeout: 15 * time.Second}, ) - bucket := []byte(bucketName) - if err != nil { golog.Errorf("unable to initialize the BoltDB-based session database: %v", err) return nil, err } + return NewFromDB(service, bucketName) +} + +// NewFromDB same as `New` but accepts an already-created custom boltdb connection instead. +func NewFromDB(service *bolt.DB, bucketName string) (*Database, error) { + if bucketName == "" { + return nil, ErrOptionsMissing + } + bucket := []byte(bucketName) + service.Update(func(tx *bolt.Tx) (err error) { _, err = tx.CreateBucketIfNotExists(bucket) return }) - db := &Database{path: path, fileMode: fileMode, - table: bucket, Service: service, - } + db := &Database{table: bucket, Service: service} + runtime.SetFinalizer(db, closeDB) return db, db.Cleanup() } @@ -214,6 +223,10 @@ func (db *Database) Len() (num int) { // Close shutdowns the BoltDB connection. func (db *Database) Close() error { + return closeDB(db) +} + +func closeDB(db *Database) error { err := db.Service.Close() if err != nil { golog.Warnf("closing the BoltDB connection: %v", err) diff --git a/sessions/sessiondb/redis/database.go b/sessions/sessiondb/redis/database.go index 7397523d..8ee35587 100644 --- a/sessions/sessiondb/redis/database.go +++ b/sessions/sessiondb/redis/database.go @@ -1,6 +1,8 @@ package redis import ( + "runtime" + "github.com/kataras/golog" "github.com/kataras/iris/sessions" "github.com/kataras/iris/sessions/sessiondb/redis/service" @@ -14,10 +16,9 @@ type Database struct { // New returns a new redis database. func New(cfg ...service.Config) *Database { - return &Database{redis: service.New(cfg...)} - // Note: no need to clean up here, the redis should handle these automatically because of the "SETEX" - // but that expiration doesn't depend on the session, instead it depends on the `MaxAgeSeconds` - // of the redis database configuration. + db := &Database{redis: service.New(cfg...)} + runtime.SetFinalizer(db, closeDB) + return db } // Config returns the configuration for the redis server bridge, you can change them. @@ -83,5 +84,14 @@ func (db *Database) sync(p sessions.SyncPayload) { return } - db.redis.Set(p.SessionID, storeB) + db.redis.Set(p.SessionID, storeB, p.Store.Lifetime.Second()) +} + +// Close shutdowns the redis connection. +func (db *Database) Close() error { + return closeDB(db) +} + +func closeDB(db *Database) error { + return db.redis.CloseConnection() } diff --git a/sessions/sessiondb/redis/service/config.go b/sessions/sessiondb/redis/service/config.go index e71d7ccb..fe5f2637 100644 --- a/sessions/sessiondb/redis/service/config.go +++ b/sessions/sessiondb/redis/service/config.go @@ -33,21 +33,18 @@ type Config struct { IdleTimeout time.Duration // Prefix "myprefix-for-this-website". Default "" Prefix string - // MaxAgeSeconds how much long the redis should keep the session in seconds. Default 31556926.0 (1 year) - MaxAgeSeconds int } // DefaultConfig returns the default configuration for Redis service. func DefaultConfig() Config { return Config{ - Network: DefaultRedisNetwork, - Addr: DefaultRedisAddr, - Password: "", - Database: "", - MaxIdle: 0, - MaxActive: 0, - IdleTimeout: DefaultRedisIdleTimeout, - Prefix: "", - MaxAgeSeconds: DefaultRedisMaxAgeSeconds, + Network: DefaultRedisNetwork, + Addr: DefaultRedisAddr, + Password: "", + Database: "", + MaxIdle: 0, + MaxActive: 0, + IdleTimeout: DefaultRedisIdleTimeout, + Prefix: "", } } diff --git a/sessions/sessiondb/redis/service/service.go b/sessions/sessiondb/redis/service/service.go index 94c037e4..e48e63de 100644 --- a/sessions/sessiondb/redis/service/service.go +++ b/sessions/sessiondb/redis/service/service.go @@ -44,15 +44,21 @@ func (r *Service) CloseConnection() error { // Set sets a key-value to the redis store. // The expiration is setted by the MaxAgeSeconds. -func (r *Service) Set(key string, value interface{}) error { +func (r *Service) Set(key string, value interface{}, secondsLifetime int) (err error) { c := r.pool.Get() defer c.Close() if c.Err() != nil { return c.Err() } - _, err := c.Do("SETEX", r.Config.Prefix+key, r.Config.MaxAgeSeconds, value) - return err + // if has expiration, then use the "EX" to delete the key automatically. + if secondsLifetime > 0 { + _, err = c.Do("SETEX", r.Config.Prefix+key, secondsLifetime, value) + } else { + _, err = c.Do("SET", r.Config.Prefix+key, value) + } + + return } // Get returns value, err by its key @@ -164,10 +170,6 @@ func (r *Service) Connect() { c.Addr = DefaultRedisAddr } - if c.MaxAgeSeconds <= 0 { - c.MaxAgeSeconds = DefaultRedisMaxAgeSeconds - } - pool := &redis.Pool{IdleTimeout: DefaultRedisIdleTimeout, MaxIdle: c.MaxIdle, MaxActive: c.MaxActive} pool.TestOnBorrow = func(c redis.Conn, t time.Time) error { _, err := c.Do("PING")