mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
add grand.D for random time.Duration;add checking and removing session files for package gsession
This commit is contained in:
@ -7,11 +7,11 @@
|
||||
package gsession
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"github.com/gogf/gf/util/grand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@ -36,10 +36,12 @@ type StorageFile struct {
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultStorageFilePath = gfile.TempDir("gsessions")
|
||||
DefaultStorageFileCryptoKey = []byte("Session storage file crypto key!")
|
||||
DefaultStorageFileCryptoEnabled = false
|
||||
DefaultStorageFileLoopInterval = 10 * time.Second
|
||||
DefaultStorageFilePath = gfile.TempDir("gsessions")
|
||||
DefaultStorageFileCryptoKey = []byte("Session storage file crypto key!")
|
||||
DefaultStorageFileCryptoEnabled = false
|
||||
DefaultStorageFileLoopInterval = 10 * time.Second
|
||||
DefaultStorageFileRemoveIntervalMin = time.Hour
|
||||
DefaultStorageFileRemoveIntervalMax = time.Hour * 24
|
||||
)
|
||||
|
||||
// NewStorageFile creates and returns a file storage object for session.
|
||||
@ -48,10 +50,10 @@ func NewStorageFile(path ...string) *StorageFile {
|
||||
if len(path) > 0 && path[0] != "" {
|
||||
storagePath, _ = gfile.Search(path[0])
|
||||
if storagePath == "" {
|
||||
panic(fmt.Sprintf("'%s' does not exist", path[0]))
|
||||
panic(gerror.Newf("'%s' does not exist", path[0]))
|
||||
}
|
||||
if !gfile.IsWritable(storagePath) {
|
||||
panic(fmt.Sprintf("'%s' is not writable", path[0]))
|
||||
panic(gerror.Newf("'%s' is not writable", path[0]))
|
||||
}
|
||||
}
|
||||
if storagePath != "" {
|
||||
@ -65,24 +67,61 @@ func NewStorageFile(path ...string) *StorageFile {
|
||||
cryptoEnabled: DefaultStorageFileCryptoEnabled,
|
||||
updatingIdSet: gset.NewStrSet(true),
|
||||
}
|
||||
// Batch updates the TTL for session ids timely.
|
||||
gtimer.AddSingleton(DefaultStorageFileLoopInterval, func() {
|
||||
//intlog.Print("StorageFile.timer start")
|
||||
var (
|
||||
id string
|
||||
err error
|
||||
)
|
||||
for {
|
||||
if id = s.updatingIdSet.Pop(); id == "" {
|
||||
break
|
||||
}
|
||||
if err = s.doUpdateTTL(id); err != nil {
|
||||
intlog.Error(err)
|
||||
|
||||
gtimer.AddSingleton(DefaultStorageFileLoopInterval, s.updateSessionTimely)
|
||||
gtimer.AddOnce(
|
||||
grand.D(DefaultStorageFileRemoveIntervalMin, DefaultStorageFileRemoveIntervalMax),
|
||||
s.checkAndRemoveSessionTimely,
|
||||
)
|
||||
return s
|
||||
}
|
||||
|
||||
// updateSessionTimely batch updates the TTL for sessions timely.
|
||||
func (s *StorageFile) updateSessionTimely() {
|
||||
var (
|
||||
id string
|
||||
err error
|
||||
)
|
||||
// Batch updating sessions.
|
||||
for {
|
||||
if id = s.updatingIdSet.Pop(); id == "" {
|
||||
break
|
||||
}
|
||||
if err = s.updateSessionTTl(id); err != nil {
|
||||
intlog.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkAndRemoveSessionTimely checks the session storage directory path and removes the expired session files.
|
||||
func (s *StorageFile) checkAndRemoveSessionTimely() {
|
||||
defer gtimer.AddOnce(
|
||||
grand.D(DefaultStorageFileRemoveIntervalMin, DefaultStorageFileRemoveIntervalMax),
|
||||
s.checkAndRemoveSessionTimely,
|
||||
)
|
||||
|
||||
var (
|
||||
timestampMilliFile int64
|
||||
timestampMilliNow = gtime.Now().TimestampMilli()
|
||||
files, _ = gfile.ScanDirFile(s.path, "*")
|
||||
timestampMilliBytes = make([]byte, 8)
|
||||
)
|
||||
for _, path := range files {
|
||||
file, err := gfile.OpenWithFlag(path, os.O_RDONLY)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if _, err := file.Read(timestampMilliBytes); err == nil {
|
||||
timestampMilliFile = gbinary.DecodeToInt64(timestampMilliBytes)
|
||||
if timestampMilliNow >= timestampMilliFile {
|
||||
intlog.Printf(
|
||||
"remove expired session file: %s, result:%v",
|
||||
path, gfile.Remove(path),
|
||||
)
|
||||
}
|
||||
}
|
||||
//intlog.Print("StorageFile.timer end")
|
||||
})
|
||||
return s
|
||||
file.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// SetCryptoKey sets the crypto key for session storage.
|
||||
@ -229,9 +268,9 @@ func (s *StorageFile) UpdateTTL(id string, ttl time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// doUpdateTTL updates the TTL for session id.
|
||||
func (s *StorageFile) doUpdateTTL(id string) error {
|
||||
intlog.Printf("StorageFile.doUpdateTTL: %s", id)
|
||||
// updateSessionTTL updates the TTL for specified session id.
|
||||
func (s *StorageFile) updateSessionTTl(id string) error {
|
||||
intlog.Printf("StorageFile.updateSession: %s", id)
|
||||
path := s.sessionFilePath(id)
|
||||
file, err := gfile.OpenWithFlag(path, os.O_WRONLY)
|
||||
if err != nil {
|
||||
|
||||
@ -9,6 +9,7 @@ package grand
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@ -97,6 +98,20 @@ func S(n int, symbols ...bool) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// D returns a random time.Duration between min and max: [min, max].
|
||||
func D(min, max time.Duration) time.Duration {
|
||||
multiple := 1
|
||||
if min != 0 {
|
||||
for min%10 == 0 {
|
||||
multiple *= 10
|
||||
min /= 10
|
||||
max /= 10
|
||||
}
|
||||
}
|
||||
n := N(int(min), int(max))
|
||||
return time.Duration(n * multiple)
|
||||
}
|
||||
|
||||
// Str randomly picks and returns <n> count of chars from given string <s>.
|
||||
// It also supports unicode string like Chinese/Russian/Japanese, etc.
|
||||
func Str(s string, n int) string {
|
||||
|
||||
@ -11,6 +11,7 @@ package grand_test
|
||||
import (
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/grand"
|
||||
@ -73,6 +74,23 @@ func Test_N(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_D(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
t.Assert(grand.D(time.Second, time.Second), time.Second)
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
t.Assert(grand.D(0, 0), time.Duration(0))
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
t.AssertIN(
|
||||
grand.D(1*time.Second, 3*time.Second),
|
||||
[]time.Duration{1 * time.Second, 2 * time.Second, 3 * time.Second},
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Rand(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
|
||||
Reference in New Issue
Block a user