Skip to content

Commit

Permalink
feat(session): add session purge
Browse files Browse the repository at this point in the history
Refs: #8
  • Loading branch information
piraz committed Jan 22, 2025
1 parent fab607b commit 97e4502
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 23 deletions.
33 changes: 31 additions & 2 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ type Engine interface {
Start() error
Stop() error
Store(string, any) error
Purge() error
}

type FileEngine struct {
Dir string
AgeLimit time.Duration
Dir string
Encoder
PurgeDuration time.Duration
}

func NewFileEngine() *FileEngine {
dir := filepath.Join(os.TempDir(), "httpok", "sess")
return &FileEngine{
AgeLimit: 30 * time.Minute,
Dir: dir,
Encoder: &JsonEncoder{},
PurgeDuration: 2 * time.Minute,
Expand All @@ -42,10 +45,10 @@ func (e *FileEngine) Read(sess string, v any) error {

buffer := make([]byte, 1024)
n, err := file.Read(buffer)

if err != nil {
return err
}

err = e.Encoder.Decode(buffer[:n], v)
if err != nil {
return err
Expand Down Expand Up @@ -78,6 +81,7 @@ func (e *FileEngine) Start() error {
"create the sesssion dir", e.Dir),
)
}
// TODO: start purge rotine

return nil
}
Expand All @@ -104,6 +108,31 @@ func (e *FileEngine) Store(sess string, v any) error {
return nil
}

func (e *FileEngine) Purge() error {

files, err := os.ReadDir(e.Dir)
if err != nil {
return err
}

for _, file := range files {
info, err := file.Info()
if err != nil {
return err
}
filePath := filepath.Join(e.Dir, file.Name())
age := time.Now().Sub(info.ModTime())
if age > e.AgeLimit {
err := os.Remove(filePath)
if err != nil {
return err
}
}
}

return nil
}

type Encoder interface {
Encode(any) ([]byte, error)
Decode([]byte, any) error
Expand Down
115 changes: 94 additions & 21 deletions session/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,114 @@ import (
"os"
"path/filepath"
"testing"
"time"

"github.com/candango/httpok/util"
"github.com/stretchr/testify/assert"
)

// TODO: We need to keep building the session engine tests
func TestSessionServer(t *testing.T) {
engine := NewFileEngine()
err := engine.Start()
func chFileTime(name string, mTime time.Time) error {
err := os.Chtimes(name, mTime, mTime)
if err != nil {
t.Error(err)
return err
}
return nil
}

func fileExists(name string) bool {
_, err := os.Stat(name)
if err != nil && os.IsNotExist(err) {
return false
}
return true
}

// TODO: We need to keep building the session engine tests
func TestSessionServer(t *testing.T) {
t.Run("Session store/read with json encoder", func(t *testing.T) {
engine := NewFileEngine()
err := engine.Start()
if err != nil {
t.Error(err)
}

sess := util.RandomString(64)

err = engine.Store(sess, map[string]interface{}{
"key": "value",
})
if err != nil {
t.Error(err)
}
var sessData map[string]interface{}

err = engine.Read(sess, &sessData)
if err != nil {
t.Error(err)
}

sess := util.RandomString(16)
assert.Equal(t, "value", sessData["key"])
defer func() {
sessFile := filepath.Join(engine.Dir, fmt.Sprintf("%s.sess", sess))
err := os.Remove(sessFile)
if err != nil {
t.Error(err)
}

err = engine.Store(sess, map[string]interface{}{
"key": "value",
}()
})
if err != nil {
t.Error(err)
}
var sessData map[string]interface{}

err = engine.Read(sess, &sessData)
if err != nil {
t.Error(err)
}
t.Run("Session purge", func(t *testing.T) {
engine := NewFileEngine()
err := engine.Start()
if err != nil {
t.Error(err)
}

sess1 := util.RandomString(64)
file1 := fmt.Sprintf("%s.sess", filepath.Join(engine.Dir, sess1))
sess2 := util.RandomString(64)
file2 := fmt.Sprintf("%s.sess", filepath.Join(engine.Dir, sess2))
sess3 := util.RandomString(64)
file3 := fmt.Sprintf("%s.sess", filepath.Join(engine.Dir, sess3))

assert.Equal(t, "value", sessData["key"])
defer func() {
sessFile := filepath.Join(engine.Dir, fmt.Sprintf("%s.sess", sess))
err := os.Remove(sessFile)
err = engine.Store(sess1, map[string]interface{}{
"key": "value",
})
assert.True(t, fileExists(file1))
err = engine.Store(sess2, map[string]interface{}{
"key": "value",
})
assert.True(t, fileExists(file2))
err = engine.Store(sess3, map[string]interface{}{
"key": "value",
})
assert.True(t, fileExists(file3))
if err != nil {
t.Error(err)
}

}()
oldTime := time.Date(2023, time.October, 1, 12, 0, 0, 0, time.UTC)
err = chFileTime(file1, oldTime)
if err != nil {
t.Error(err)
}
err = chFileTime(file2, oldTime)
if err != nil {
t.Error(err)
}

engine.Purge()

assert.False(t, fileExists(file1))
assert.False(t, fileExists(file2))
assert.True(t, fileExists(file3))

err = chFileTime(file3, oldTime)
if err != nil {
t.Error(err)
}
engine.Purge()
assert.False(t, fileExists(file3))
})
}

0 comments on commit 97e4502

Please sign in to comment.