mirror of
https://github.com/gofiber/fiber.git
synced 2025-02-23 10:44:02 +00:00
📦 update session
This commit is contained in:
parent
0d2eb334d6
commit
de912755f7
7
middleware/cache/README.md
vendored
7
middleware/cache/README.md
vendored
@ -61,12 +61,12 @@ type Config struct {
|
||||
// Default: func(c *fiber.Ctx) string {
|
||||
// return c.Path()
|
||||
// }
|
||||
Key func(*fiber.Ctx) string
|
||||
KeyGenerator func(*fiber.Ctx) string
|
||||
|
||||
// Store is used to store the state of the middleware
|
||||
//
|
||||
// Default: an in memory store for this process only
|
||||
Store fiber.Storage
|
||||
Storage fiber.Storage
|
||||
}
|
||||
```
|
||||
|
||||
@ -77,8 +77,9 @@ var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Expiration: 1 * time.Minute,
|
||||
CacheControl: false,
|
||||
Key: func(c *fiber.Ctx) string {
|
||||
KeyGenerator: func(c *fiber.Ctx) string {
|
||||
return c.Path()
|
||||
},
|
||||
Storage: nil,
|
||||
}
|
||||
```
|
||||
|
33
middleware/cache/config.go
vendored
33
middleware/cache/config.go
vendored
@ -29,16 +29,19 @@ type Config struct {
|
||||
// Default: func(c *fiber.Ctx) string {
|
||||
// return c.Path()
|
||||
// }
|
||||
Key func(*fiber.Ctx) string
|
||||
|
||||
// Deprecated, use Storage instead
|
||||
Store fiber.Storage
|
||||
KeyGenerator func(*fiber.Ctx) string
|
||||
|
||||
// Store is used to store the state of the middleware
|
||||
//
|
||||
// Default: an in memory store for this process only
|
||||
Storage fiber.Storage
|
||||
|
||||
// Deprecated, use Storage instead
|
||||
Store fiber.Storage
|
||||
|
||||
// Deprecated, use KeyGenerator instead
|
||||
Key func(*fiber.Ctx) string
|
||||
|
||||
// Internally used - if true, the simpler method of two maps is used in order to keep
|
||||
// execution time down.
|
||||
defaultStore bool
|
||||
@ -49,9 +52,10 @@ var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Expiration: 1 * time.Minute,
|
||||
CacheControl: false,
|
||||
Key: func(c *fiber.Ctx) string {
|
||||
KeyGenerator: func(c *fiber.Ctx) string {
|
||||
return c.Path()
|
||||
},
|
||||
Storage: nil,
|
||||
defaultStore: true,
|
||||
}
|
||||
|
||||
@ -66,21 +70,24 @@ func configDefault(config ...Config) Config {
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
if cfg.Store != nil {
|
||||
fmt.Println("[CACHE] Store is deprecated, please use Storage")
|
||||
cfg.Storage = cfg.Store
|
||||
}
|
||||
if cfg.Key != nil {
|
||||
fmt.Println("[CACHE] Key is deprecated, please use KeyGenerator")
|
||||
cfg.KeyGenerator = cfg.Key
|
||||
}
|
||||
if cfg.Next == nil {
|
||||
cfg.Next = ConfigDefault.Next
|
||||
}
|
||||
if int(cfg.Expiration.Seconds()) == 0 {
|
||||
cfg.Expiration = ConfigDefault.Expiration
|
||||
}
|
||||
if cfg.Key == nil {
|
||||
cfg.Key = ConfigDefault.Key
|
||||
if cfg.KeyGenerator == nil {
|
||||
cfg.KeyGenerator = ConfigDefault.KeyGenerator
|
||||
}
|
||||
if cfg.Storage == nil && cfg.Store == nil {
|
||||
cfg.defaultStore = true
|
||||
}
|
||||
if cfg.Store != nil {
|
||||
fmt.Println("cache: `Store` is deprecated, use `Storage` instead")
|
||||
cfg.Storage = cfg.Store
|
||||
if cfg.Storage != nil {
|
||||
cfg.defaultStore = true
|
||||
}
|
||||
return cfg
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Compress
|
||||
|
||||
Compression middleware for [Fiber](https://github.com/gofiber/fiber) that will compress the response using `gzip`, `deflate` and `brotli` compression depending on the [Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) header.
|
||||
|
||||
- [Signatures](#signatures)
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Cross-Origin Resource Sharing (CORS)
|
||||
|
||||
CORS middleware for [Fiber](https://github.com/gofiber/fiber) that that can be used to enable [Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) with various options.
|
||||
|
||||
### Table of Contents
|
||||
|
@ -1,4 +1,5 @@
|
||||
# ETag
|
||||
|
||||
ETag middleware for [Fiber](https://github.com/gofiber/fiber) that lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed.
|
||||
|
||||
### Table of Contents
|
||||
@ -37,6 +38,11 @@ app.Get("/", func(c *fiber.Ctx) error {
|
||||
```go
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Next defines a function to skip this middleware when returned true.
|
||||
//
|
||||
// Optional. Default: nil
|
||||
Next func(c *fiber.Ctx) bool
|
||||
|
||||
// Weak indicates that a weak validator is used. Weak etags are easy
|
||||
// to generate, but are far less useful for comparisons. Strong
|
||||
// validators are ideal for comparisons but can be very difficult
|
||||
@ -46,18 +52,13 @@ type Config struct {
|
||||
// when byte range requests are used, but strong etags mean range
|
||||
// requests can still be cached.
|
||||
Weak bool
|
||||
|
||||
// Next defines a function to skip this middleware when returned true.
|
||||
//
|
||||
// Optional. Default: nil
|
||||
Next func(c *fiber.Ctx) bool
|
||||
}
|
||||
```
|
||||
|
||||
### Default Config
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Weak: false,
|
||||
Next: nil,
|
||||
Weak: false,
|
||||
}
|
||||
```
|
||||
|
44
middleware/etag/config.go
Normal file
44
middleware/etag/config.go
Normal file
@ -0,0 +1,44 @@
|
||||
package etag
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Weak indicates that a weak validator is used. Weak etags are easy
|
||||
// to generate, but are far less useful for comparisons. Strong
|
||||
// validators are ideal for comparisons but can be very difficult
|
||||
// to generate efficiently. Weak ETag values of two representations
|
||||
// of the same resources might be semantically equivalent, but not
|
||||
// byte-for-byte identical. This means weak etags prevent caching
|
||||
// when byte range requests are used, but strong etags mean range
|
||||
// requests can still be cached.
|
||||
Weak bool
|
||||
|
||||
// Next defines a function to skip this middleware when returned true.
|
||||
//
|
||||
// Optional. Default: nil
|
||||
Next func(c *fiber.Ctx) bool
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Weak: false,
|
||||
Next: nil,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
|
||||
return cfg
|
||||
}
|
@ -8,42 +8,13 @@ import (
|
||||
"github.com/gofiber/fiber/v2/internal/bytebufferpool"
|
||||
)
|
||||
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Weak indicates that a weak validator is used. Weak etags are easy
|
||||
// to generate, but are far less useful for comparisons. Strong
|
||||
// validators are ideal for comparisons but can be very difficult
|
||||
// to generate efficiently. Weak ETag values of two representations
|
||||
// of the same resources might be semantically equivalent, but not
|
||||
// byte-for-byte identical. This means weak etags prevent caching
|
||||
// when byte range requests are used, but strong etags mean range
|
||||
// requests can still be cached.
|
||||
Weak bool
|
||||
|
||||
// Next defines a function to skip this middleware when returned true.
|
||||
//
|
||||
// Optional. Default: nil
|
||||
Next func(c *fiber.Ctx) bool
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
Weak: false,
|
||||
Next: nil,
|
||||
}
|
||||
|
||||
var normalizedHeaderETag = []byte("Etag")
|
||||
var weakPrefix = []byte("W/")
|
||||
|
||||
// New creates a new middleware handler
|
||||
func New(config ...Config) fiber.Handler {
|
||||
// Set default config
|
||||
cfg := ConfigDefault
|
||||
|
||||
// Override config if provided
|
||||
if len(config) > 0 {
|
||||
cfg = config[0]
|
||||
}
|
||||
cfg := configDefault(config...)
|
||||
|
||||
var crc32q = crc32.MakeTable(0xD5828281)
|
||||
|
||||
|
@ -129,7 +129,7 @@ func New(config ...Config) fiber.Handler {
|
||||
|
||||
// Set error handler once
|
||||
once.Do(func() {
|
||||
errHandler = c.App().Config().ErrorHandler
|
||||
// get longested possible path
|
||||
stack := c.App().Stack()
|
||||
for m := range stack {
|
||||
for r := range stack[m] {
|
||||
@ -139,7 +139,8 @@ func New(config ...Config) fiber.Handler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// override error handler
|
||||
errHandler = c.App().Config().ErrorHandler
|
||||
})
|
||||
|
||||
// Set latency start time
|
||||
|
@ -1,10 +1,12 @@
|
||||
package session
|
||||
|
||||
import "sync"
|
||||
|
||||
// go:generate msgp
|
||||
// msgp -file="db.go" -o="db_msgp.go" -tests=false -unexported
|
||||
// msgp -file="data.go" -o="data_msgp.go" -tests=false -unexported
|
||||
// don't forget to replace the msgp import path to:
|
||||
// "github.com/gofiber/fiber/v2/internal/msgp"
|
||||
type db struct {
|
||||
type data struct {
|
||||
d []kv
|
||||
}
|
||||
|
||||
@ -14,11 +16,26 @@ type kv struct {
|
||||
v interface{}
|
||||
}
|
||||
|
||||
func (d *db) Reset() {
|
||||
var dataPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(data)
|
||||
},
|
||||
}
|
||||
|
||||
func acquireData() *data {
|
||||
return dataPool.Get().(*data)
|
||||
}
|
||||
|
||||
func releaseData(d *data) {
|
||||
d.Reset()
|
||||
dataPool.Put(d)
|
||||
}
|
||||
|
||||
func (d *data) Reset() {
|
||||
d.d = d.d[:0]
|
||||
}
|
||||
|
||||
func (d *db) Get(key string) interface{} {
|
||||
func (d *data) Get(key string) interface{} {
|
||||
idx := d.indexOf(key)
|
||||
if idx > -1 {
|
||||
return d.d[idx].v
|
||||
@ -26,7 +43,7 @@ func (d *db) Get(key string) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *db) Set(key string, value interface{}) {
|
||||
func (d *data) Set(key string, value interface{}) {
|
||||
idx := d.indexOf(key)
|
||||
if idx > -1 {
|
||||
kv := &d.d[idx]
|
||||
@ -36,7 +53,7 @@ func (d *db) Set(key string, value interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *db) Delete(key string) {
|
||||
func (d *data) Delete(key string) {
|
||||
idx := d.indexOf(key)
|
||||
if idx > -1 {
|
||||
n := len(d.d) - 1
|
||||
@ -45,11 +62,11 @@ func (d *db) Delete(key string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *db) Len() int {
|
||||
func (d *data) Len() int {
|
||||
return len(d.d)
|
||||
}
|
||||
|
||||
func (d *db) swap(i, j int) {
|
||||
func (d *data) swap(i, j int) {
|
||||
iKey, iValue := d.d[i].k, d.d[i].v
|
||||
jKey, jValue := d.d[j].k, d.d[j].v
|
||||
|
||||
@ -57,7 +74,7 @@ func (d *db) swap(i, j int) {
|
||||
d.d[j].k, d.d[j].v = iKey, iValue
|
||||
}
|
||||
|
||||
func (d *db) allocPage() *kv {
|
||||
func (d *data) allocPage() *kv {
|
||||
n := len(d.d)
|
||||
if cap(d.d) > n {
|
||||
d.d = d.d[:n+1]
|
||||
@ -67,13 +84,13 @@ func (d *db) allocPage() *kv {
|
||||
return &d.d[n]
|
||||
}
|
||||
|
||||
func (d *db) append(key string, value interface{}) {
|
||||
func (d *data) append(key string, value interface{}) {
|
||||
kv := d.allocPage()
|
||||
kv.k = key
|
||||
kv.v = value
|
||||
}
|
||||
|
||||
func (d *db) indexOf(key string) int {
|
||||
func (d *data) indexOf(key string) int {
|
||||
n := len(d.d)
|
||||
for i := 0; i < n; i++ {
|
||||
if d.d[i].k == key {
|
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *db) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
func (z *data) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
var field []byte
|
||||
_ = field
|
||||
var zb0001 uint32
|
||||
@ -84,7 +84,7 @@ func (z *db) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z *db) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
func (z *data) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
// map header, size 1
|
||||
// write "d"
|
||||
err = en.Append(0x81, 0xa1, 0x64)
|
||||
@ -123,7 +123,7 @@ func (z *db) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z *db) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
func (z *data) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
// map header, size 1
|
||||
// string "d"
|
||||
@ -146,7 +146,7 @@ func (z *db) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *db) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
func (z *data) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
var field []byte
|
||||
_ = field
|
||||
var zb0001 uint32
|
||||
@ -224,7 +224,7 @@ func (z *db) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
}
|
||||
|
||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||
func (z *db) Msgsize() (s int) {
|
||||
func (z *data) Msgsize() (s int) {
|
||||
s = 1 + 2 + msgp.ArrayHeaderSize
|
||||
for za0001 := range z.d {
|
||||
s += 1 + 2 + msgp.StringPrefixSize + len(z.d[za0001].k) + 2 + msgp.GuessSize(z.d[za0001].v)
|
@ -10,11 +10,11 @@ import (
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
ctx *fiber.Ctx
|
||||
config *Store
|
||||
db *db
|
||||
id string
|
||||
fresh bool
|
||||
id string // session id
|
||||
fresh bool // if new session
|
||||
ctx *fiber.Ctx // fiber context
|
||||
config *Store // store configuration
|
||||
data *data // key value data
|
||||
}
|
||||
|
||||
var sessionPool = sync.Pool{
|
||||
@ -24,20 +24,10 @@ var sessionPool = sync.Pool{
|
||||
}
|
||||
|
||||
func acquireSession() *Session {
|
||||
s := sessionPool.Get().(*Session)
|
||||
s.db = new(db)
|
||||
s.fresh = true
|
||||
return s
|
||||
return sessionPool.Get().(*Session)
|
||||
}
|
||||
|
||||
func releaseSession(s *Session) {
|
||||
s.ctx = nil
|
||||
s.config = nil
|
||||
if s.db != nil {
|
||||
s.db.Reset()
|
||||
}
|
||||
s.id = ""
|
||||
s.fresh = true
|
||||
sessionPool.Put(s)
|
||||
}
|
||||
|
||||
@ -53,28 +43,51 @@ func (s *Session) ID() string {
|
||||
|
||||
// Get will return the value
|
||||
func (s *Session) Get(key string) interface{} {
|
||||
return s.db.Get(key)
|
||||
// Better safe than sorry
|
||||
if s.data == nil {
|
||||
return nil
|
||||
}
|
||||
return s.data.Get(key)
|
||||
}
|
||||
|
||||
// Set will update or create a new key value
|
||||
func (s *Session) Set(key string, val interface{}) {
|
||||
s.db.Set(key, val)
|
||||
// Better safe than sorry
|
||||
if s.data == nil {
|
||||
return
|
||||
}
|
||||
s.data.Set(key, val)
|
||||
}
|
||||
|
||||
// Delete will delete the value
|
||||
func (s *Session) Delete(key string) {
|
||||
s.db.Delete(key)
|
||||
// Better safe than sorry
|
||||
if s.data == nil {
|
||||
return
|
||||
}
|
||||
s.data.Delete(key)
|
||||
}
|
||||
|
||||
// Destroy will delete the session from Storage and expire session cookie
|
||||
func (s *Session) Destroy() error {
|
||||
// Reset local data
|
||||
s.db.Reset()
|
||||
// Better safe than sorry
|
||||
if s.data == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete data from storage
|
||||
// Reset local data
|
||||
s.data.Reset()
|
||||
|
||||
// Use external Storage if exist
|
||||
if s.config.Storage != nil {
|
||||
if err := s.config.Storage.Delete(s.id); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
s.config.mux.Lock()
|
||||
delete(s.config.sessions, s.id)
|
||||
s.config.mux.Unlock()
|
||||
}
|
||||
|
||||
// Expire cookie
|
||||
s.delCookie()
|
||||
@ -83,11 +96,18 @@ func (s *Session) Destroy() error {
|
||||
|
||||
// Regenerate generates a new session id and delete the old one from Storage
|
||||
func (s *Session) Regenerate() error {
|
||||
|
||||
// Use external Storage if exist
|
||||
if s.config.Storage != nil {
|
||||
// Delete old id from storage
|
||||
if err := s.config.Storage.Delete(s.id); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
s.config.mux.Lock()
|
||||
delete(s.config.sessions, s.id)
|
||||
s.config.mux.Unlock()
|
||||
}
|
||||
|
||||
// Create new ID
|
||||
s.id = s.config.KeyGenerator()
|
||||
|
||||
@ -96,13 +116,20 @@ func (s *Session) Regenerate() error {
|
||||
|
||||
// Save will update the storage and client cookie
|
||||
func (s *Session) Save() error {
|
||||
// Don't save to Storage if no data is available
|
||||
if s.db.Len() <= 0 {
|
||||
// Better safe than sorry
|
||||
if s.data == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Don't save to Storage if no data is available
|
||||
if s.data.Len() <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Use external Storage if exist
|
||||
if s.config.Storage != nil {
|
||||
// Convert book to bytes
|
||||
data, err := s.db.MarshalMsg(nil)
|
||||
data, err := s.data.MarshalMsg(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -111,11 +138,20 @@ func (s *Session) Save() error {
|
||||
if err := s.config.Storage.Set(s.id, data, s.config.Expiration); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
s.config.mux.Lock()
|
||||
s.config.sessions[s.id] = s.data
|
||||
s.config.mux.Unlock()
|
||||
}
|
||||
|
||||
// Create cookie with the session ID
|
||||
s.setCookie()
|
||||
|
||||
// release session to pool to be re-used on next request
|
||||
// Release data if we use a Storage
|
||||
if s.config.Storage != nil {
|
||||
releaseData(s.data)
|
||||
}
|
||||
|
||||
releaseSession(s)
|
||||
|
||||
return nil
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/internal/storage/memory"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
@ -170,3 +171,34 @@ func Test_Session_Cookie(t *testing.T) {
|
||||
// cookie should not be set if empty data
|
||||
utils.AssertEqual(t, 0, len(ctx.Response().Header.PeekCookie(store.CookieName)))
|
||||
}
|
||||
|
||||
// go test -v -run=^$ -bench=Benchmark_Session -benchmem -count=4
|
||||
func Benchmark_Session(b *testing.B) {
|
||||
app, store := fiber.New(), New()
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
defer app.ReleaseCtx(c)
|
||||
c.Request().Header.SetCookie(store.CookieName, "12356789")
|
||||
|
||||
b.Run("default", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
sess, _ := store.Get(c)
|
||||
sess.Set("john", "doe")
|
||||
_ = sess.Save()
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("storage", func(b *testing.B) {
|
||||
store = New(Config{
|
||||
Storage: memory.New(),
|
||||
})
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
sess, _ := store.Get(c)
|
||||
sess.Set("john", "doe")
|
||||
_ = sess.Save()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,12 +1,15 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/internal/storage/memory"
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
Config
|
||||
mux *sync.RWMutex
|
||||
sessions map[string]*data
|
||||
}
|
||||
|
||||
// Storage ErrNotExist
|
||||
@ -16,46 +19,74 @@ func New(config ...Config) *Store {
|
||||
// Set default config
|
||||
cfg := configDefault(config...)
|
||||
|
||||
if cfg.Storage == nil {
|
||||
cfg.Storage = memory.New()
|
||||
// Create Store object
|
||||
store := &Store{
|
||||
Config: cfg,
|
||||
}
|
||||
|
||||
return &Store{
|
||||
cfg,
|
||||
// Default store logic (if no Storage is provided)
|
||||
if cfg.Storage == nil {
|
||||
store.mux = &sync.RWMutex{}
|
||||
store.sessions = make(map[string]*data)
|
||||
}
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func (s *Store) Get(c *fiber.Ctx) (*Session, error) {
|
||||
var fresh bool
|
||||
|
||||
// Get key from cookie
|
||||
// Get session id from cookie
|
||||
id := c.Cookies(s.CookieName)
|
||||
|
||||
// If no key exist, create new one
|
||||
// Create key if not exist
|
||||
if len(id) == 0 {
|
||||
id = s.KeyGenerator()
|
||||
fresh = true
|
||||
}
|
||||
|
||||
// Create session object
|
||||
// Get session object from pool
|
||||
sess := acquireSession()
|
||||
sess.id = id
|
||||
sess.fresh = fresh
|
||||
sess.ctx = c
|
||||
sess.config = s
|
||||
sess.id = id
|
||||
|
||||
// Fetch existing data
|
||||
if !fresh {
|
||||
// Get session data if not fresh
|
||||
if !sess.fresh {
|
||||
// Use external Storage if exist
|
||||
if s.Storage != nil {
|
||||
raw, err := s.Storage.Get(id)
|
||||
// Unmashal if we found data
|
||||
if err == nil {
|
||||
if _, err = sess.db.UnmarshalMsg(raw); err != nil {
|
||||
sess.data = acquireData()
|
||||
if _, err = sess.data.UnmarshalMsg(raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sess.fresh = false
|
||||
} else if err.Error() != errNotExist {
|
||||
// Only return error if it's not ErrNotExist
|
||||
return nil, err
|
||||
} else {
|
||||
// No data was found, this is now a fresh session
|
||||
sess.fresh = true
|
||||
}
|
||||
} else {
|
||||
// Find data in local memory map
|
||||
s.mux.RLock()
|
||||
data, ok := s.sessions[id]
|
||||
s.mux.RUnlock()
|
||||
if ok && data != nil {
|
||||
sess.data = data
|
||||
} else {
|
||||
// No data was found, this is now a fresh session
|
||||
sess.fresh = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get new kv store if nil
|
||||
if sess.data == nil {
|
||||
sess.data = acquireData()
|
||||
}
|
||||
|
||||
return sess, nil
|
||||
@ -63,5 +94,11 @@ func (s *Store) Get(c *fiber.Ctx) (*Session, error) {
|
||||
|
||||
// Reset will delete all session from the storage
|
||||
func (s *Store) Reset() error {
|
||||
if s.Storage != nil {
|
||||
return s.Storage.Reset()
|
||||
}
|
||||
s.mux.Lock()
|
||||
s.sessions = make(map[string]*data)
|
||||
s.mux.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user