Skip to content

Commit 09fc683

Browse files
committed
Add version 1.0.0
1 parent 0ff919f commit 09fc683

File tree

5 files changed

+511
-2
lines changed

5 files changed

+511
-2
lines changed

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2018 Golang Session
3+
Copyright (c) 2018 Lyric
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+95-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,96 @@
11
# redis
2-
A redis-based session store
2+
3+
> A redis-based session store
4+
5+
[![ReportCard][reportcard-image]][reportcard-url] [![GoDoc][godoc-image]][godoc-url] [![License][license-image]][license-url]
6+
7+
## Quick Start
8+
9+
### Download and install
10+
11+
```bash
12+
$ go get -u -v gopkg.in/go-session/redis.v1
13+
```
14+
15+
### Create file `server.go`
16+
17+
```go
18+
package main
19+
20+
import (
21+
"fmt"
22+
"net/http"
23+
24+
"gopkg.in/go-session/redis.v1"
25+
"gopkg.in/session.v2"
26+
)
27+
28+
func main() {
29+
session.InitManager(
30+
session.SetCookieName("session_id"),
31+
session.SetSign([]byte("sign")),
32+
session.SetStore(redis.NewRedisStore(&redis.Options{
33+
Addr: "127.0.0.1:6379",
34+
DB: 15,
35+
})),
36+
)
37+
38+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
39+
store, err := session.Start(w, r)
40+
if err != nil {
41+
fmt.Fprint(w, err)
42+
return
43+
}
44+
45+
store.Set("foo", "bar")
46+
err = store.Save()
47+
if err != nil {
48+
fmt.Fprint(w, err)
49+
return
50+
}
51+
52+
http.Redirect(w, r, "/foo", 302)
53+
})
54+
55+
http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
56+
store, err := session.Start(w, r)
57+
if err != nil {
58+
fmt.Fprint(w, err)
59+
return
60+
}
61+
62+
foo, ok := store.Get("foo")
63+
if ok {
64+
fmt.Fprintf(w, "foo:%s", foo)
65+
return
66+
}
67+
fmt.Fprint(w, "does not exist")
68+
})
69+
70+
http.ListenAndServe(":8080", nil)
71+
}
72+
```
73+
74+
### Build and run
75+
76+
```bash
77+
$ go build server.go
78+
$ ./server
79+
```
80+
81+
### Open in your web browser
82+
83+
<http://localhost:8080>
84+
85+
foo:bar
86+
87+
## MIT License
88+
89+
Copyright (c) 2018 Lyric
90+
91+
[reportcard-url]: https://goreportcard.com/report/gopkg.in/go-session/redis.v1
92+
[reportcard-image]: https://goreportcard.com/badge/gopkg.in/go-session/redis.v1
93+
[godoc-url]: https://godoc.org/gopkg.in/go-session/redis.v1
94+
[godoc-image]: https://godoc.org/gopkg.in/go-session/redis.v1?status.svg
95+
[license-url]: http://opensource.org/licenses/MIT
96+
[license-image]: https://img.shields.io/npm/l/express.svg

options.go

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package redis
2+
3+
import (
4+
"crypto/tls"
5+
"net"
6+
"time"
7+
8+
"github.com/go-redis/redis"
9+
)
10+
11+
// Options Redis parameter options
12+
type Options struct {
13+
// The network type, either tcp or unix.
14+
// Default is tcp.
15+
Network string
16+
// host:port address.
17+
Addr string
18+
19+
// Dialer creates new network connection and has priority over
20+
// Network and Addr options.
21+
Dialer func() (net.Conn, error)
22+
23+
// Optional password. Must match the password specified in the
24+
// requirepass server configuration option.
25+
Password string
26+
// Database to be selected after connecting to the server.
27+
DB int
28+
29+
// Maximum number of retries before giving up.
30+
// Default is to not retry failed commands.
31+
MaxRetries int
32+
// Minimum backoff between each retry.
33+
// Default is 8 milliseconds; -1 disables backoff.
34+
MinRetryBackoff time.Duration
35+
// Maximum backoff between each retry.
36+
// Default is 512 milliseconds; -1 disables backoff.
37+
MaxRetryBackoff time.Duration
38+
39+
// Dial timeout for establishing new connections.
40+
// Default is 5 seconds.
41+
DialTimeout time.Duration
42+
// Timeout for socket reads. If reached, commands will fail
43+
// with a timeout instead of blocking.
44+
// Default is 3 seconds.
45+
ReadTimeout time.Duration
46+
// Timeout for socket writes. If reached, commands will fail
47+
// with a timeout instead of blocking.
48+
// Default is ReadTimeout.
49+
WriteTimeout time.Duration
50+
51+
// Maximum number of socket connections.
52+
// Default is 10 connections per every CPU as reported by runtime.NumCPU.
53+
PoolSize int
54+
// Amount of time client waits for connection if all connections
55+
// are busy before returning an error.
56+
// Default is ReadTimeout + 1 second.
57+
PoolTimeout time.Duration
58+
// Amount of time after which client closes idle connections.
59+
// Should be less than server's timeout.
60+
// Default is 5 minutes.
61+
IdleTimeout time.Duration
62+
// Frequency of idle checks.
63+
// Default is 1 minute.
64+
// When minus value is set, then idle check is disabled.
65+
IdleCheckFrequency time.Duration
66+
67+
// TLS Config to use. When set TLS will be negotiated.
68+
TLSConfig *tls.Config
69+
}
70+
71+
func (o *Options) redisOptions() *redis.Options {
72+
return &redis.Options{
73+
Network: o.Network,
74+
Addr: o.Addr,
75+
Dialer: o.Dialer,
76+
Password: o.Password,
77+
DB: o.DB,
78+
MaxRetries: o.MaxRetries,
79+
MinRetryBackoff: o.MinRetryBackoff,
80+
MaxRetryBackoff: o.MaxRetryBackoff,
81+
DialTimeout: o.DialTimeout,
82+
ReadTimeout: o.ReadTimeout,
83+
WriteTimeout: o.WriteTimeout,
84+
PoolSize: o.PoolSize,
85+
PoolTimeout: o.PoolTimeout,
86+
IdleTimeout: o.IdleTimeout,
87+
IdleCheckFrequency: o.IdleCheckFrequency,
88+
TLSConfig: o.TLSConfig,
89+
}
90+
}

redis.go

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package redis
2+
3+
import (
4+
"encoding/json"
5+
"sync"
6+
"time"
7+
8+
"github.com/go-redis/redis"
9+
"gopkg.in/session.v2"
10+
)
11+
12+
var (
13+
_ session.ManagerStore = &managerStore{}
14+
_ session.Store = &store{}
15+
)
16+
17+
// NewRedisStore Create an instance of a redis store
18+
func NewRedisStore(opt *Options) session.ManagerStore {
19+
if opt == nil {
20+
panic("Option cannot be nil")
21+
}
22+
return &managerStore{cli: redis.NewClient(opt.redisOptions())}
23+
}
24+
25+
type managerStore struct {
26+
cli *redis.Client
27+
}
28+
29+
func (s *managerStore) getValue(sid string) (string, error) {
30+
cmd := s.cli.Get(sid)
31+
if err := cmd.Err(); err != nil {
32+
if err == redis.Nil {
33+
return "", nil
34+
}
35+
return "", err
36+
}
37+
38+
return cmd.Val(), nil
39+
}
40+
41+
func (s *managerStore) parseValue(value string) (map[string]string, error) {
42+
var values map[string]string
43+
44+
if len(value) > 0 {
45+
err := json.Unmarshal([]byte(value), &values)
46+
if err != nil {
47+
return nil, err
48+
}
49+
}
50+
51+
if values == nil {
52+
values = make(map[string]string)
53+
}
54+
return values, nil
55+
}
56+
57+
func (s *managerStore) Create(sid string, expired int64) (session.Store, error) {
58+
values := make(map[string]string)
59+
return &store{sid: sid, cli: s.cli, expired: expired, values: values}, nil
60+
}
61+
62+
func (s *managerStore) Update(sid string, expired int64) (session.Store, error) {
63+
value, err := s.getValue(sid)
64+
if err != nil {
65+
return nil, err
66+
} else if value == "" {
67+
return s.Create(sid, expired)
68+
}
69+
70+
cmd := s.cli.Set(sid, value, time.Duration(expired)*time.Second)
71+
if err = cmd.Err(); err != nil {
72+
return nil, err
73+
}
74+
75+
values, err := s.parseValue(value)
76+
if err != nil {
77+
return nil, err
78+
}
79+
80+
return &store{sid: sid, cli: s.cli, expired: expired, values: values}, nil
81+
}
82+
83+
func (s *managerStore) Delete(sid string) error {
84+
cmd := s.cli.Del(sid)
85+
return cmd.Err()
86+
}
87+
88+
func (s *managerStore) Check(sid string) (bool, error) {
89+
cmd := s.cli.Get(sid)
90+
if err := cmd.Err(); err != nil {
91+
if err == redis.Nil {
92+
return false, nil
93+
}
94+
return false, err
95+
}
96+
return true, nil
97+
}
98+
99+
func (s *managerStore) Close() error {
100+
return s.cli.Close()
101+
}
102+
103+
type store struct {
104+
sid string
105+
cli *redis.Client
106+
expired int64
107+
values map[string]string
108+
sync.RWMutex
109+
}
110+
111+
func (s *store) SessionID() string {
112+
return s.sid
113+
}
114+
115+
func (s *store) Set(key, value string) {
116+
s.Lock()
117+
s.values[key] = value
118+
s.Unlock()
119+
}
120+
121+
func (s *store) Get(key string) (string, bool) {
122+
s.RLock()
123+
defer s.RUnlock()
124+
val, ok := s.values[key]
125+
return val, ok
126+
}
127+
128+
func (s *store) Delete(key string) string {
129+
s.RLock()
130+
v, ok := s.values[key]
131+
s.RUnlock()
132+
if ok {
133+
s.Lock()
134+
delete(s.values, key)
135+
s.Unlock()
136+
}
137+
return v
138+
}
139+
140+
func (s *store) Flush() {
141+
s.Lock()
142+
s.values = make(map[string]string)
143+
s.Unlock()
144+
}
145+
146+
func (s *store) Save() error {
147+
var value string
148+
149+
s.RLock()
150+
if len(s.values) > 0 {
151+
buf, _ := json.Marshal(s.values)
152+
value = string(buf)
153+
}
154+
s.RUnlock()
155+
156+
cmd := s.cli.Set(s.sid, value, time.Duration(s.expired)*time.Second)
157+
return cmd.Err()
158+
}

0 commit comments

Comments
 (0)