-
Notifications
You must be signed in to change notification settings - Fork 0
/
redisstore.go
127 lines (111 loc) · 3.67 KB
/
redisstore.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package sessions
import (
"time"
"encoding/json"
"gopkg.in/redis.v5"
)
//redisKeyPrefix is the prefix we will use for keys
//related to session IDs. This keeps session ID keys
//separate from other keys in the shared redis key
//namespace.
const redisKeyPrefix = "sid:"
const defaultAddr = "127.0.0.1:6379"
//RedisStore represents a session.Store backed by redis.
type RedisStore struct {
//Redis client used to talk to redis server.
Client *redis.Client
//Used for key expiry time on redis.
SessionDuration time.Duration
}
//NewRedisStore constructs a new RedisStore, using the provided client and
//session duration. If the `client`` is nil, it will be set to redis.NewClient()
//pointing at a local redis instance. If `sessionDuration`` is negative, it will
//be set to `DefaultSessionDuration`.
func NewRedisStore(client *redis.Client, sessionDuration time.Duration) *RedisStore {
//set defaults for parameters
//if `client` is nil, set it to a redis.NewClient()
//pointing at a redis instance on the same machine
//i.e., Addr is "127.0.0.1"
if client == nil {
roptions := redis.Options{
Addr: defaultAddr,
}
client = redis.NewClient(&roptions)
}
//if `sessionDuration` is < 0
//set it to DefaultSessionDuration
if sessionDuration < 0 {
sessionDuration = DefaultSessionDuration
}
//return a new RedisStore with the Client field set to `client`
//and the SessionDuration field set to `sessionDuration`
return &RedisStore{
Client: client,
SessionDuration: sessionDuration,
}
}
//Store implementation
//Save associates the provided `state` data with the provided `sid` in the store.
func (rs *RedisStore) Save(sid SessionID, state interface{}) error {
//encode the `state` into JSON
jbuf, err := json.Marshal(state)
if err != nil {
return err
}
//use the redis client's Set() method, using `sid.getRedisKey()`
//as the key, the JSON as the data, and the store's session duration
//as the expiration
status := rs.Client.Set(sid.getRedisKey(), jbuf, rs.SessionDuration)
//Set() returns a StatusCmd, which has an .Err() method that will
//report any error that occurred; return the result of that method
return status.Err()
}
//Get retrieves the previously saved data for the session id,
//and populates the `state` parameter with it. This will also
//reset the data's time to live in the store.
func (rs *RedisStore) Get(sid SessionID, state interface{}) error {
// EXTRA CREDIT using the pipeline feature
// to do the .Get() and .Expire() commands
// in just one round-trip!
pipe := rs.Client.Pipeline()
cmd := pipe.Get(sid.getRedisKey())
pipe.Expire(sid.getRedisKey(), rs.SessionDuration)
// execute the pipeline and check for errors
_, err := pipe.Exec()
// the err of the pipe exec will be the first error returned
// check if it's the redis.Nil error meaning that the looked up key doesn't exist
if err != nil {
if err == redis.Nil {
return ErrStateNotFound
}
return err
}
// get the bytes from the get response and err
jbuf, err := cmd.Bytes()
if err != nil {
return err
}
//get the returned bytes and Unmarshal them into
//the `state` parameter
//if you get an error, return it
err = json.Unmarshal(jbuf, &state)
if err != nil {
return err
}
return nil
}
//Delete deletes all data associated with the session id from the store.
func (rs *RedisStore) Delete(sid SessionID) error {
//use the .Del() method to delete the data associated
//with the key `sid.getRedisKey()`, and use .Err()
//to report any errors that occurred
err := rs.Client.Del(sid.getRedisKey()).Err()
if err != nil {
return err
}
return nil
}
//returns the key to use in redis
func (sid SessionID) getRedisKey() string {
return redisKeyPrefix + sid.String()
}