mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
MySQL session: fixed problem using mysql as session store, Fixes #1681
This commit is contained in:
parent
4af1dcd54f
commit
7eb45e1799
@ -1,5 +1,7 @@
|
||||
# 2.0.0-RC1 (unreleased)
|
||||
|
||||
**FIxes**
|
||||
- [Issue #1681](https://github.com/grafana/grafana/issues/1681). MySQL session: fixed problem using mysql as session store
|
||||
- [Issue #1671](https://github.com/grafana/grafana/issues/1671). Data sources: Fixed issue with changing default data source (should not require full page load to take effect, now fixed)
|
||||
|
||||
# 2.0.0-Beta1 (2015-03-30)
|
||||
|
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
@ -47,7 +47,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/macaron-contrib/session",
|
||||
"Rev": "65b8817c40cb5bdce08673a15fd2a648c2ba0e16"
|
||||
"Rev": "31e841d95c7302b9ac456c830ea2d6dfcef4f84a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-sqlite3",
|
||||
|
2
Godeps/_workspace/src/github.com/macaron-contrib/session/.gitignore
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/macaron-contrib/session/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
ledis/tmp.db
|
||||
nodb/tmp.db
|
6
Godeps/_workspace/src/github.com/macaron-contrib/session/README.md
generated
vendored
6
Godeps/_workspace/src/github.com/macaron-contrib/session/README.md
generated
vendored
@ -1,7 +1,7 @@
|
||||
session [](https://drone.io/github.com/macaron-contrib/session/latest) [](http://gocover.io/github.com/macaron-contrib/session)
|
||||
=======
|
||||
|
||||
Middleware session provides session management for [Macaron](https://github.com/Unknwon/macaron). It can use many session providers, including memory, file, Redis, Memcache, PostgreSQL, MySQL, Couchbase and Ledis.
|
||||
Middleware session provides session management for [Macaron](https://github.com/Unknwon/macaron). It can use many session providers, including memory, file, Redis, Memcache, PostgreSQL, MySQL, Couchbase, Ledis and Nodb.
|
||||
|
||||
### Installation
|
||||
|
||||
@ -12,6 +12,10 @@ Middleware session provides session management for [Macaron](https://github.com/
|
||||
- [API Reference](https://gowalker.org/github.com/macaron-contrib/session)
|
||||
- [Documentation](http://macaron.gogs.io/docs/middlewares/session)
|
||||
|
||||
## Credits
|
||||
|
||||
This package is forked from [beego/session](https://github.com/astaxie/beego/tree/master/session) with reconstruction(over 80%).
|
||||
|
||||
## License
|
||||
|
||||
This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.
|
||||
|
40
Godeps/_workspace/src/github.com/macaron-contrib/session/file.go
generated
vendored
40
Godeps/_workspace/src/github.com/macaron-contrib/session/file.go
generated
vendored
@ -28,17 +28,17 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
)
|
||||
|
||||
// FileSessionStore represents a file session store implementation.
|
||||
type FileSessionStore struct {
|
||||
// FileStore represents a file session store implementation.
|
||||
type FileStore struct {
|
||||
p *FileProvider
|
||||
sid string
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// NewFileSessionStore creates and returns a file session store.
|
||||
func NewFileSessionStore(p *FileProvider, sid string, kv map[interface{}]interface{}) *FileSessionStore {
|
||||
return &FileSessionStore{
|
||||
// NewFileStore creates and returns a file session store.
|
||||
func NewFileStore(p *FileProvider, sid string, kv map[interface{}]interface{}) *FileStore {
|
||||
return &FileStore{
|
||||
p: p,
|
||||
sid: sid,
|
||||
data: kv,
|
||||
@ -46,7 +46,7 @@ func NewFileSessionStore(p *FileProvider, sid string, kv map[interface{}]interfa
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *FileSessionStore) Set(key, val interface{}) error {
|
||||
func (s *FileStore) Set(key, val interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -55,7 +55,7 @@ func (s *FileSessionStore) Set(key, val interface{}) error {
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *FileSessionStore) Get(key interface{}) interface{} {
|
||||
func (s *FileStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
@ -63,7 +63,7 @@ func (s *FileSessionStore) Get(key interface{}) interface{} {
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *FileSessionStore) Delete(key interface{}) error {
|
||||
func (s *FileStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -72,12 +72,12 @@ func (s *FileSessionStore) Delete(key interface{}) error {
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *FileSessionStore) ID() string {
|
||||
func (s *FileStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// Release releases resource and save data to provider.
|
||||
func (s *FileSessionStore) Release() error {
|
||||
func (s *FileStore) Release() error {
|
||||
data, err := EncodeGob(s.data)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -87,7 +87,7 @@ func (s *FileSessionStore) Release() error {
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *FileSessionStore) Flush() error {
|
||||
func (s *FileStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -97,7 +97,6 @@ func (s *FileSessionStore) Flush() error {
|
||||
|
||||
// FileProvider represents a file session provider implementation.
|
||||
type FileProvider struct {
|
||||
lock sync.RWMutex
|
||||
maxlifetime int64
|
||||
rootPath string
|
||||
}
|
||||
@ -115,9 +114,6 @@ func (p *FileProvider) filepath(sid string) string {
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
filename := p.filepath(sid)
|
||||
if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
@ -151,22 +147,16 @@ func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return NewFileSessionStore(p, sid, kv), nil
|
||||
return NewFileStore(p, sid, kv), nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *FileProvider) Exist(sid string) bool {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
return com.IsFile(p.filepath(sid))
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *FileProvider) Destory(sid string) error {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
return os.Remove(p.filepath(sid))
|
||||
}
|
||||
|
||||
@ -201,12 +191,9 @@ func (p *FileProvider) regenerate(oldsid, sid string) (err error) {
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *FileProvider) Regenerate(oldsid, sid string) (_ RawStore, err error) {
|
||||
p.lock.Lock()
|
||||
if err := p.regenerate(oldsid, sid); err != nil {
|
||||
p.lock.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
p.lock.Unlock()
|
||||
|
||||
return p.Read(sid)
|
||||
}
|
||||
@ -236,9 +223,6 @@ func (p *FileProvider) GC() {
|
||||
return
|
||||
}
|
||||
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
|
149
Godeps/_workspace/src/github.com/macaron-contrib/session/ledis/ledis.go
generated
vendored
149
Godeps/_workspace/src/github.com/macaron-contrib/session/ledis/ledis.go
generated
vendored
@ -16,26 +16,39 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
var c *ledis.DB
|
||||
|
||||
// LedisSessionStore represents a ledis session store implementation.
|
||||
type LedisSessionStore struct {
|
||||
// LedisStore represents a ledis session store implementation.
|
||||
type LedisStore struct {
|
||||
c *ledis.DB
|
||||
sid string
|
||||
expire int64
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
maxlifetime int64
|
||||
}
|
||||
|
||||
// NewLedisStore creates and returns a ledis session store.
|
||||
func NewLedisStore(c *ledis.DB, sid string, expire int64, kv map[interface{}]interface{}) *LedisStore {
|
||||
return &LedisStore{
|
||||
c: c,
|
||||
expire: expire,
|
||||
sid: sid,
|
||||
data: kv,
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *LedisSessionStore) Set(key, val interface{}) error {
|
||||
func (s *LedisStore) Set(key, val interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -44,7 +57,7 @@ func (s *LedisSessionStore) Set(key, val interface{}) error {
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *LedisSessionStore) Get(key interface{}) interface{} {
|
||||
func (s *LedisStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
@ -52,7 +65,7 @@ func (s *LedisSessionStore) Get(key interface{}) interface{} {
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *LedisSessionStore) Delete(key interface{}) error {
|
||||
func (s *LedisStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -61,25 +74,26 @@ func (s *LedisSessionStore) Delete(key interface{}) error {
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *LedisSessionStore) ID() string {
|
||||
func (s *LedisStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// Release releases resource and save data to provider.
|
||||
func (s *LedisSessionStore) Release() error {
|
||||
func (s *LedisStore) Release() error {
|
||||
data, err := session.EncodeGob(s.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = c.Set([]byte(s.sid), data); err != nil {
|
||||
|
||||
if err = s.c.Set([]byte(s.sid), data); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.Expire([]byte(s.sid), s.maxlifetime)
|
||||
_, err = s.c.Expire([]byte(s.sid), s.expire)
|
||||
return err
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *LedisSessionStore) Flush() error {
|
||||
func (s *LedisStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -89,30 +103,54 @@ func (s *LedisSessionStore) Flush() error {
|
||||
|
||||
// LedisProvider represents a ledis session provider implementation.
|
||||
type LedisProvider struct {
|
||||
maxlifetime int64
|
||||
savePath string
|
||||
c *ledis.DB
|
||||
expire int64
|
||||
}
|
||||
|
||||
// Init initializes memory session provider.
|
||||
func (p *LedisProvider) Init(maxlifetime int64, savePath string) error {
|
||||
p.maxlifetime = maxlifetime
|
||||
p.savePath = savePath
|
||||
cfg := new(config.Config)
|
||||
cfg.DataDir = p.savePath
|
||||
var err error
|
||||
nowLedis, err := ledis.Open(cfg)
|
||||
c, err = nowLedis.Select(0)
|
||||
// Init initializes ledis session provider.
|
||||
// configs: data_dir=./app.db,db=0
|
||||
func (p *LedisProvider) Init(expire int64, configs string) error {
|
||||
p.expire = expire
|
||||
|
||||
cfg, err := ini.Load([]byte(strings.Replace(configs, ",", "\n", -1)))
|
||||
if err != nil {
|
||||
println(err)
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
db := 0
|
||||
opt := new(config.Config)
|
||||
for k, v := range cfg.Section("").KeysHash() {
|
||||
switch k {
|
||||
case "data_dir":
|
||||
opt.DataDir = v
|
||||
case "db":
|
||||
db = com.StrTo(v).MustInt()
|
||||
default:
|
||||
return fmt.Errorf("session/ledis: unsupported option '%s'", k)
|
||||
}
|
||||
}
|
||||
|
||||
l, err := ledis.Open(opt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("session/ledis: error opening db: %v", err)
|
||||
}
|
||||
p.c, err = l.Select(db)
|
||||
return err
|
||||
}
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *LedisProvider) Read(sid string) (session.RawStore, error) {
|
||||
kvs, err := c.Get([]byte(sid))
|
||||
if !p.Exist(sid) {
|
||||
if err := p.c.Set([]byte(sid), []byte("")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
kvs, err := p.c.Get([]byte(sid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(kvs) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
@ -121,41 +159,40 @@ func (p *LedisProvider) Read(sid string) (session.RawStore, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ls := &LedisSessionStore{sid: sid, data: kv, maxlifetime: p.maxlifetime}
|
||||
return ls, nil
|
||||
|
||||
return NewLedisStore(p.c, sid, p.expire, kv), nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *LedisProvider) Exist(sid string) bool {
|
||||
count, _ := c.Exists([]byte(sid))
|
||||
if count == 0 {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
count, err := p.c.Exists([]byte(sid))
|
||||
return err == nil && count > 0
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *LedisProvider) Destory(sid string) error {
|
||||
_, err := c.Del([]byte(sid))
|
||||
_, err := p.c.Del([]byte(sid))
|
||||
return err
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *LedisProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
|
||||
count, _ := c.Exists([]byte(sid))
|
||||
if count == 0 {
|
||||
// oldsid doesn't exists, set the new sid directly
|
||||
// ignore error here, since if it return error
|
||||
// the existed value will be 0
|
||||
c.Set([]byte(sid), []byte(""))
|
||||
c.Expire([]byte(sid), p.maxlifetime)
|
||||
} else {
|
||||
data, _ := c.Get([]byte(oldsid))
|
||||
c.Set([]byte(sid), data)
|
||||
c.Expire([]byte(sid), p.maxlifetime)
|
||||
func (p *LedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
|
||||
if p.Exist(sid) {
|
||||
return nil, fmt.Errorf("new sid '%s' already exists", sid)
|
||||
}
|
||||
kvs, err := c.Get([]byte(sid))
|
||||
|
||||
kvs := make([]byte, 0)
|
||||
if p.Exist(oldsid) {
|
||||
if kvs, err = p.c.Get([]byte(oldsid)); err != nil {
|
||||
return nil, err
|
||||
} else if _, err = p.c.Del([]byte(oldsid)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = p.c.SetEX([]byte(sid), p.expire, kvs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
if len(kvs) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
@ -165,18 +202,20 @@ func (p *LedisProvider) Regenerate(oldsid, sid string) (session.RawStore, error)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ls := &LedisSessionStore{sid: sid, data: kv, maxlifetime: p.maxlifetime}
|
||||
return ls, nil
|
||||
|
||||
return NewLedisStore(p.c, sid, p.expire, kv), nil
|
||||
}
|
||||
|
||||
// Count counts and returns number of sessions.
|
||||
func (p *LedisProvider) Count() int {
|
||||
// FIXME
|
||||
return 0
|
||||
// FIXME: how come this library does not have DbSize() method?
|
||||
return -1
|
||||
}
|
||||
|
||||
// GC calls GC to clean expired sessions.
|
||||
func (p *LedisProvider) GC() {}
|
||||
func (p *LedisProvider) GC() {
|
||||
// FIXME: wtf???
|
||||
}
|
||||
|
||||
func init() {
|
||||
session.Register("ledis", &LedisProvider{})
|
||||
|
1
Godeps/_workspace/src/github.com/macaron-contrib/session/ledis/ledis.goconvey
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/macaron-contrib/session/ledis/ledis.goconvey
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
ignore
|
105
Godeps/_workspace/src/github.com/macaron-contrib/session/ledis/ledis_test.go
generated
vendored
Normal file
105
Godeps/_workspace/src/github.com/macaron-contrib/session/ledis/ledis_test.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
func Test_LedisProvider(t *testing.T) {
|
||||
Convey("Test ledis session provider", t, func() {
|
||||
opt := session.Options{
|
||||
Provider: "ledis",
|
||||
ProviderConfig: "data_dir=./tmp.db",
|
||||
}
|
||||
|
||||
Convey("Basic operation", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
sess.Set("uname", "unknwon")
|
||||
})
|
||||
m.Get("/reg", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := raw.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
})
|
||||
m.Get("/get", func(ctx *macaron.Context, sess session.Store) {
|
||||
sid := sess.ID()
|
||||
So(sid, ShouldNotBeEmpty)
|
||||
|
||||
raw, err := sess.Read(sid)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := sess.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
|
||||
So(sess.Delete("uname"), ShouldBeNil)
|
||||
So(sess.Get("uname"), ShouldBeNil)
|
||||
|
||||
So(sess.Destory(ctx), ShouldBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie := resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/reg", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie = resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
Convey("Regenrate empty session", func() {
|
||||
m.Get("/empty", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/empty", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", "MacaronSession=ad2c7e3cbecfcf486; Path=/;")
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
206
Godeps/_workspace/src/github.com/macaron-contrib/session/memcache/memcache.go
generated
vendored
206
Godeps/_workspace/src/github.com/macaron-contrib/session/memcache/memcache.go
generated
vendored
@ -16,6 +16,7 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -24,20 +25,35 @@ import (
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
var (
|
||||
client *memcache.Client
|
||||
)
|
||||
|
||||
// MemcacheSessionStore represents a memcache session store implementation.
|
||||
type MemcacheSessionStore struct {
|
||||
// MemcacheStore represents a memcache session store implementation.
|
||||
type MemcacheStore struct {
|
||||
c *memcache.Client
|
||||
sid string
|
||||
expire int32
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
maxlifetime int64
|
||||
}
|
||||
|
||||
// NewMemcacheStore creates and returns a memcache session store.
|
||||
func NewMemcacheStore(c *memcache.Client, sid string, expire int32, kv map[interface{}]interface{}) *MemcacheStore {
|
||||
return &MemcacheStore{
|
||||
c: c,
|
||||
sid: sid,
|
||||
expire: expire,
|
||||
data: kv,
|
||||
}
|
||||
}
|
||||
|
||||
func NewItem(sid string, data []byte, expire int32) *memcache.Item {
|
||||
return &memcache.Item{
|
||||
Key: sid,
|
||||
Value: data,
|
||||
Expiration: expire,
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *MemcacheSessionStore) Set(key, val interface{}) error {
|
||||
func (s *MemcacheStore) Set(key, val interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -46,7 +62,7 @@ func (s *MemcacheSessionStore) Set(key, val interface{}) error {
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *MemcacheSessionStore) Get(key interface{}) interface{} {
|
||||
func (s *MemcacheStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
@ -54,7 +70,7 @@ func (s *MemcacheSessionStore) Get(key interface{}) interface{} {
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *MemcacheSessionStore) Delete(key interface{}) error {
|
||||
func (s *MemcacheStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -63,26 +79,22 @@ func (s *MemcacheSessionStore) Delete(key interface{}) error {
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *MemcacheSessionStore) ID() string {
|
||||
func (s *MemcacheStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// Release releases resource and save data to provider.
|
||||
func (s *MemcacheSessionStore) Release() error {
|
||||
func (s *MemcacheStore) Release() error {
|
||||
data, err := session.EncodeGob(s.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.Set(&memcache.Item{
|
||||
Key: s.sid,
|
||||
Value: data,
|
||||
Expiration: int32(s.maxlifetime),
|
||||
})
|
||||
return s.c.Set(NewItem(s.sid, data, s.expire))
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *MemcacheSessionStore) Flush() error {
|
||||
func (s *MemcacheStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -90,41 +102,75 @@ func (s *MemcacheSessionStore) Flush() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MemProvider represents a memcache session provider implementation.
|
||||
type MemProvider struct {
|
||||
maxlifetime int64
|
||||
conninfo []string
|
||||
poolsize int
|
||||
password string
|
||||
// MemcacheProvider represents a memcache session provider implementation.
|
||||
type MemcacheProvider struct {
|
||||
c *memcache.Client
|
||||
expire int32
|
||||
}
|
||||
|
||||
// Init initializes memory session provider.
|
||||
// connStrs can be multiple connection strings separate by ;
|
||||
// e.g. 127.0.0.1:9090
|
||||
func (p *MemProvider) Init(maxlifetime int64, connStrs string) error {
|
||||
p.maxlifetime = maxlifetime
|
||||
p.conninfo = strings.Split(connStrs, ";")
|
||||
client = memcache.New(p.conninfo...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *MemProvider) connectInit() error {
|
||||
client = memcache.New(p.conninfo...)
|
||||
// Init initializes memcache session provider.
|
||||
// connStrs: 127.0.0.1:9090;127.0.0.1:9091
|
||||
func (p *MemcacheProvider) Init(expire int64, connStrs string) error {
|
||||
p.expire = int32(expire)
|
||||
p.c = memcache.New(strings.Split(connStrs, ";")...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *MemProvider) Read(sid string) (session.RawStore, error) {
|
||||
if client == nil {
|
||||
if err := p.connectInit(); err != nil {
|
||||
func (p *MemcacheProvider) Read(sid string) (session.RawStore, error) {
|
||||
if !p.Exist(sid) {
|
||||
if err := p.c.Set(NewItem(sid, []byte(""), p.expire)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
item, err := client.Get(sid)
|
||||
var kv map[interface{}]interface{}
|
||||
item, err := p.c.Get(sid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(item.Value) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
kv, err = session.DecodeGob(item.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return NewMemcacheStore(p.c, sid, p.expire, kv), nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *MemcacheProvider) Exist(sid string) bool {
|
||||
_, err := p.c.Get(sid)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *MemcacheProvider) Destory(sid string) error {
|
||||
return p.c.Delete(sid)
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *MemcacheProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
|
||||
if p.Exist(sid) {
|
||||
return nil, fmt.Errorf("new sid '%s' already exists", sid)
|
||||
}
|
||||
|
||||
item := NewItem(sid, []byte(""), p.expire)
|
||||
if p.Exist(oldsid) {
|
||||
item, err = p.c.Get(oldsid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if err = p.c.Delete(oldsid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item.Key = sid
|
||||
}
|
||||
if err = p.c.Set(item); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
if len(item.Value) == 0 {
|
||||
@ -136,86 +182,18 @@ func (p *MemProvider) Read(sid string) (session.RawStore, error) {
|
||||
}
|
||||
}
|
||||
|
||||
rs := &MemcacheSessionStore{sid: sid, data: kv, maxlifetime: p.maxlifetime}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *MemProvider) Exist(sid string) bool {
|
||||
if client == nil {
|
||||
if err := p.connectInit(); err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if item, err := client.Get(sid); err != nil || len(item.Value) == 0 {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *MemProvider) Destory(sid string) error {
|
||||
if client == nil {
|
||||
if err := p.connectInit(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return client.Delete(sid)
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *MemProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
|
||||
if client == nil {
|
||||
if err := p.connectInit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var contain []byte
|
||||
if item, err := client.Get(sid); err != nil || len(item.Value) == 0 {
|
||||
// oldsid doesn't exists, set the new sid directly
|
||||
// ignore error here, since if it return error
|
||||
// the existed value will be 0
|
||||
item.Key = sid
|
||||
item.Value = []byte("")
|
||||
item.Expiration = int32(p.maxlifetime)
|
||||
client.Set(item)
|
||||
} else {
|
||||
client.Delete(oldsid)
|
||||
item.Key = sid
|
||||
item.Value = item.Value
|
||||
item.Expiration = int32(p.maxlifetime)
|
||||
client.Set(item)
|
||||
contain = item.Value
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
if len(contain) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
var err error
|
||||
kv, err = session.DecodeGob(contain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
rs := &MemcacheSessionStore{sid: sid, data: kv, maxlifetime: p.maxlifetime}
|
||||
return rs, nil
|
||||
return NewMemcacheStore(p.c, sid, p.expire, kv), nil
|
||||
}
|
||||
|
||||
// Count counts and returns number of sessions.
|
||||
func (p *MemProvider) Count() int {
|
||||
// FIXME
|
||||
return 0
|
||||
func (p *MemcacheProvider) Count() int {
|
||||
// FIXME: how come this library does not have Stats method?
|
||||
return -1
|
||||
}
|
||||
|
||||
// GC calls GC to clean expired sessions.
|
||||
func (p *MemProvider) GC() {}
|
||||
func (p *MemcacheProvider) GC() {}
|
||||
|
||||
func init() {
|
||||
session.Register("memcache", &MemProvider{})
|
||||
session.Register("memcache", &MemcacheProvider{})
|
||||
}
|
||||
|
1
Godeps/_workspace/src/github.com/macaron-contrib/session/memcache/memcache.goconvey
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/macaron-contrib/session/memcache/memcache.goconvey
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
ignore
|
107
Godeps/_workspace/src/github.com/macaron-contrib/session/memcache/memcache_test.go
generated
vendored
Normal file
107
Godeps/_workspace/src/github.com/macaron-contrib/session/memcache/memcache_test.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
func Test_MemcacheProvider(t *testing.T) {
|
||||
Convey("Test memcache session provider", t, func() {
|
||||
opt := session.Options{
|
||||
Provider: "memcache",
|
||||
ProviderConfig: "127.0.0.1:9090",
|
||||
}
|
||||
|
||||
Convey("Basic operation", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
sess.Set("uname", "unknwon")
|
||||
})
|
||||
m.Get("/reg", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := raw.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
})
|
||||
m.Get("/get", func(ctx *macaron.Context, sess session.Store) {
|
||||
sid := sess.ID()
|
||||
So(sid, ShouldNotBeEmpty)
|
||||
|
||||
raw, err := sess.Read(sid)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := sess.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
|
||||
So(sess.Delete("uname"), ShouldBeNil)
|
||||
So(sess.Get("uname"), ShouldBeNil)
|
||||
|
||||
So(sess.Destory(ctx), ShouldBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie := resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/reg", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie = resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Regenrate empty session", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", "MacaronSession=ad2c7e3cbecfcf486; Path=/;")
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
})
|
||||
}
|
36
Godeps/_workspace/src/github.com/macaron-contrib/session/memory.go
generated
vendored
36
Godeps/_workspace/src/github.com/macaron-contrib/session/memory.go
generated
vendored
@ -22,17 +22,17 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// MemSessionStore represents a in-memory session store implementation.
|
||||
type MemSessionStore struct {
|
||||
// MemStore represents a in-memory session store implementation.
|
||||
type MemStore struct {
|
||||
sid string
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
lastAccess time.Time
|
||||
}
|
||||
|
||||
// NewMemSessionStore creates and returns a memory session store.
|
||||
func NewMemSessionStore(sid string) *MemSessionStore {
|
||||
return &MemSessionStore{
|
||||
// NewMemStore creates and returns a memory session store.
|
||||
func NewMemStore(sid string) *MemStore {
|
||||
return &MemStore{
|
||||
sid: sid,
|
||||
data: make(map[interface{}]interface{}),
|
||||
lastAccess: time.Now(),
|
||||
@ -40,7 +40,7 @@ func NewMemSessionStore(sid string) *MemSessionStore {
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *MemSessionStore) Set(key, val interface{}) error {
|
||||
func (s *MemStore) Set(key, val interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -49,15 +49,15 @@ func (s *MemSessionStore) Set(key, val interface{}) error {
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *MemSessionStore) Get(key interface{}) interface{} {
|
||||
func (s *MemStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return s.data[key]
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *MemSessionStore) Delete(key interface{}) error {
|
||||
// Delete deletes a key from session.
|
||||
func (s *MemStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -66,17 +66,17 @@ func (s *MemSessionStore) Delete(key interface{}) error {
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *MemSessionStore) ID() string {
|
||||
func (s *MemStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// Release releases resource and save data to provider.
|
||||
func (_ *MemSessionStore) Release() error {
|
||||
func (_ *MemStore) Release() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *MemSessionStore) Flush() error {
|
||||
func (s *MemStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -105,7 +105,7 @@ func (p *MemProvider) update(sid string) error {
|
||||
defer p.lock.Unlock()
|
||||
|
||||
if e, ok := p.data[sid]; ok {
|
||||
e.Value.(*MemSessionStore).lastAccess = time.Now()
|
||||
e.Value.(*MemStore).lastAccess = time.Now()
|
||||
p.list.MoveToFront(e)
|
||||
return nil
|
||||
}
|
||||
@ -122,14 +122,14 @@ func (p *MemProvider) Read(sid string) (_ RawStore, err error) {
|
||||
if err = p.update(sid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.Value.(*MemSessionStore), nil
|
||||
return e.Value.(*MemStore), nil
|
||||
}
|
||||
|
||||
// Create a new session.
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
s := NewMemSessionStore(sid)
|
||||
s := NewMemStore(sid)
|
||||
p.data[sid] = p.list.PushBack(s)
|
||||
return s, nil
|
||||
}
|
||||
@ -173,7 +173,7 @@ func (p *MemProvider) Regenerate(oldsid, sid string) (RawStore, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.(*MemSessionStore).sid = sid
|
||||
s.(*MemStore).sid = sid
|
||||
p.data[sid] = p.list.PushBack(s)
|
||||
return s, nil
|
||||
}
|
||||
@ -193,11 +193,11 @@ func (p *MemProvider) GC() {
|
||||
break
|
||||
}
|
||||
|
||||
if (e.Value.(*MemSessionStore).lastAccess.Unix() + p.maxLifetime) < time.Now().Unix() {
|
||||
if (e.Value.(*MemStore).lastAccess.Unix() + p.maxLifetime) < time.Now().Unix() {
|
||||
p.lock.RUnlock()
|
||||
p.lock.Lock()
|
||||
p.list.Remove(e)
|
||||
delete(p.data, e.Value.(*MemSessionStore).sid)
|
||||
delete(p.data, e.Value.(*MemStore).sid)
|
||||
p.lock.Unlock()
|
||||
p.lock.RLock()
|
||||
} else {
|
||||
|
146
Godeps/_workspace/src/github.com/macaron-contrib/session/mysql/mysql.go
generated
vendored
146
Godeps/_workspace/src/github.com/macaron-contrib/session/mysql/mysql.go
generated
vendored
@ -17,6 +17,8 @@ package session
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -25,16 +27,25 @@ import (
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
// MysqlSessionStore represents a mysql session store implementation.
|
||||
type MysqlSessionStore struct {
|
||||
// MysqlStore represents a mysql session store implementation.
|
||||
type MysqlStore struct {
|
||||
c *sql.DB
|
||||
sid string
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// NewMysqlStore creates and returns a mysql session store.
|
||||
func NewMysqlStore(c *sql.DB, sid string, kv map[interface{}]interface{}) *MysqlStore {
|
||||
return &MysqlStore{
|
||||
c: c,
|
||||
sid: sid,
|
||||
data: kv,
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *MysqlSessionStore) Set(key, val interface{}) error {
|
||||
func (s *MysqlStore) Set(key, val interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -43,7 +54,7 @@ func (s *MysqlSessionStore) Set(key, val interface{}) error {
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *MysqlSessionStore) Get(key interface{}) interface{} {
|
||||
func (s *MysqlStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
@ -51,7 +62,7 @@ func (s *MysqlSessionStore) Get(key interface{}) interface{} {
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *MysqlSessionStore) Delete(key interface{}) error {
|
||||
func (s *MysqlStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -60,24 +71,24 @@ func (s *MysqlSessionStore) Delete(key interface{}) error {
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *MysqlSessionStore) ID() string {
|
||||
func (s *MysqlStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// Release releases resource and save data to provider.
|
||||
func (s *MysqlSessionStore) Release() error {
|
||||
defer s.c.Close()
|
||||
func (s *MysqlStore) Release() error {
|
||||
data, err := session.EncodeGob(s.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.c.Exec("UPDATE session set `session_data`=?, `session_expiry`=? where session_key=?",
|
||||
|
||||
_, err = s.c.Exec("UPDATE session SET data=?, expiry=? WHERE `key`=?",
|
||||
data, time.Now().Unix(), s.sid)
|
||||
return err
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *MysqlSessionStore) Flush() error {
|
||||
func (s *MysqlStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -87,113 +98,96 @@ func (s *MysqlSessionStore) Flush() error {
|
||||
|
||||
// MysqlProvider represents a mysql session provider implementation.
|
||||
type MysqlProvider struct {
|
||||
maxlifetime int64
|
||||
connStr string
|
||||
c *sql.DB
|
||||
expire int64
|
||||
}
|
||||
|
||||
func (p *MysqlProvider) connectInit() *sql.DB {
|
||||
db, e := sql.Open("mysql", p.connStr)
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
return db
|
||||
}
|
||||
// Init initializes mysql session provider.
|
||||
// connStr: username:password@protocol(address)/dbname?param=value
|
||||
func (p *MysqlProvider) Init(expire int64, connStr string) (err error) {
|
||||
p.expire = expire
|
||||
|
||||
// Init initializes memory session provider.
|
||||
func (p *MysqlProvider) Init(maxlifetime int64, connStr string) error {
|
||||
p.maxlifetime = maxlifetime
|
||||
p.connStr = connStr
|
||||
return nil
|
||||
p.c, err = sql.Open("mysql", connStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.c.Ping()
|
||||
}
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *MysqlProvider) Read(sid string) (session.RawStore, error) {
|
||||
c := p.connectInit()
|
||||
row := c.QueryRow("select session_data from session where session_key=?", sid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
var data []byte
|
||||
err := p.c.QueryRow("SELECT data FROM session WHERE `key`=?", sid).Scan(&data)
|
||||
if err == sql.ErrNoRows {
|
||||
c.Exec("insert into session(`session_key`,`session_data`,`session_expiry`) values(?,?,?)",
|
||||
_, err = p.c.Exec("INSERT INTO session(`key`,data,expiry) VALUES(?,?,?)",
|
||||
sid, "", time.Now().Unix())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
if len(sessiondata) == 0 {
|
||||
if len(data) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
kv, err = session.DecodeGob(sessiondata)
|
||||
kv, err = session.DecodeGob(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
rs := &MysqlSessionStore{c: c, sid: sid, data: kv}
|
||||
return rs, nil
|
||||
|
||||
return NewMysqlStore(p.c, sid, kv), nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *MysqlProvider) Exist(sid string) bool {
|
||||
c := p.connectInit()
|
||||
defer c.Close()
|
||||
|
||||
row := c.QueryRow("select session_data from session where session_key=?", sid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
if err == sql.ErrNoRows {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
var data []byte
|
||||
err := p.c.QueryRow("SELECT data FROM session WHERE `key`=?", sid).Scan(&data)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
panic("session/mysql: error checking existence: " + err.Error())
|
||||
}
|
||||
return err != sql.ErrNoRows
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *MysqlProvider) Destory(sid string) (err error) {
|
||||
c := p.connectInit()
|
||||
if _, err = c.Exec("DELETE FROM session where session_key=?", sid); err != nil {
|
||||
func (p *MysqlProvider) Destory(sid string) error {
|
||||
_, err := p.c.Exec("DELETE FROM session WHERE `key`=?", sid)
|
||||
return err
|
||||
}
|
||||
return c.Close()
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *MysqlProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
|
||||
c := p.connectInit()
|
||||
row := c.QueryRow("select session_data from session where session_key=?", oldsid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
if err == sql.ErrNoRows {
|
||||
c.Exec("insert into session(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", oldsid, "", time.Now().Unix())
|
||||
func (p *MysqlProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
|
||||
if p.Exist(sid) {
|
||||
return nil, fmt.Errorf("new sid '%s' already exists", sid)
|
||||
}
|
||||
c.Exec("update session set `session_key`=? where session_key=?", sid, oldsid)
|
||||
var kv map[interface{}]interface{}
|
||||
if len(sessiondata) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
kv, err = session.DecodeGob(sessiondata)
|
||||
if err != nil {
|
||||
|
||||
if !p.Exist(oldsid) {
|
||||
if _, err = p.c.Exec("INSERT INTO session(`key`,data,expiry) VALUES(?,?,?)",
|
||||
oldsid, "", time.Now().Unix()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
rs := &MysqlSessionStore{c: c, sid: sid, data: kv}
|
||||
return rs, nil
|
||||
|
||||
if _, err = p.c.Exec("UPDATE session SET `key`=? WHERE `key`=?", sid, oldsid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.Read(sid)
|
||||
}
|
||||
|
||||
// Count counts and returns number of sessions.
|
||||
func (p *MysqlProvider) Count() int {
|
||||
c := p.connectInit()
|
||||
defer c.Close()
|
||||
|
||||
var total int
|
||||
err := c.QueryRow("SELECT count(*) as num from session").Scan(&total)
|
||||
if err != nil {
|
||||
return 0
|
||||
func (p *MysqlProvider) Count() (total int) {
|
||||
if err := p.c.QueryRow("SELECT COUNT(*) AS NUM FROM session").Scan(&total); err != nil {
|
||||
panic("session/mysql: error counting records: " + err.Error())
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// GC calls GC to clean expired sessions.
|
||||
func (mp *MysqlProvider) GC() {
|
||||
c := mp.connectInit()
|
||||
c.Exec("DELETE from session where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
|
||||
c.Close()
|
||||
func (p *MysqlProvider) GC() {
|
||||
if _, err := p.c.Exec("DELETE FROM session WHERE UNIX_TIMESTAMP(NOW()) - expiry > ?", p.expire); err != nil {
|
||||
log.Printf("session/mysql: error garbage collecting: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
1
Godeps/_workspace/src/github.com/macaron-contrib/session/mysql/mysql.goconvey
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/macaron-contrib/session/mysql/mysql.goconvey
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
ignore
|
138
Godeps/_workspace/src/github.com/macaron-contrib/session/mysql/mysql_test.go
generated
vendored
Normal file
138
Godeps/_workspace/src/github.com/macaron-contrib/session/mysql/mysql_test.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
func Test_MysqlProvider(t *testing.T) {
|
||||
Convey("Test mysql session provider", t, func() {
|
||||
opt := session.Options{
|
||||
Provider: "mysql",
|
||||
ProviderConfig: "root:@tcp(localhost:3306)/macaron?charset=utf8",
|
||||
}
|
||||
|
||||
Convey("Basic operation", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
sess.Set("uname", "unknwon")
|
||||
})
|
||||
m.Get("/reg", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := raw.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
})
|
||||
m.Get("/get", func(ctx *macaron.Context, sess session.Store) {
|
||||
sid := sess.ID()
|
||||
So(sid, ShouldNotBeEmpty)
|
||||
|
||||
raw, err := sess.Read(sid)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
So(raw.Release(), ShouldBeNil)
|
||||
|
||||
uname := sess.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
|
||||
So(sess.Delete("uname"), ShouldBeNil)
|
||||
So(sess.Get("uname"), ShouldBeNil)
|
||||
|
||||
So(sess.Destory(ctx), ShouldBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie := resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/reg", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie = resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Regenrate empty session", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
So(sess.Destory(ctx), ShouldBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", "MacaronSession=ad2c7e3cbecfcf48; Path=/;")
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("GC session", func() {
|
||||
m := macaron.New()
|
||||
opt2 := opt
|
||||
opt2.Gclifetime = 1
|
||||
m.Use(session.Sessioner(opt2))
|
||||
|
||||
m.Get("/", func(sess session.Store) {
|
||||
sess.Set("uname", "unknwon")
|
||||
So(sess.ID(), ShouldNotBeEmpty)
|
||||
uname := sess.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
|
||||
So(sess.Flush(), ShouldBeNil)
|
||||
So(sess.Get("uname"), ShouldBeNil)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
sess.GC()
|
||||
So(sess.Count(), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
})
|
||||
}
|
203
Godeps/_workspace/src/github.com/macaron-contrib/session/nodb/nodb.go
generated
vendored
Normal file
203
Godeps/_workspace/src/github.com/macaron-contrib/session/nodb/nodb.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
// Copyright 2015 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/lunny/nodb"
|
||||
"github.com/lunny/nodb/config"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
// NodbStore represents a nodb session store implementation.
|
||||
type NodbStore struct {
|
||||
c *nodb.DB
|
||||
sid string
|
||||
expire int64
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// NewNodbStore creates and returns a ledis session store.
|
||||
func NewNodbStore(c *nodb.DB, sid string, expire int64, kv map[interface{}]interface{}) *NodbStore {
|
||||
return &NodbStore{
|
||||
c: c,
|
||||
expire: expire,
|
||||
sid: sid,
|
||||
data: kv,
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *NodbStore) Set(key, val interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data[key] = val
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *NodbStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return s.data[key]
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *NodbStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
delete(s.data, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *NodbStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// Release releases resource and save data to provider.
|
||||
func (s *NodbStore) Release() error {
|
||||
data, err := session.EncodeGob(s.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = s.c.Set([]byte(s.sid), data); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.c.Expire([]byte(s.sid), s.expire)
|
||||
return err
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *NodbStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data = make(map[interface{}]interface{})
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodbProvider represents a ledis session provider implementation.
|
||||
type NodbProvider struct {
|
||||
c *nodb.DB
|
||||
expire int64
|
||||
}
|
||||
|
||||
// Init initializes nodb session provider.
|
||||
func (p *NodbProvider) Init(expire int64, configs string) error {
|
||||
p.expire = expire
|
||||
|
||||
cfg := new(config.Config)
|
||||
cfg.DataDir = configs
|
||||
dbs, err := nodb.Open(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("session/nodb: error opening db: %v", err)
|
||||
}
|
||||
|
||||
p.c, err = dbs.Select(0)
|
||||
return err
|
||||
}
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *NodbProvider) Read(sid string) (session.RawStore, error) {
|
||||
if !p.Exist(sid) {
|
||||
if err := p.c.Set([]byte(sid), []byte("")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
kvs, err := p.c.Get([]byte(sid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(kvs) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
kv, err = session.DecodeGob(kvs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return NewNodbStore(p.c, sid, p.expire, kv), nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *NodbProvider) Exist(sid string) bool {
|
||||
count, err := p.c.Exists([]byte(sid))
|
||||
return err == nil && count > 0
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *NodbProvider) Destory(sid string) error {
|
||||
_, err := p.c.Del([]byte(sid))
|
||||
return err
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *NodbProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
|
||||
if p.Exist(sid) {
|
||||
return nil, fmt.Errorf("new sid '%s' already exists", sid)
|
||||
}
|
||||
|
||||
kvs := make([]byte, 0)
|
||||
if p.Exist(oldsid) {
|
||||
if kvs, err = p.c.Get([]byte(oldsid)); err != nil {
|
||||
return nil, err
|
||||
} else if _, err = p.c.Del([]byte(oldsid)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err = p.c.Set([]byte(sid), kvs); err != nil {
|
||||
return nil, err
|
||||
} else if _, err = p.c.Expire([]byte(sid), p.expire); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
if len(kvs) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
kv, err = session.DecodeGob([]byte(kvs))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return NewNodbStore(p.c, sid, p.expire, kv), nil
|
||||
}
|
||||
|
||||
// Count counts and returns number of sessions.
|
||||
func (p *NodbProvider) Count() int {
|
||||
// FIXME: how come this library does not have DbSize() method?
|
||||
return -1
|
||||
}
|
||||
|
||||
// GC calls GC to clean expired sessions.
|
||||
func (p *NodbProvider) GC() {}
|
||||
|
||||
func init() {
|
||||
session.Register("nodb", &NodbProvider{})
|
||||
}
|
1
Godeps/_workspace/src/github.com/macaron-contrib/session/nodb/nodb.goconvey
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/macaron-contrib/session/nodb/nodb.goconvey
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
ignore
|
105
Godeps/_workspace/src/github.com/macaron-contrib/session/nodb/nodb_test.go
generated
vendored
Normal file
105
Godeps/_workspace/src/github.com/macaron-contrib/session/nodb/nodb_test.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright 2015 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
func Test_LedisProvider(t *testing.T) {
|
||||
Convey("Test nodb session provider", t, func() {
|
||||
opt := session.Options{
|
||||
Provider: "nodb",
|
||||
ProviderConfig: "./tmp.db",
|
||||
}
|
||||
|
||||
Convey("Basic operation", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
sess.Set("uname", "unknwon")
|
||||
})
|
||||
m.Get("/reg", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := raw.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
})
|
||||
m.Get("/get", func(ctx *macaron.Context, sess session.Store) {
|
||||
sid := sess.ID()
|
||||
So(sid, ShouldNotBeEmpty)
|
||||
|
||||
raw, err := sess.Read(sid)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := sess.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
|
||||
So(sess.Delete("uname"), ShouldBeNil)
|
||||
So(sess.Get("uname"), ShouldBeNil)
|
||||
|
||||
So(sess.Destory(ctx), ShouldBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie := resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/reg", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie = resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
Convey("Regenrate empty session", func() {
|
||||
m.Get("/empty", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/empty", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", "MacaronSession=ad2c7e3cbecfcf486; Path=/;")
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
196
Godeps/_workspace/src/github.com/macaron-contrib/session/postgres/postgres.go
generated
vendored
Normal file
196
Godeps/_workspace/src/github.com/macaron-contrib/session/postgres/postgres.go
generated
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
// Copyright 2013 Beego Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
// PostgresStore represents a postgres session store implementation.
|
||||
type PostgresStore struct {
|
||||
c *sql.DB
|
||||
sid string
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// NewPostgresStore creates and returns a postgres session store.
|
||||
func NewPostgresStore(c *sql.DB, sid string, kv map[interface{}]interface{}) *PostgresStore {
|
||||
return &PostgresStore{
|
||||
c: c,
|
||||
sid: sid,
|
||||
data: kv,
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *PostgresStore) Set(key, value interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *PostgresStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return s.data[key]
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *PostgresStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
delete(s.data, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *PostgresStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// save postgres session values to database.
|
||||
// must call this method to save values to database.
|
||||
func (s *PostgresStore) Release() error {
|
||||
data, err := session.EncodeGob(s.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.c.Exec("UPDATE session SET data=$1, expiry=$2 WHERE key=$3",
|
||||
data, time.Now().Unix(), s.sid)
|
||||
return err
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *PostgresStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data = make(map[interface{}]interface{})
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostgresProvider represents a postgres session provider implementation.
|
||||
type PostgresProvider struct {
|
||||
c *sql.DB
|
||||
maxlifetime int64
|
||||
}
|
||||
|
||||
// Init initializes postgres session provider.
|
||||
// connStr: user=a password=b host=localhost port=5432 dbname=c sslmode=disable
|
||||
func (p *PostgresProvider) Init(maxlifetime int64, connStr string) (err error) {
|
||||
p.maxlifetime = maxlifetime
|
||||
|
||||
p.c, err = sql.Open("postgres", connStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.c.Ping()
|
||||
}
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *PostgresProvider) Read(sid string) (session.RawStore, error) {
|
||||
var data []byte
|
||||
err := p.c.QueryRow("SELECT data FROM session WHERE key=$1", sid).Scan(&data)
|
||||
if err == sql.ErrNoRows {
|
||||
_, err = p.c.Exec("INSERT INTO session(key,data,expiry) VALUES($1,$2,$3)",
|
||||
sid, "", time.Now().Unix())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
if len(data) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
kv, err = session.DecodeGob(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return NewPostgresStore(p.c, sid, kv), nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *PostgresProvider) Exist(sid string) bool {
|
||||
var data []byte
|
||||
err := p.c.QueryRow("SELECT data FROM session WHERE key=$1", sid).Scan(&data)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
panic("session/postgres: error checking existence: " + err.Error())
|
||||
}
|
||||
return err != sql.ErrNoRows
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *PostgresProvider) Destory(sid string) error {
|
||||
_, err := p.c.Exec("DELETE FROM session WHERE key=$1", sid)
|
||||
return err
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *PostgresProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
|
||||
if p.Exist(sid) {
|
||||
return nil, fmt.Errorf("new sid '%s' already exists", sid)
|
||||
}
|
||||
|
||||
if !p.Exist(oldsid) {
|
||||
if _, err = p.c.Exec("INSERT INTO session(key,data,expiry) VALUES($1,$2,$3)",
|
||||
oldsid, "", time.Now().Unix()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = p.c.Exec("UPDATE session SET key=$1 WHERE key=$2", sid, oldsid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.Read(sid)
|
||||
}
|
||||
|
||||
// Count counts and returns number of sessions.
|
||||
func (p *PostgresProvider) Count() (total int) {
|
||||
if err := p.c.QueryRow("SELECT COUNT(*) AS NUM FROM session").Scan(&total); err != nil {
|
||||
panic("session/postgres: error counting records: " + err.Error())
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// GC calls GC to clean expired sessions.
|
||||
func (p *PostgresProvider) GC() {
|
||||
if _, err := p.c.Exec("DELETE FROM session WHERE EXTRACT(EPOCH FROM NOW()) - expiry > $1", p.maxlifetime); err != nil {
|
||||
log.Printf("session/postgres: error garbage collecting: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
session.Register("postgres", &PostgresProvider{})
|
||||
}
|
1
Godeps/_workspace/src/github.com/macaron-contrib/session/postgres/postgres.goconvey
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/macaron-contrib/session/postgres/postgres.goconvey
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
ignore
|
138
Godeps/_workspace/src/github.com/macaron-contrib/session/postgres/postgres_test.go
generated
vendored
Normal file
138
Godeps/_workspace/src/github.com/macaron-contrib/session/postgres/postgres_test.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
func Test_PostgresProvider(t *testing.T) {
|
||||
Convey("Test postgres session provider", t, func() {
|
||||
opt := session.Options{
|
||||
Provider: "postgres",
|
||||
ProviderConfig: "user=jiahuachen dbname=macaron port=5432 sslmode=disable",
|
||||
}
|
||||
|
||||
Convey("Basic operation", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
sess.Set("uname", "unknwon")
|
||||
})
|
||||
m.Get("/reg", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := raw.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
})
|
||||
m.Get("/get", func(ctx *macaron.Context, sess session.Store) {
|
||||
sid := sess.ID()
|
||||
So(sid, ShouldNotBeEmpty)
|
||||
|
||||
raw, err := sess.Read(sid)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
So(raw.Release(), ShouldBeNil)
|
||||
|
||||
uname := sess.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
|
||||
So(sess.Delete("uname"), ShouldBeNil)
|
||||
So(sess.Get("uname"), ShouldBeNil)
|
||||
|
||||
So(sess.Destory(ctx), ShouldBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie := resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/reg", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie = resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Regenrate empty session", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
So(sess.Destory(ctx), ShouldBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", "MacaronSession=ad2c7e3cbecfcf48; Path=/;")
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("GC session", func() {
|
||||
m := macaron.New()
|
||||
opt2 := opt
|
||||
opt2.Gclifetime = 1
|
||||
m.Use(session.Sessioner(opt2))
|
||||
|
||||
m.Get("/", func(sess session.Store) {
|
||||
sess.Set("uname", "unknwon")
|
||||
So(sess.ID(), ShouldNotBeEmpty)
|
||||
uname := sess.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
|
||||
So(sess.Flush(), ShouldBeNil)
|
||||
So(sess.Get("uname"), ShouldBeNil)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
sess.GC()
|
||||
So(sess.Count(), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
})
|
||||
}
|
211
Godeps/_workspace/src/github.com/macaron-contrib/session/postgres/postgresql.go
generated
vendored
211
Godeps/_workspace/src/github.com/macaron-contrib/session/postgres/postgresql.go
generated
vendored
@ -1,211 +0,0 @@
|
||||
// Copyright 2013 Beego Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
// PostgresqlSessionStore represents a postgresql session store implementation.
|
||||
type PostgresqlSessionStore struct {
|
||||
c *sql.DB
|
||||
sid string
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *PostgresqlSessionStore) Set(key, value interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *PostgresqlSessionStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return s.data[key]
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *PostgresqlSessionStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
delete(s.data, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *PostgresqlSessionStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// save postgresql session values to database.
|
||||
// must call this method to save values to database.
|
||||
func (s *PostgresqlSessionStore) Release() error {
|
||||
defer s.c.Close()
|
||||
|
||||
data, err := session.EncodeGob(s.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.c.Exec("UPDATE session set session_data=$1, session_expiry=$2 where session_key=$3",
|
||||
data, time.Now().Format(time.RFC3339), s.sid)
|
||||
return err
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *PostgresqlSessionStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data = make(map[interface{}]interface{})
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostgresqlProvider represents a postgresql session provider implementation.
|
||||
type PostgresqlProvider struct {
|
||||
maxlifetime int64
|
||||
connStr string
|
||||
}
|
||||
|
||||
func (p *PostgresqlProvider) connectInit() *sql.DB {
|
||||
db, e := sql.Open("postgres", p.connStr)
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
// Init initializes memory session provider.
|
||||
func (p *PostgresqlProvider) Init(maxlifetime int64, connStr string) error {
|
||||
p.maxlifetime = maxlifetime
|
||||
p.connStr = connStr
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *PostgresqlProvider) Read(sid string) (session.RawStore, error) {
|
||||
c := p.connectInit()
|
||||
row := c.QueryRow("select session_data from session where session_key=$1", sid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
if err == sql.ErrNoRows {
|
||||
_, err = c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)",
|
||||
sid, "", time.Now().Format(time.RFC3339))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kv map[interface{}]interface{}
|
||||
if len(sessiondata) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
kv, err = session.DecodeGob(sessiondata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
rs := &PostgresqlSessionStore{c: c, sid: sid, data: kv}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *PostgresqlProvider) Exist(sid string) bool {
|
||||
c := p.connectInit()
|
||||
defer c.Close()
|
||||
row := c.QueryRow("select session_data from session where session_key=$1", sid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *PostgresqlProvider) Destory(sid string) (err error) {
|
||||
c := p.connectInit()
|
||||
if _, err = c.Exec("DELETE FROM session where session_key=$1", sid); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Close()
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *PostgresqlProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
|
||||
c := p.connectInit()
|
||||
row := c.QueryRow("select session_data from session where session_key=$1", oldsid)
|
||||
var sessiondata []byte
|
||||
err := row.Scan(&sessiondata)
|
||||
if err == sql.ErrNoRows {
|
||||
c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)",
|
||||
oldsid, "", time.Now().Format(time.RFC3339))
|
||||
}
|
||||
c.Exec("update session set session_key=$1 where session_key=$2", sid, oldsid)
|
||||
var kv map[interface{}]interface{}
|
||||
if len(sessiondata) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
kv, err = session.DecodeGob(sessiondata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
rs := &PostgresqlSessionStore{c: c, sid: sid, data: kv}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
// Count counts and returns number of sessions.
|
||||
func (p *PostgresqlProvider) Count() int {
|
||||
c := p.connectInit()
|
||||
defer c.Close()
|
||||
var total int
|
||||
err := c.QueryRow("SELECT count(*) as num from session").Scan(&total)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// GC calls GC to clean expired sessions.
|
||||
func (mp *PostgresqlProvider) GC() {
|
||||
c := mp.connectInit()
|
||||
c.Exec("DELETE from session where EXTRACT(EPOCH FROM (current_timestamp - session_expiry)) > $1", mp.maxlifetime)
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func init() {
|
||||
session.Register("postgresql", &PostgresqlProvider{})
|
||||
}
|
193
Godeps/_workspace/src/github.com/macaron-contrib/session/redis/redis.go
generated
vendored
193
Godeps/_workspace/src/github.com/macaron-contrib/session/redis/redis.go
generated
vendored
@ -16,31 +16,39 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/beego/redigo/redis"
|
||||
"github.com/Unknwon/com"
|
||||
"gopkg.in/ini.v1"
|
||||
"gopkg.in/redis.v2"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
// redis max pool size
|
||||
var MAX_POOL_SIZE = 100
|
||||
|
||||
var redisPool chan redis.Conn
|
||||
|
||||
// RedisSessionStore represents a redis session store implementation.
|
||||
type RedisSessionStore struct {
|
||||
p *redis.Pool
|
||||
// RedisStore represents a redis session store implementation.
|
||||
type RedisStore struct {
|
||||
c *redis.Client
|
||||
sid string
|
||||
duration time.Duration
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
maxlifetime int64
|
||||
}
|
||||
|
||||
// NewRedisStore creates and returns a redis session store.
|
||||
func NewRedisStore(c *redis.Client, sid string, dur time.Duration, kv map[interface{}]interface{}) *RedisStore {
|
||||
return &RedisStore{
|
||||
c: c,
|
||||
sid: sid,
|
||||
duration: dur,
|
||||
data: kv,
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *RedisSessionStore) Set(key, val interface{}) error {
|
||||
func (s *RedisStore) Set(key, val interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -49,7 +57,7 @@ func (s *RedisSessionStore) Set(key, val interface{}) error {
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *RedisSessionStore) Get(key interface{}) interface{} {
|
||||
func (s *RedisStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
@ -57,7 +65,7 @@ func (s *RedisSessionStore) Get(key interface{}) interface{} {
|
||||
}
|
||||
|
||||
// Delete delete a key from session.
|
||||
func (s *RedisSessionStore) Delete(key interface{}) error {
|
||||
func (s *RedisStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -66,26 +74,22 @@ func (s *RedisSessionStore) Delete(key interface{}) error {
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *RedisSessionStore) ID() string {
|
||||
func (s *RedisStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// Release releases resource and save data to provider.
|
||||
func (s *RedisSessionStore) Release() error {
|
||||
c := s.p.Get()
|
||||
defer c.Close()
|
||||
|
||||
func (s *RedisStore) Release() error {
|
||||
data, err := session.EncodeGob(s.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = c.Do("SETEX", s.sid, s.maxlifetime, string(data))
|
||||
return err
|
||||
return s.c.SetEx(s.sid, s.duration, string(data)).Err()
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *RedisSessionStore) Flush() error {
|
||||
func (s *RedisStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
@ -95,59 +99,65 @@ func (s *RedisSessionStore) Flush() error {
|
||||
|
||||
// RedisProvider represents a redis session provider implementation.
|
||||
type RedisProvider struct {
|
||||
maxlifetime int64
|
||||
connAddr string
|
||||
poolsize int
|
||||
password string
|
||||
poollist *redis.Pool
|
||||
c *redis.Client
|
||||
duration time.Duration
|
||||
}
|
||||
|
||||
// Init initializes memory session provider.
|
||||
// connStr: <redis server addr>,<pool size>,<password>
|
||||
// e.g. 127.0.0.1:6379,100,macaron
|
||||
func (p *RedisProvider) Init(maxlifetime int64, connStr string) error {
|
||||
p.maxlifetime = maxlifetime
|
||||
configs := strings.Split(connStr, ",")
|
||||
if len(configs) > 0 {
|
||||
p.connAddr = configs[0]
|
||||
}
|
||||
if len(configs) > 1 {
|
||||
poolsize, err := strconv.Atoi(configs[1])
|
||||
if err != nil || poolsize <= 0 {
|
||||
p.poolsize = MAX_POOL_SIZE
|
||||
} else {
|
||||
p.poolsize = poolsize
|
||||
}
|
||||
} else {
|
||||
p.poolsize = MAX_POOL_SIZE
|
||||
}
|
||||
if len(configs) > 2 {
|
||||
p.password = configs[2]
|
||||
}
|
||||
p.poollist = redis.NewPool(func() (redis.Conn, error) {
|
||||
c, err := redis.Dial("tcp", p.connAddr)
|
||||
// Init initializes redis session provider.
|
||||
// configs: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
|
||||
func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) {
|
||||
p.duration, err = time.ParseDuration(fmt.Sprintf("%ds", maxlifetime))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if p.password != "" {
|
||||
if _, err := c.Do("AUTH", p.password); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c, err
|
||||
}, p.poolsize)
|
||||
|
||||
return p.poollist.Get().Err()
|
||||
cfg, err := ini.Load([]byte(strings.Replace(configs, ",", "\n", -1)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opt := &redis.Options{
|
||||
Network: "tcp",
|
||||
}
|
||||
for k, v := range cfg.Section("").KeysHash() {
|
||||
switch k {
|
||||
case "network":
|
||||
opt.Network = v
|
||||
case "addr":
|
||||
opt.Addr = v
|
||||
case "password":
|
||||
opt.Password = v
|
||||
case "db":
|
||||
opt.DB = com.StrTo(v).MustInt64()
|
||||
case "pool_size":
|
||||
opt.PoolSize = com.StrTo(v).MustInt()
|
||||
case "idle_timeout":
|
||||
opt.IdleTimeout, err = time.ParseDuration(v + "s")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing idle timeout: %v", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("session/redis: unsupported option '%s'", k)
|
||||
}
|
||||
}
|
||||
|
||||
p.c = redis.NewClient(opt)
|
||||
return p.c.Ping().Err()
|
||||
}
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *RedisProvider) Read(sid string) (session.RawStore, error) {
|
||||
c := p.poollist.Get()
|
||||
defer c.Close()
|
||||
if !p.Exist(sid) {
|
||||
if err := p.c.Set(sid, "").Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
kvs, err := redis.String(c.Do("GET", sid))
|
||||
var kv map[interface{}]interface{}
|
||||
kvs, err := p.c.Get(sid).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(kvs) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
@ -157,48 +167,41 @@ func (p *RedisProvider) Read(sid string) (session.RawStore, error) {
|
||||
}
|
||||
}
|
||||
|
||||
rs := &RedisSessionStore{p: p.poollist, sid: sid, data: kv, maxlifetime: p.maxlifetime}
|
||||
return rs, nil
|
||||
return NewRedisStore(p.c, sid, p.duration, kv), nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *RedisProvider) Exist(sid string) bool {
|
||||
c := p.poollist.Get()
|
||||
defer c.Close()
|
||||
|
||||
if existed, err := redis.Int(c.Do("EXISTS", sid)); err != nil || existed == 0 {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
has, err := p.c.Exists(sid).Result()
|
||||
return err == nil && has
|
||||
}
|
||||
|
||||
// Destory deletes a session by session ID.
|
||||
func (p *RedisProvider) Destory(sid string) error {
|
||||
c := p.poollist.Get()
|
||||
defer c.Close()
|
||||
|
||||
_, err := c.Do("DEL", sid)
|
||||
return err
|
||||
return p.c.Del(sid).Err()
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *RedisProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
|
||||
c := p.poollist.Get()
|
||||
defer c.Close()
|
||||
|
||||
if existed, _ := redis.Int(c.Do("EXISTS", oldsid)); existed == 0 {
|
||||
// oldsid doesn't exists, set the new sid directly
|
||||
// ignore error here, since if it return error
|
||||
// the existed value will be 0
|
||||
c.Do("SET", sid, "", "EX", p.maxlifetime)
|
||||
} else {
|
||||
c.Do("RENAME", oldsid, sid)
|
||||
c.Do("EXPIRE", sid, p.maxlifetime)
|
||||
func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
|
||||
if p.Exist(sid) {
|
||||
return nil, fmt.Errorf("new sid '%s' already exists", sid)
|
||||
} else if !p.Exist(oldsid) {
|
||||
// Make a fake old session.
|
||||
if err = p.c.SetEx(oldsid, p.duration, "").Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err = p.c.Rename(oldsid, sid).Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kvs, err := redis.String(c.Do("GET", sid))
|
||||
var kv map[interface{}]interface{}
|
||||
kvs, err := p.c.Get(sid).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(kvs) == 0 {
|
||||
kv = make(map[interface{}]interface{})
|
||||
} else {
|
||||
@ -208,14 +211,12 @@ func (p *RedisProvider) Regenerate(oldsid, sid string) (session.RawStore, error)
|
||||
}
|
||||
}
|
||||
|
||||
rs := &RedisSessionStore{p: p.poollist, sid: sid, data: kv, maxlifetime: p.maxlifetime}
|
||||
return rs, nil
|
||||
return NewRedisStore(p.c, sid, p.duration, kv), nil
|
||||
}
|
||||
|
||||
// Count counts and returns number of sessions.
|
||||
func (p *RedisProvider) Count() int {
|
||||
// FIXME
|
||||
return 0
|
||||
return int(p.c.DbSize().Val())
|
||||
}
|
||||
|
||||
// GC calls GC to clean expired sessions.
|
||||
|
1
Godeps/_workspace/src/github.com/macaron-contrib/session/redis/redis.goconvey
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/macaron-contrib/session/redis/redis.goconvey
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
ignore
|
107
Godeps/_workspace/src/github.com/macaron-contrib/session/redis/redis_test.go
generated
vendored
Normal file
107
Godeps/_workspace/src/github.com/macaron-contrib/session/redis/redis_test.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/macaron-contrib/session"
|
||||
)
|
||||
|
||||
func Test_RedisProvider(t *testing.T) {
|
||||
Convey("Test redis session provider", t, func() {
|
||||
opt := session.Options{
|
||||
Provider: "redis",
|
||||
ProviderConfig: "addr=:6379",
|
||||
}
|
||||
|
||||
Convey("Basic operation", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
sess.Set("uname", "unknwon")
|
||||
})
|
||||
m.Get("/reg", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := raw.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
})
|
||||
m.Get("/get", func(ctx *macaron.Context, sess session.Store) {
|
||||
sid := sess.ID()
|
||||
So(sid, ShouldNotBeEmpty)
|
||||
|
||||
raw, err := sess.Read(sid)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
|
||||
uname := sess.Get("uname")
|
||||
So(uname, ShouldNotBeNil)
|
||||
So(uname, ShouldEqual, "unknwon")
|
||||
|
||||
So(sess.Delete("uname"), ShouldBeNil)
|
||||
So(sess.Get("uname"), ShouldBeNil)
|
||||
|
||||
So(sess.Destory(ctx), ShouldBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie := resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/reg", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie = resp.Header().Get("Set-Cookie")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Regenrate empty session", func() {
|
||||
m := macaron.New()
|
||||
m.Use(session.Sessioner(opt))
|
||||
m.Get("/", func(ctx *macaron.Context, sess session.Store) {
|
||||
raw, err := sess.RegenerateId(ctx)
|
||||
So(err, ShouldBeNil)
|
||||
So(raw, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", "MacaronSession=ad2c7e3cbecfcf486; Path=/;")
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
})
|
||||
}
|
38
Godeps/_workspace/src/github.com/macaron-contrib/session/session.go
generated
vendored
38
Godeps/_workspace/src/github.com/macaron-contrib/session/session.go
generated
vendored
@ -13,7 +13,7 @@
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
// Package session a middleware that provides the session manager of Macaron.
|
||||
// Package session a middleware that provides the session management of Macaron.
|
||||
package session
|
||||
|
||||
// NOTE: last sync 000033e on Nov 4, 2014.
|
||||
@ -28,7 +28,7 @@ import (
|
||||
"github.com/Unknwon/macaron"
|
||||
)
|
||||
|
||||
const _VERSION = "0.1.1"
|
||||
const _VERSION = "0.1.6"
|
||||
|
||||
func Version() string {
|
||||
return _VERSION
|
||||
@ -37,11 +37,11 @@ func Version() string {
|
||||
// RawStore is the interface that operates the session data.
|
||||
type RawStore interface {
|
||||
// Set sets value to given key in session.
|
||||
Set(key, value interface{}) error
|
||||
Set(interface{}, interface{}) error
|
||||
// Get gets value by given key in session.
|
||||
Get(key interface{}) interface{}
|
||||
// Delete delete a key from session.
|
||||
Delete(key interface{}) error
|
||||
Get(interface{}) interface{}
|
||||
// Delete deletes a key from session.
|
||||
Delete(interface{}) error
|
||||
// ID returns current session ID.
|
||||
ID() string
|
||||
// Release releases session resource and save data to provider.
|
||||
@ -54,7 +54,7 @@ type RawStore interface {
|
||||
type Store interface {
|
||||
RawStore
|
||||
// Read returns raw session store by session ID.
|
||||
Read(sid string) (RawStore, error)
|
||||
Read(string) (RawStore, error)
|
||||
// Destory deletes a session.
|
||||
Destory(*macaron.Context) error
|
||||
// RegenerateId regenerates a session store from old session ID to new one.
|
||||
@ -111,7 +111,7 @@ func prepareOptions(options []Options) Options {
|
||||
if len(opt.Provider) == 0 {
|
||||
opt.Provider = sec.Key("PROVIDER").MustString("memory")
|
||||
}
|
||||
if len(opt.ProviderConfig) == 0 && opt.Provider == "file" {
|
||||
if len(opt.ProviderConfig) == 0 {
|
||||
opt.ProviderConfig = sec.Key("PROVIDER_CONFIG").MustString("data/sessions")
|
||||
}
|
||||
if len(opt.CookieName) == 0 {
|
||||
@ -155,7 +155,7 @@ func Sessioner(options ...Options) macaron.Handler {
|
||||
return func(ctx *macaron.Context) {
|
||||
sess, err := manager.Start(ctx)
|
||||
if err != nil {
|
||||
panic("session: " + err.Error())
|
||||
panic("session(start): " + err.Error())
|
||||
}
|
||||
|
||||
// Get flash.
|
||||
@ -187,8 +187,8 @@ func Sessioner(options ...Options) macaron.Handler {
|
||||
|
||||
ctx.Next()
|
||||
|
||||
if sess.Release() != nil {
|
||||
panic("session: " + err.Error())
|
||||
if err = sess.Release(); err != nil {
|
||||
panic("session(release): " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -242,17 +242,14 @@ type Manager struct {
|
||||
func NewManager(name string, opt Options) (*Manager, error) {
|
||||
p, ok := providers[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("session: unknown provider ‘%q’(forgotten import?)", name)
|
||||
return nil, fmt.Errorf("session: unknown provider '%s'(forgotten import?)", name)
|
||||
}
|
||||
if err := p.Init(opt.Maxlifetime, opt.ProviderConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Manager{p, opt}, nil
|
||||
return &Manager{p, opt}, p.Init(opt.Maxlifetime, opt.ProviderConfig)
|
||||
}
|
||||
|
||||
// sessionId generates a new session ID with rand string, unix nano time, remote addr by hash function.
|
||||
func (m *Manager) sessionId() string {
|
||||
return hex.EncodeToString(generateRandomKey(m.opt.IDLength))
|
||||
return hex.EncodeToString(generateRandomKey(m.opt.IDLength / 2))
|
||||
}
|
||||
|
||||
// Start starts a session by generating new one
|
||||
@ -315,17 +312,10 @@ func (m *Manager) Destory(ctx *macaron.Context) error {
|
||||
func (m *Manager) RegenerateId(ctx *macaron.Context) (sess RawStore, err error) {
|
||||
sid := m.sessionId()
|
||||
oldsid := ctx.GetCookie(m.opt.CookieName)
|
||||
if len(oldsid) == 0 {
|
||||
sess, err = m.provider.Read(oldsid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
sess, err = m.provider.Regenerate(oldsid, sid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ck := &http.Cookie{
|
||||
Name: m.opt.CookieName,
|
||||
Value: sid,
|
||||
|
2
Godeps/_workspace/src/github.com/macaron-contrib/session/session_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/macaron-contrib/session/session_test.go
generated
vendored
@ -42,7 +42,7 @@ func Test_Sessioner(t *testing.T) {
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Register invalid provider that", t, func() {
|
||||
Convey("Register invalid provider", t, func() {
|
||||
Convey("Provider not exists", func() {
|
||||
defer func() {
|
||||
So(recover(), ShouldNotBeNil)
|
||||
|
30
Godeps/_workspace/src/github.com/macaron-contrib/session/utils.go
generated
vendored
30
Godeps/_workspace/src/github.com/macaron-contrib/session/utils.go
generated
vendored
@ -24,39 +24,19 @@ import (
|
||||
"github.com/Unknwon/com"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register([]interface{}{})
|
||||
gob.Register(map[int]interface{}{})
|
||||
gob.Register(map[string]interface{}{})
|
||||
gob.Register(map[interface{}]interface{}{})
|
||||
gob.Register(map[string]string{})
|
||||
gob.Register(map[int]string{})
|
||||
gob.Register(map[int]int{})
|
||||
gob.Register(map[int]int64{})
|
||||
}
|
||||
|
||||
func EncodeGob(obj map[interface{}]interface{}) ([]byte, error) {
|
||||
for _, v := range obj {
|
||||
gob.Register(v)
|
||||
}
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := gob.NewEncoder(buf)
|
||||
err := enc.Encode(obj)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
err := gob.NewEncoder(buf).Encode(obj)
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func DecodeGob(encoded []byte) (map[interface{}]interface{}, error) {
|
||||
func DecodeGob(encoded []byte) (out map[interface{}]interface{}, err error) {
|
||||
buf := bytes.NewBuffer(encoded)
|
||||
dec := gob.NewDecoder(buf)
|
||||
var out map[interface{}]interface{}
|
||||
err := dec.Decode(&out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
err = gob.NewDecoder(buf).Decode(&out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// generateRandomKey creates a random key with the given strength.
|
||||
|
Loading…
Reference in New Issue
Block a user