Skip to content

Commit 32d4fbb

Browse files
author
pengwei
committed
Donn't override old value when seting same value
1 parent 5adcb1e commit 32d4fbb

File tree

5 files changed

+139
-120
lines changed

5 files changed

+139
-120
lines changed

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,24 @@ Use cookie as session, base on [secure cookie](https://github.com/go-http-utils/
1414
* Interfaces and infrastructure for custom session backends: sessions from
1515
different stores can be retrieved and batch-saved using a common API.
1616

17+
##Installation
18+
```go
19+
go get github.com/go-http-utils/cookie-session
20+
```
1721
##Examples
1822
```go
1923
go run cookiesession/main.go
2024
```
2125
##Usage
2226
```go
23-
store := sessions.New([]string{"key"})
27+
store := sessions.NewCookieStore([]string{"key"})
2428
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
25-
store.Init(w, r, false)
26-
session, _ := sessions.Get(sessionkey, store)
27-
session.Values["name"] = "mushroom"
28-
println(session.Values["name"].(string)) //get session
29+
session, _ := store.Get(sessionkey, w, r)
30+
if val, ok := session.Values["name"]; ok {
31+
println(val)
32+
} else {
33+
session.Values["name"] = "mushroom"
34+
}
2935
session.Save()
3036
})
3137
```

cookiesession/main.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,29 @@ func main() {
1111

1212
sessionkey := "sessionid"
1313

14+
store := sessions.NewCookieStore([]string{})
15+
1416
req, _ := http.NewRequest("GET", "/", nil)
1517

1618
recorder := httptest.NewRecorder()
1719
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
18-
19-
store := sessions.NewCookieStore([]string{"key"})
20-
21-
session, _ := sessions.New(sessionkey, store, w, r)
22-
23-
session.Values["name"] = "mushroom"
24-
20+
session, _ := store.Get(sessionkey, w, r)
21+
if val, ok := session.Values["name"]; ok {
22+
println(val)
23+
} else {
24+
session.Values["name"] = "mushroom"
25+
}
2526
session.Save()
26-
2727
})
2828
handler.ServeHTTP(recorder, req)
2929

3030
//======reuse=====
31+
store = sessions.NewCookieStore([]string{})
3132
cookies, _ := getCookie(sessionkey, recorder)
3233
req.AddCookie(cookies)
3334
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
34-
store := sessions.NewCookieStore([]string{"key"})
3535

36-
session, _ := sessions.New(sessionkey, store, w, r)
36+
session, _ := store.Get(sessionkey, w, r)
3737

3838
println(session.Values["name"].(string))
3939
})

cookiestore.go

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package sessions
22

33
import (
4-
"errors"
54
"net/http"
5+
"reflect"
66

77
"github.com/go-http-utils/cookie"
88
)
@@ -22,43 +22,42 @@ type Options struct {
2222
}
2323

2424
// NewCookieStore an CookieStore instance
25-
func NewCookieStore(Keys []string, options ...*Options) (store *CookieStore) {
26-
if len(Keys) == 0 {
27-
panic(errors.New("invalid keys parameter"))
28-
}
29-
store = &CookieStore{keys: Keys}
25+
func NewCookieStore(keys []string, options ...*Options) (store *CookieStore) {
26+
store = &CookieStore{keys: keys}
3027
if len(options) > 0 {
3128
store.options = options[0]
3229
}
30+
if len(keys) > 0 && len(keys[0]) > 0 {
31+
store.signed = true
32+
}
3333
return
3434
}
3535

3636
// CookieStore stores sessions using secure cookies.
3737
type CookieStore struct {
38-
cookie *cookie.Cookies
3938
options *Options
4039
keys []string
41-
signed bool // optional
42-
}
43-
44-
// Init an CookieStore instance
45-
func (c *CookieStore) Init(w http.ResponseWriter, r *http.Request, signed bool) {
46-
c.cookie = cookie.New(w, r, c.keys)
47-
c.signed = signed
48-
return
40+
signed bool
4941
}
5042

51-
// Get existed session from Request's cookies
52-
func (c *CookieStore) Get(name string) (data map[string]interface{}, err error) {
53-
val, _ := c.cookie.Get(name, c.signed)
43+
// Get a session instance by name and any kind of stores
44+
func (c *CookieStore) Get(name string, w http.ResponseWriter, r *http.Request) (session *Session, err error) {
45+
cookie := cookie.New(w, r, c.keys)
46+
session = NewSession(name, c, w, r)
47+
val, _ := cookie.Get(name, c.signed)
5448
if val != "" {
55-
Decode(val, &data)
49+
Decode(val, &session.Values)
5650
}
51+
session.AddCache("cookie", cookie)
52+
session.AddCache("lastvalue", session.Values)
5753
return
5854
}
5955

6056
// Save session to Response's cookie
61-
func (c *CookieStore) Save(name string, data map[string]interface{}) (err error) {
57+
func (c *CookieStore) Save(w http.ResponseWriter, r *http.Request, session *Session) (err error) {
58+
if reflect.DeepEqual(session.GetCache("lastvalue"), session.Values) {
59+
return
60+
}
6261
opts := &cookie.Options{
6362
Path: "/",
6463
HTTPOnly: true,
@@ -72,9 +71,9 @@ func (c *CookieStore) Save(name string, data map[string]interface{}) (err error)
7271
opts.Secure = c.options.Secure
7372
opts.HTTPOnly = c.options.HTTPOnly
7473
}
75-
val, err := Encode(data)
74+
val, err := Encode(session.Values)
7675
if err == nil {
77-
c.cookie.Set(name, val, opts)
76+
session.GetCache("cookie").(*cookie.Cookies).Set(session.Name(), val, opts)
7877
}
7978
return
8079
}

sessions.go

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,26 @@ import (
88

99
// Session stores the values and optional configuration for a session.
1010
type Session struct {
11-
sid string
1211
Values map[string]interface{}
12+
SID string
1313
store Store
1414
name string
15-
//oldval string
15+
cache map[string]interface{}
16+
w http.ResponseWriter
17+
req *http.Request
18+
}
19+
20+
// NewSession to create new session instance
21+
func NewSession(name string, store Store, w http.ResponseWriter, r *http.Request) (session *Session) {
22+
session = &Session{
23+
Values: make(map[string]interface{}),
24+
store: store,
25+
name: name,
26+
w: w,
27+
req: r,
28+
cache: make(map[string]interface{}),
29+
}
30+
return
1631
}
1732

1833
// Name returns the name used to register the session
@@ -25,50 +40,37 @@ func (s *Session) Store() Store {
2540
return s.store
2641
}
2742

28-
// New a session instance by name and any kind of stores
29-
func New(name string, store Store, w http.ResponseWriter, r *http.Request, signed ...bool) (session *Session, err error) {
30-
session = &Session{
31-
store: store,
32-
name: name,
33-
}
34-
var issigned = false
35-
if len(signed) > 0 {
36-
issigned = signed[0]
37-
}
38-
store.Init(w, r, issigned)
39-
session.Values, err = store.Get(name)
40-
41-
if session.Values == nil {
42-
session.Values = make(map[string]interface{})
43+
// AddCache to add data cache for thirdparty store implement, like store the last value to check whether changed when saving
44+
func (s *Session) AddCache(key string, val interface{}) {
45+
switch v := val.(type) {
46+
case map[string]interface{}:
47+
s.cache[key] = copyMap(val.(map[string]interface{}))
48+
default:
49+
s.cache[key] = v
4350
}
44-
return
4551
}
4652

47-
// New a new session instance by name base on current store
48-
func (s *Session) New(name string) *Session {
49-
session := &Session{
50-
Values: make(map[string]interface{}),
51-
store: s.store,
52-
name: name,
53+
func copyMap(cache map[string]interface{}) (data map[string]interface{}) {
54+
data = make(map[string]interface{})
55+
for k, v := range cache {
56+
switch val := v.(type) {
57+
case map[string]interface{}:
58+
data[k] = copyMap(val)
59+
default:
60+
data[k] = val
61+
}
5362
}
54-
return session
63+
return
5564
}
5665

57-
// Get a new session instance by name base on current store
58-
func (s *Session) Get(name string) (session *Session, err error) {
59-
session = &Session{
60-
61-
Values: make(map[string]interface{}),
62-
store: s.store,
63-
name: name,
64-
}
65-
session.Values, err = s.store.Get(session.name)
66-
return
66+
// GetCache cache data from current Session
67+
func (s *Session) GetCache(name string) interface{} {
68+
return s.cache[name]
6769
}
6870

6971
// Save is a convenience method to save current session
7072
func (s *Session) Save() (err error) {
71-
s.store.Save(s.name, s.Values)
73+
s.store.Save(s.w, s.req, s)
7274
return
7375
}
7476

@@ -97,11 +99,9 @@ func Decode(value string, dst interface{}) (err error) {
9799

98100
// Store is an interface for custom session stores.
99101
type Store interface {
100-
Init(w http.ResponseWriter, r *http.Request, signed bool)
101-
102102
// Get should return a cached session string.
103-
Get(name string) (map[string]interface{}, error)
103+
Get(name string, w http.ResponseWriter, r *http.Request) (session *Session, err error)
104104

105105
// Save should persist session to the underlying store implementation.
106-
Save(name string, data map[string]interface{}) error
106+
Save(w http.ResponseWriter, r *http.Request, session *Session) error
107107
}

0 commit comments

Comments
 (0)