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
This commit is contained in:
kataras 2017-08-08 12:31:42 +03:00
parent 48e352e1df
commit 92d0b146df
7 changed files with 70 additions and 43 deletions

1
.gitignore vendored
View File

@ -0,0 +1 @@
.vscode

View File

@ -11,15 +11,20 @@ import (
func main() { func main() {
// replace with your running redis' server settings: // replace with your running redis' server settings:
db := redis.New(service.Config{Network: service.DefaultRedisNetwork, db := redis.New(service.Config{
Network: service.DefaultRedisNetwork,
Addr: service.DefaultRedisAddr, Addr: service.DefaultRedisAddr,
Password: "", Password: "",
Database: "", Database: "",
MaxIdle: 0, MaxIdle: 0,
MaxActive: 0, MaxActive: 0,
IdleTimeout: service.DefaultRedisIdleTimeout, IdleTimeout: service.DefaultRedisIdleTimeout,
Prefix: "", Prefix: ""}) // optionally configure the bridge between your redis server
MaxAgeSeconds: service.DefaultRedisMaxAgeSeconds}) // 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"}) sess := sessions.New(sessions.Config{Cookie: "sessionscookieid"})

View File

@ -31,7 +31,6 @@ import (
) )
const ( const (
// Version is the current version number of the Iris Web Framework. // Version is the current version number of the Iris Web Framework.
Version = "8.2.0" Version = "8.2.0"
) )

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"time" "time"
"github.com/boltdb/bolt" "github.com/boltdb/bolt"
@ -21,10 +22,11 @@ var (
// Database the BoltDB(file-based) session storage. // Database the BoltDB(file-based) session storage.
type Database struct { type Database struct {
path string // path included the name, i.e sessions/store.db
fileMode os.FileMode // defaults to 0666.
table []byte table []byte
Service *bolt.DB // `New` sets it but it can be override exactly after `New`, use with caution. // 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 async bool
} }
@ -58,22 +60,29 @@ func New(path string, fileMode os.FileMode, bucketName string) (*Database, error
&bolt.Options{Timeout: 15 * time.Second}, &bolt.Options{Timeout: 15 * time.Second},
) )
bucket := []byte(bucketName)
if err != nil { if err != nil {
golog.Errorf("unable to initialize the BoltDB-based session database: %v", err) golog.Errorf("unable to initialize the BoltDB-based session database: %v", err)
return nil, 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) { service.Update(func(tx *bolt.Tx) (err error) {
_, err = tx.CreateBucketIfNotExists(bucket) _, err = tx.CreateBucketIfNotExists(bucket)
return return
}) })
db := &Database{path: path, fileMode: fileMode, db := &Database{table: bucket, Service: service}
table: bucket, Service: service,
}
runtime.SetFinalizer(db, closeDB)
return db, db.Cleanup() return db, db.Cleanup()
} }
@ -214,6 +223,10 @@ func (db *Database) Len() (num int) {
// Close shutdowns the BoltDB connection. // Close shutdowns the BoltDB connection.
func (db *Database) Close() error { func (db *Database) Close() error {
return closeDB(db)
}
func closeDB(db *Database) error {
err := db.Service.Close() err := db.Service.Close()
if err != nil { if err != nil {
golog.Warnf("closing the BoltDB connection: %v", err) golog.Warnf("closing the BoltDB connection: %v", err)

View File

@ -1,6 +1,8 @@
package redis package redis
import ( import (
"runtime"
"github.com/kataras/golog" "github.com/kataras/golog"
"github.com/kataras/iris/sessions" "github.com/kataras/iris/sessions"
"github.com/kataras/iris/sessions/sessiondb/redis/service" "github.com/kataras/iris/sessions/sessiondb/redis/service"
@ -14,10 +16,9 @@ type Database struct {
// New returns a new redis database. // New returns a new redis database.
func New(cfg ...service.Config) *Database { func New(cfg ...service.Config) *Database {
return &Database{redis: service.New(cfg...)} db := &Database{redis: service.New(cfg...)}
// Note: no need to clean up here, the redis should handle these automatically because of the "SETEX" runtime.SetFinalizer(db, closeDB)
// but that expiration doesn't depend on the session, instead it depends on the `MaxAgeSeconds` return db
// of the redis database configuration.
} }
// Config returns the configuration for the redis server bridge, you can change them. // 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 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()
} }

View File

@ -33,8 +33,6 @@ type Config struct {
IdleTimeout time.Duration IdleTimeout time.Duration
// Prefix "myprefix-for-this-website". Default "" // Prefix "myprefix-for-this-website". Default ""
Prefix string 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. // DefaultConfig returns the default configuration for Redis service.
@ -48,6 +46,5 @@ func DefaultConfig() Config {
MaxActive: 0, MaxActive: 0,
IdleTimeout: DefaultRedisIdleTimeout, IdleTimeout: DefaultRedisIdleTimeout,
Prefix: "", Prefix: "",
MaxAgeSeconds: DefaultRedisMaxAgeSeconds,
} }
} }

View File

@ -44,15 +44,21 @@ func (r *Service) CloseConnection() error {
// Set sets a key-value to the redis store. // Set sets a key-value to the redis store.
// The expiration is setted by the MaxAgeSeconds. // 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() c := r.pool.Get()
defer c.Close() defer c.Close()
if c.Err() != nil { if c.Err() != nil {
return c.Err() return c.Err()
} }
_, err := c.Do("SETEX", r.Config.Prefix+key, r.Config.MaxAgeSeconds, value) // if has expiration, then use the "EX" to delete the key automatically.
return err 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 // Get returns value, err by its key
@ -164,10 +170,6 @@ func (r *Service) Connect() {
c.Addr = DefaultRedisAddr c.Addr = DefaultRedisAddr
} }
if c.MaxAgeSeconds <= 0 {
c.MaxAgeSeconds = DefaultRedisMaxAgeSeconds
}
pool := &redis.Pool{IdleTimeout: DefaultRedisIdleTimeout, MaxIdle: c.MaxIdle, MaxActive: c.MaxActive} pool := &redis.Pool{IdleTimeout: DefaultRedisIdleTimeout, MaxIdle: c.MaxIdle, MaxActive: c.MaxActive}
pool.TestOnBorrow = func(c redis.Conn, t time.Time) error { pool.TestOnBorrow = func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING") _, err := c.Do("PING")