session
1. session move from astaxie/session to beego/session 2. support 4 type session
Showing
9 changed files
with
645 additions
and
31 deletions
| ... | @@ -32,7 +32,7 @@ func (this *MainController) Get() { | ... | @@ -32,7 +32,7 @@ func (this *MainController) Get() { |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | func main() { | 34 | func main() { |
| 35 | beego.RegisterController("/", &MainController{}) | 35 | beego.Router("/", &MainController{}) |
| 36 | //beego.HttpPort = 8080 // default | 36 | //beego.HttpPort = 8080 // default |
| 37 | beego.Run() | 37 | beego.Run() |
| 38 | } | 38 | } |
| ... | @@ -54,16 +54,16 @@ Some associated tools for beego reside in:[bee](https://github.com/astaxie/bee) | ... | @@ -54,16 +54,16 @@ Some associated tools for beego reside in:[bee](https://github.com/astaxie/bee) |
| 54 | ============ | 54 | ============ |
| 55 | In beego, a route is a struct paired with a URL-matching pattern. The struct has many method with the same name of http method to serve the http response. Each route is associated with a block. | 55 | In beego, a route is a struct paired with a URL-matching pattern. The struct has many method with the same name of http method to serve the http response. Each route is associated with a block. |
| 56 | ```go | 56 | ```go |
| 57 | beego.RegisterController("/", &controllers.MainController{}) | 57 | beego.Router("/", &controllers.MainController{}) |
| 58 | beego.RegisterController("/admin", &admin.UserController{}) | 58 | beego.Router("/admin", &admin.UserController{}) |
| 59 | beego.RegisterController("/admin/index", &admin.ArticleController{}) | 59 | beego.Router("/admin/index", &admin.ArticleController{}) |
| 60 | beego.RegisterController("/admin/addpkg", &admin.AddController{}) | 60 | beego.Router("/admin/addpkg", &admin.AddController{}) |
| 61 | ``` | 61 | ``` |
| 62 | You can specify custom regular expressions for routes: | 62 | You can specify custom regular expressions for routes: |
| 63 | ```go | 63 | ```go |
| 64 | beego.RegisterController("/admin/editpkg/:id([0-9]+)", &admin.EditController{}) | 64 | beego.Router("/admin/editpkg/:id([0-9]+)", &admin.EditController{}) |
| 65 | beego.RegisterController("/admin/delpkg/:id([0-9]+)", &admin.DelController{}) | 65 | beego.Router("/admin/delpkg/:id([0-9]+)", &admin.DelController{}) |
| 66 | beego.RegisterController("/:pkg(.*)", &controllers.MainController{}) | 66 | beego.Router("/:pkg(.*)", &controllers.MainController{}) |
| 67 | ``` | 67 | ``` |
| 68 | You can also create routes for static files: | 68 | You can also create routes for static files: |
| 69 | 69 | ||
| ... | @@ -87,7 +87,7 @@ beego.Filter(FilterUser) | ... | @@ -87,7 +87,7 @@ beego.Filter(FilterUser) |
| 87 | ``` | 87 | ``` |
| 88 | You can also apply filters only when certain REST URL Parameters exist: | 88 | You can also apply filters only when certain REST URL Parameters exist: |
| 89 | ```go | 89 | ```go |
| 90 | beego.RegisterController("/:id([0-9]+)", &admin.EditController{}) | 90 | beego.Router("/:id([0-9]+)", &admin.EditController{}) |
| 91 | beego.FilterParam("id", func(rw http.ResponseWriter, r *http.Request) { | 91 | beego.FilterParam("id", func(rw http.ResponseWriter, r *http.Request) { |
| 92 | ... | 92 | ... |
| 93 | }) | 93 | }) | ... | ... |
| ... | @@ -2,8 +2,7 @@ package beego | ... | @@ -2,8 +2,7 @@ package beego |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | "github.com/astaxie/session" | 5 | "github.com/astaxie/beego/session" |
| 6 | _ "github.com/astaxie/session/providers/memory" | ||
| 7 | "html/template" | 6 | "html/template" |
| 8 | "net" | 7 | "net" |
| 9 | "net/http" | 8 | "net/http" |
| ... | @@ -31,9 +30,10 @@ var ( | ... | @@ -31,9 +30,10 @@ var ( |
| 31 | AppConfig *Config | 30 | AppConfig *Config |
| 32 | //related to session | 31 | //related to session |
| 33 | SessionOn bool // wheather auto start session,default is false | 32 | SessionOn bool // wheather auto start session,default is false |
| 34 | SessionProvider string // default session provider memory | 33 | SessionProvider string // default session provider memory mysql redis |
| 35 | SessionName string // sessionName cookie's name | 34 | SessionName string // sessionName cookie's name |
| 36 | SessionGCMaxLifetime int64 // session's gc maxlifetime | 35 | SessionGCMaxLifetime int64 // session's gc maxlifetime |
| 36 | SessionSavePath string // session savepath if use mysql/redis/file this set to the connectinfo | ||
| 37 | UseFcgi bool | 37 | UseFcgi bool |
| 38 | 38 | ||
| 39 | GlobalSessions *session.Manager //GlobalSessions | 39 | GlobalSessions *session.Manager //GlobalSessions |
| ... | @@ -60,6 +60,7 @@ func init() { | ... | @@ -60,6 +60,7 @@ func init() { |
| 60 | SessionProvider = "memory" | 60 | SessionProvider = "memory" |
| 61 | SessionName = "beegosessionID" | 61 | SessionName = "beegosessionID" |
| 62 | SessionGCMaxLifetime = 3600 | 62 | SessionGCMaxLifetime = 3600 |
| 63 | SessionSavePath = "" | ||
| 63 | UseFcgi = false | 64 | UseFcgi = false |
| 64 | } else { | 65 | } else { |
| 65 | HttpAddr = AppConfig.String("httpaddr") | 66 | HttpAddr = AppConfig.String("httpaddr") |
| ... | @@ -109,6 +110,11 @@ func init() { | ... | @@ -109,6 +110,11 @@ func init() { |
| 109 | } else { | 110 | } else { |
| 110 | SessionName = ar | 111 | SessionName = ar |
| 111 | } | 112 | } |
| 113 | if ar := AppConfig.String("sessionsavepath"); ar == "" { | ||
| 114 | SessionSavePath = "" | ||
| 115 | } else { | ||
| 116 | SessionSavePath = ar | ||
| 117 | } | ||
| 112 | if ar, err := AppConfig.Int("sessiongcmaxlifetime"); err != nil && ar != 0 { | 118 | if ar, err := AppConfig.Int("sessiongcmaxlifetime"); err != nil && ar != 0 { |
| 113 | int64val, _ := strconv.ParseInt(strconv.Itoa(ar), 10, 64) | 119 | int64val, _ := strconv.ParseInt(strconv.Itoa(ar), 10, 64) |
| 114 | SessionGCMaxLifetime = int64val | 120 | SessionGCMaxLifetime = int64val |
| ... | @@ -222,7 +228,7 @@ func Run() { | ... | @@ -222,7 +228,7 @@ func Run() { |
| 222 | BeeApp.Router(`/debug/pprof/:pp([\w]+)`, &ProfController{}) | 228 | BeeApp.Router(`/debug/pprof/:pp([\w]+)`, &ProfController{}) |
| 223 | } | 229 | } |
| 224 | if SessionOn { | 230 | if SessionOn { |
| 225 | GlobalSessions, _ = session.NewManager(SessionProvider, SessionName, SessionGCMaxLifetime) | 231 | GlobalSessions, _ = session.NewManager(SessionProvider, SessionName, SessionGCMaxLifetime, SessionSavePath) |
| 226 | go GlobalSessions.GC() | 232 | go GlobalSessions.GC() |
| 227 | } | 233 | } |
| 228 | err := BuildTemplate(ViewsPath) | 234 | err := BuildTemplate(ViewsPath) | ... | ... |
| ... | @@ -4,7 +4,7 @@ import ( | ... | @@ -4,7 +4,7 @@ import ( |
| 4 | "bytes" | 4 | "bytes" |
| 5 | "encoding/json" | 5 | "encoding/json" |
| 6 | "encoding/xml" | 6 | "encoding/xml" |
| 7 | "github.com/astaxie/session" | 7 | "github.com/astaxie/beego/session" |
| 8 | "html/template" | 8 | "html/template" |
| 9 | "io/ioutil" | 9 | "io/ioutil" |
| 10 | "net/http" | 10 | "net/http" |
| ... | @@ -51,7 +51,6 @@ func (c *Controller) Prepare() { | ... | @@ -51,7 +51,6 @@ func (c *Controller) Prepare() { |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | func (c *Controller) Finish() { | 53 | func (c *Controller) Finish() { |
| 54 | |||
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | func (c *Controller) Get() { | 56 | func (c *Controller) Get() { |
| ... | @@ -82,21 +81,6 @@ func (c *Controller) Options() { | ... | @@ -82,21 +81,6 @@ func (c *Controller) Options() { |
| 82 | http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405) | 81 | http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405) |
| 83 | } | 82 | } |
| 84 | 83 | ||
| 85 | func (c *Controller) SetSession(name string, value interface{}) { | ||
| 86 | ss := c.StartSession() | ||
| 87 | ss.Set(name, value) | ||
| 88 | } | ||
| 89 | |||
| 90 | func (c *Controller) GetSession(name string) interface{} { | ||
| 91 | ss := c.StartSession() | ||
| 92 | return ss.Get(name) | ||
| 93 | } | ||
| 94 | |||
| 95 | func (c *Controller) DelSession(name string) { | ||
| 96 | ss := c.StartSession() | ||
| 97 | ss.Delete(name) | ||
| 98 | } | ||
| 99 | |||
| 100 | func (c *Controller) Render() error { | 84 | func (c *Controller) Render() error { |
| 101 | rb, err := c.RenderBytes() | 85 | rb, err := c.RenderBytes() |
| 102 | 86 | ||
| ... | @@ -190,7 +174,25 @@ func (c *Controller) Input() url.Values { | ... | @@ -190,7 +174,25 @@ func (c *Controller) Input() url.Values { |
| 190 | return c.Ctx.Request.Form | 174 | return c.Ctx.Request.Form |
| 191 | } | 175 | } |
| 192 | 176 | ||
| 193 | func (c *Controller) StartSession() (sess session.Session) { | 177 | func (c *Controller) StartSession() (sess session.SessionStore) { |
| 194 | sess = GlobalSessions.SessionStart(c.Ctx.ResponseWriter, c.Ctx.Request) | 178 | sess = GlobalSessions.SessionStart(c.Ctx.ResponseWriter, c.Ctx.Request) |
| 195 | return | 179 | return |
| 196 | } | 180 | } |
| 181 | |||
| 182 | func (c *Controller) SetSession(name string, value interface{}) { | ||
| 183 | ss := c.StartSession() | ||
| 184 | defer ss.SessionRelease() | ||
| 185 | ss.Set(name, value) | ||
| 186 | } | ||
| 187 | |||
| 188 | func (c *Controller) GetSession(name string) interface{} { | ||
| 189 | ss := c.StartSession() | ||
| 190 | defer ss.SessionRelease() | ||
| 191 | return ss.Get(name) | ||
| 192 | } | ||
| 193 | |||
| 194 | func (c *Controller) DelSession(name string) { | ||
| 195 | ss := c.StartSession() | ||
| 196 | defer ss.SessionRelease() | ||
| 197 | ss.Delete(name) | ||
| 198 | } | ... | ... |
session/sess_file.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "io/ioutil" | ||
| 5 | "os" | ||
| 6 | "path" | ||
| 7 | "path/filepath" | ||
| 8 | "sync" | ||
| 9 | "time" | ||
| 10 | ) | ||
| 11 | |||
| 12 | var ( | ||
| 13 | filepder = &FileProvider{} | ||
| 14 | gcmaxlifetime int64 | ||
| 15 | ) | ||
| 16 | |||
| 17 | type FileSessionStore struct { | ||
| 18 | f *os.File | ||
| 19 | sid string | ||
| 20 | lock sync.RWMutex | ||
| 21 | values map[interface{}]interface{} | ||
| 22 | } | ||
| 23 | |||
| 24 | func (fs *FileSessionStore) Set(key, value interface{}) error { | ||
| 25 | fs.lock.Lock() | ||
| 26 | defer fs.lock.Unlock() | ||
| 27 | fs.values[key] = value | ||
| 28 | fs.updatecontent() | ||
| 29 | return nil | ||
| 30 | } | ||
| 31 | |||
| 32 | func (fs *FileSessionStore) Get(key interface{}) interface{} { | ||
| 33 | fs.lock.RLock() | ||
| 34 | defer fs.lock.RUnlock() | ||
| 35 | fs.updatecontent() | ||
| 36 | if v, ok := fs.values[key]; ok { | ||
| 37 | return v | ||
| 38 | } else { | ||
| 39 | return nil | ||
| 40 | } | ||
| 41 | return nil | ||
| 42 | } | ||
| 43 | |||
| 44 | func (fs *FileSessionStore) Delete(key interface{}) error { | ||
| 45 | fs.lock.Lock() | ||
| 46 | defer fs.lock.Unlock() | ||
| 47 | delete(fs.values, key) | ||
| 48 | fs.updatecontent() | ||
| 49 | return nil | ||
| 50 | } | ||
| 51 | |||
| 52 | func (fs *FileSessionStore) SessionID() string { | ||
| 53 | return fs.sid | ||
| 54 | } | ||
| 55 | |||
| 56 | func (fs *FileSessionStore) SessionRelease() { | ||
| 57 | fs.f.Close() | ||
| 58 | } | ||
| 59 | |||
| 60 | func (fs *FileSessionStore) updatecontent() { | ||
| 61 | b, err := encodeGob(fs.values) | ||
| 62 | if err != nil { | ||
| 63 | return | ||
| 64 | } | ||
| 65 | fs.f.Write(b) | ||
| 66 | } | ||
| 67 | |||
| 68 | type FileProvider struct { | ||
| 69 | maxlifetime int64 | ||
| 70 | savePath string | ||
| 71 | } | ||
| 72 | |||
| 73 | func (fp *FileProvider) SessionInit(maxlifetime int64, savePath string) error { | ||
| 74 | fp.maxlifetime = maxlifetime | ||
| 75 | fp.savePath = savePath | ||
| 76 | return nil | ||
| 77 | } | ||
| 78 | |||
| 79 | func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) { | ||
| 80 | err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777) | ||
| 81 | if err != nil { | ||
| 82 | println(err.Error()) | ||
| 83 | } | ||
| 84 | _, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) | ||
| 85 | var f *os.File | ||
| 86 | if err == nil { | ||
| 87 | f, err = os.OpenFile(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), os.O_RDWR, 0777) | ||
| 88 | } else if os.IsNotExist(err) { | ||
| 89 | f, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) | ||
| 90 | } else { | ||
| 91 | return nil, err | ||
| 92 | } | ||
| 93 | os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now()) | ||
| 94 | var kv map[interface{}]interface{} | ||
| 95 | b, err := ioutil.ReadAll(f) | ||
| 96 | if err != nil { | ||
| 97 | return nil, err | ||
| 98 | } | ||
| 99 | if len(b) == 0 { | ||
| 100 | kv = make(map[interface{}]interface{}) | ||
| 101 | } else { | ||
| 102 | kv, err = decodeGob(b) | ||
| 103 | if err != nil { | ||
| 104 | return nil, err | ||
| 105 | } | ||
| 106 | } | ||
| 107 | f.Close() | ||
| 108 | f, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) | ||
| 109 | ss := &FileSessionStore{f: f, sid: sid, values: kv} | ||
| 110 | return ss, nil | ||
| 111 | } | ||
| 112 | |||
| 113 | func (fp *FileProvider) SessionDestroy(sid string) error { | ||
| 114 | os.Remove(path.Join(fp.savePath)) | ||
| 115 | return nil | ||
| 116 | } | ||
| 117 | |||
| 118 | func (fp *FileProvider) SessionGC() { | ||
| 119 | gcmaxlifetime = fp.maxlifetime | ||
| 120 | filepath.Walk(fp.savePath, gcpath) | ||
| 121 | } | ||
| 122 | |||
| 123 | func gcpath(path string, info os.FileInfo, err error) error { | ||
| 124 | if err != nil { | ||
| 125 | return err | ||
| 126 | } | ||
| 127 | if info.IsDir() { | ||
| 128 | return nil | ||
| 129 | } | ||
| 130 | if (info.ModTime().Unix() + gcmaxlifetime) < time.Now().Unix() { | ||
| 131 | os.Remove(path) | ||
| 132 | } | ||
| 133 | return nil | ||
| 134 | } | ||
| 135 | |||
| 136 | func init() { | ||
| 137 | Register("file", filepder) | ||
| 138 | } |
session/sess_gob.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "bytes" | ||
| 5 | "encoding/gob" | ||
| 6 | ) | ||
| 7 | |||
| 8 | func init() { | ||
| 9 | gob.Register([]interface{}{}) | ||
| 10 | gob.Register(map[int]interface{}{}) | ||
| 11 | gob.Register(map[string]interface{}{}) | ||
| 12 | gob.Register(map[interface{}]interface{}{}) | ||
| 13 | gob.Register(map[string]string{}) | ||
| 14 | gob.Register(map[int]string{}) | ||
| 15 | gob.Register(map[int]int{}) | ||
| 16 | gob.Register(map[int]int64{}) | ||
| 17 | } | ||
| 18 | |||
| 19 | func encodeGob(obj map[interface{}]interface{}) ([]byte, error) { | ||
| 20 | buf := bytes.NewBuffer(nil) | ||
| 21 | enc := gob.NewEncoder(buf) | ||
| 22 | err := enc.Encode(obj) | ||
| 23 | if err != nil { | ||
| 24 | return []byte(""), err | ||
| 25 | } | ||
| 26 | return buf.Bytes(), nil | ||
| 27 | } | ||
| 28 | |||
| 29 | func decodeGob(encoded []byte) (map[interface{}]interface{}, error) { | ||
| 30 | buf := bytes.NewBuffer(encoded) | ||
| 31 | dec := gob.NewDecoder(buf) | ||
| 32 | var out map[interface{}]interface{} | ||
| 33 | err := dec.Decode(&out) | ||
| 34 | if err != nil { | ||
| 35 | return nil, err | ||
| 36 | } | ||
| 37 | return out, nil | ||
| 38 | } |
session/sess_mem.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "container/list" | ||
| 5 | "sync" | ||
| 6 | "time" | ||
| 7 | ) | ||
| 8 | |||
| 9 | var mempder = &MemProvider{list: list.New(), sessions: make(map[string]*list.Element)} | ||
| 10 | |||
| 11 | type MemSessionStore struct { | ||
| 12 | sid string //session id唯一标示 | ||
| 13 | timeAccessed time.Time //最后访问时间 | ||
| 14 | value map[interface{}]interface{} //session里面存储的值 | ||
| 15 | lock sync.RWMutex | ||
| 16 | } | ||
| 17 | |||
| 18 | func (st *MemSessionStore) Set(key, value interface{}) error { | ||
| 19 | st.lock.Lock() | ||
| 20 | defer st.lock.Unlock() | ||
| 21 | st.value[key] = value | ||
| 22 | return nil | ||
| 23 | } | ||
| 24 | |||
| 25 | func (st *MemSessionStore) Get(key interface{}) interface{} { | ||
| 26 | st.lock.RLock() | ||
| 27 | defer st.lock.RUnlock() | ||
| 28 | if v, ok := st.value[key]; ok { | ||
| 29 | return v | ||
| 30 | } else { | ||
| 31 | return nil | ||
| 32 | } | ||
| 33 | return nil | ||
| 34 | } | ||
| 35 | |||
| 36 | func (st *MemSessionStore) Delete(key interface{}) error { | ||
| 37 | st.lock.Lock() | ||
| 38 | defer st.lock.Unlock() | ||
| 39 | delete(st.value, key) | ||
| 40 | return nil | ||
| 41 | } | ||
| 42 | |||
| 43 | func (st *MemSessionStore) SessionID() string { | ||
| 44 | return st.sid | ||
| 45 | } | ||
| 46 | |||
| 47 | func (st *MemSessionStore) SessionRelease() { | ||
| 48 | |||
| 49 | } | ||
| 50 | |||
| 51 | type MemProvider struct { | ||
| 52 | lock sync.RWMutex //用来锁 | ||
| 53 | sessions map[string]*list.Element //用来存储在内存 | ||
| 54 | list *list.List //用来做gc | ||
| 55 | maxlifetime int64 | ||
| 56 | savePath string | ||
| 57 | } | ||
| 58 | |||
| 59 | func (pder *MemProvider) SessionInit(maxlifetime int64, savePath string) error { | ||
| 60 | pder.maxlifetime = maxlifetime | ||
| 61 | pder.savePath = savePath | ||
| 62 | return nil | ||
| 63 | } | ||
| 64 | |||
| 65 | func (pder *MemProvider) SessionRead(sid string) (SessionStore, error) { | ||
| 66 | pder.lock.RLock() | ||
| 67 | if element, ok := pder.sessions[sid]; ok { | ||
| 68 | go pder.SessionUpdate(sid) | ||
| 69 | pder.lock.RUnlock() | ||
| 70 | return element.Value.(*MemSessionStore), nil | ||
| 71 | } else { | ||
| 72 | pder.lock.RUnlock() | ||
| 73 | pder.lock.Lock() | ||
| 74 | newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})} | ||
| 75 | element := pder.list.PushBack(newsess) | ||
| 76 | pder.sessions[sid] = element | ||
| 77 | pder.lock.Unlock() | ||
| 78 | return newsess, nil | ||
| 79 | } | ||
| 80 | return nil, nil | ||
| 81 | } | ||
| 82 | |||
| 83 | func (pder *MemProvider) SessionDestroy(sid string) error { | ||
| 84 | pder.lock.Lock() | ||
| 85 | defer pder.lock.Unlock() | ||
| 86 | if element, ok := pder.sessions[sid]; ok { | ||
| 87 | delete(pder.sessions, sid) | ||
| 88 | pder.list.Remove(element) | ||
| 89 | return nil | ||
| 90 | } | ||
| 91 | return nil | ||
| 92 | } | ||
| 93 | |||
| 94 | func (pder *MemProvider) SessionGC() { | ||
| 95 | pder.lock.RLock() | ||
| 96 | for { | ||
| 97 | element := pder.list.Back() | ||
| 98 | if element == nil { | ||
| 99 | break | ||
| 100 | } | ||
| 101 | if (element.Value.(*MemSessionStore).timeAccessed.Unix() + pder.maxlifetime) < time.Now().Unix() { | ||
| 102 | pder.lock.RUnlock() | ||
| 103 | pder.lock.Lock() | ||
| 104 | pder.list.Remove(element) | ||
| 105 | delete(pder.sessions, element.Value.(*MemSessionStore).sid) | ||
| 106 | pder.lock.Unlock() | ||
| 107 | pder.lock.RLock() | ||
| 108 | } else { | ||
| 109 | break | ||
| 110 | } | ||
| 111 | } | ||
| 112 | pder.lock.RUnlock() | ||
| 113 | } | ||
| 114 | |||
| 115 | func (pder *MemProvider) SessionUpdate(sid string) error { | ||
| 116 | pder.lock.RLock() | ||
| 117 | defer pder.lock.RUnlock() | ||
| 118 | if element, ok := pder.sessions[sid]; ok { | ||
| 119 | element.Value.(*MemSessionStore).timeAccessed = time.Now() | ||
| 120 | pder.list.MoveToFront(element) | ||
| 121 | return nil | ||
| 122 | } | ||
| 123 | return nil | ||
| 124 | } | ||
| 125 | |||
| 126 | func init() { | ||
| 127 | Register("memory", mempder) | ||
| 128 | } |
session/sess_mysql.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | //CREATE TABLE `session` ( | ||
| 4 | // `session_key` char(64) NOT NULL, | ||
| 5 | // `session_data` blob, | ||
| 6 | // `session_expiry` int(11) unsigned NOT NULL, | ||
| 7 | // PRIMARY KEY (`session_key`) | ||
| 8 | //) ENGINE=MyISAM DEFAULT CHARSET=utf8; | ||
| 9 | |||
| 10 | import ( | ||
| 11 | "database/sql" | ||
| 12 | _ "github.com/go-sql-driver/mysql" | ||
| 13 | "sync" | ||
| 14 | "time" | ||
| 15 | ) | ||
| 16 | |||
| 17 | var mysqlpder = &MysqlProvider{} | ||
| 18 | |||
| 19 | type MysqlSessionStore struct { | ||
| 20 | c *sql.DB | ||
| 21 | sid string | ||
| 22 | lock sync.RWMutex | ||
| 23 | values map[interface{}]interface{} | ||
| 24 | } | ||
| 25 | |||
| 26 | func (st *MysqlSessionStore) Set(key, value interface{}) error { | ||
| 27 | st.lock.Lock() | ||
| 28 | defer st.lock.Unlock() | ||
| 29 | st.values[key] = value | ||
| 30 | st.updatemysql() | ||
| 31 | return nil | ||
| 32 | } | ||
| 33 | |||
| 34 | func (st *MysqlSessionStore) Get(key interface{}) interface{} { | ||
| 35 | st.lock.RLock() | ||
| 36 | defer st.lock.RUnlock() | ||
| 37 | if v, ok := st.values[key]; ok { | ||
| 38 | return v | ||
| 39 | } else { | ||
| 40 | return nil | ||
| 41 | } | ||
| 42 | return nil | ||
| 43 | } | ||
| 44 | |||
| 45 | func (st *MysqlSessionStore) Delete(key interface{}) error { | ||
| 46 | st.lock.Lock() | ||
| 47 | defer st.lock.Unlock() | ||
| 48 | delete(st.values, key) | ||
| 49 | st.updatemysql() | ||
| 50 | return nil | ||
| 51 | } | ||
| 52 | |||
| 53 | func (st *MysqlSessionStore) SessionID() string { | ||
| 54 | return st.sid | ||
| 55 | } | ||
| 56 | |||
| 57 | func (st *MysqlSessionStore) updatemysql() { | ||
| 58 | b, err := encodeGob(st.values) | ||
| 59 | if err != nil { | ||
| 60 | return | ||
| 61 | } | ||
| 62 | st.c.Exec("UPDATE session set `session_data`= ? where session_key=?", b, st.sid) | ||
| 63 | } | ||
| 64 | |||
| 65 | func (st *MysqlSessionStore) SessionRelease() { | ||
| 66 | st.c.Close() | ||
| 67 | } | ||
| 68 | |||
| 69 | type MysqlProvider struct { | ||
| 70 | maxlifetime int64 | ||
| 71 | savePath string | ||
| 72 | } | ||
| 73 | |||
| 74 | func (mp *MysqlProvider) connectInit() *sql.DB { | ||
| 75 | db, e := sql.Open("mysql", mp.savePath) | ||
| 76 | if e != nil { | ||
| 77 | return nil | ||
| 78 | } | ||
| 79 | return db | ||
| 80 | } | ||
| 81 | |||
| 82 | func (mp *MysqlProvider) SessionInit(maxlifetime int64, savePath string) error { | ||
| 83 | mp.maxlifetime = maxlifetime | ||
| 84 | mp.savePath = savePath | ||
| 85 | return nil | ||
| 86 | } | ||
| 87 | |||
| 88 | func (mp *MysqlProvider) SessionRead(sid string) (SessionStore, error) { | ||
| 89 | c := mp.connectInit() | ||
| 90 | row := c.QueryRow("select session_data from session where session_key=?", sid) | ||
| 91 | var sessiondata []byte | ||
| 92 | err := row.Scan(&sessiondata) | ||
| 93 | if err == sql.ErrNoRows { | ||
| 94 | c.Exec("insert into session(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", sid, "", time.Now().Unix()) | ||
| 95 | } | ||
| 96 | var kv map[interface{}]interface{} | ||
| 97 | if len(sessiondata) == 0 { | ||
| 98 | kv = make(map[interface{}]interface{}) | ||
| 99 | } else { | ||
| 100 | kv, err = decodeGob(sessiondata) | ||
| 101 | if err != nil { | ||
| 102 | return nil, err | ||
| 103 | } | ||
| 104 | } | ||
| 105 | rs := &MysqlSessionStore{c: c, sid: sid, values: kv} | ||
| 106 | return rs, nil | ||
| 107 | } | ||
| 108 | |||
| 109 | func (mp *MysqlProvider) SessionDestroy(sid string) error { | ||
| 110 | c := mp.connectInit() | ||
| 111 | c.Exec("DELETE FROM session where session_key=?", sid) | ||
| 112 | c.Close() | ||
| 113 | return nil | ||
| 114 | } | ||
| 115 | |||
| 116 | func (mp *MysqlProvider) SessionGC() { | ||
| 117 | c := mp.connectInit() | ||
| 118 | c.Exec("DELETE from session where session_expiry < ?", time.Now().Unix()-mp.maxlifetime) | ||
| 119 | c.Close() | ||
| 120 | return | ||
| 121 | } | ||
| 122 | |||
| 123 | func init() { | ||
| 124 | Register("mysql", mysqlpder) | ||
| 125 | } |
session/sess_redis.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "github.com/garyburd/redigo/redis" | ||
| 5 | ) | ||
| 6 | |||
| 7 | var redispder = &RedisProvider{} | ||
| 8 | |||
| 9 | type RedisSessionStore struct { | ||
| 10 | c redis.Conn | ||
| 11 | sid string | ||
| 12 | } | ||
| 13 | |||
| 14 | func (rs *RedisSessionStore) Set(key, value interface{}) error { | ||
| 15 | _, err := rs.c.Do("HSET", rs.sid, key, value) | ||
| 16 | return err | ||
| 17 | } | ||
| 18 | |||
| 19 | func (rs *RedisSessionStore) Get(key interface{}) interface{} { | ||
| 20 | v, err := rs.c.Do("GET", rs.sid, key) | ||
| 21 | if err != nil { | ||
| 22 | return nil | ||
| 23 | } | ||
| 24 | return v | ||
| 25 | } | ||
| 26 | |||
| 27 | func (rs *RedisSessionStore) Delete(key interface{}) error { | ||
| 28 | _, err := rs.c.Do("HDEL", rs.sid, key) | ||
| 29 | return err | ||
| 30 | } | ||
| 31 | |||
| 32 | func (rs *RedisSessionStore) SessionID() string { | ||
| 33 | return rs.sid | ||
| 34 | } | ||
| 35 | |||
| 36 | func (rs *RedisSessionStore) SessionRelease() { | ||
| 37 | rs.c.Close() | ||
| 38 | } | ||
| 39 | |||
| 40 | type RedisProvider struct { | ||
| 41 | maxlifetime int64 | ||
| 42 | savePath string | ||
| 43 | } | ||
| 44 | |||
| 45 | func (rp *RedisProvider) connectInit() redis.Conn { | ||
| 46 | c, err := redis.Dial("tcp", rp.savePath) | ||
| 47 | if err != nil { | ||
| 48 | return nil | ||
| 49 | } | ||
| 50 | return c | ||
| 51 | } | ||
| 52 | |||
| 53 | func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { | ||
| 54 | rp.maxlifetime = maxlifetime | ||
| 55 | rp.savePath = savePath | ||
| 56 | return nil | ||
| 57 | } | ||
| 58 | |||
| 59 | func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) { | ||
| 60 | c := rp.connectInit() | ||
| 61 | if str, err := redis.String(c.Do("GET", sid)); err != nil || str == "" { | ||
| 62 | c.Do("SET", sid, sid, rp.maxlifetime) | ||
| 63 | } | ||
| 64 | rs := &RedisSessionStore{c: c, sid: sid} | ||
| 65 | return rs, nil | ||
| 66 | } | ||
| 67 | |||
| 68 | func (rp *RedisProvider) SessionDestroy(sid string) error { | ||
| 69 | c := rp.connectInit() | ||
| 70 | c.Do("DEL", sid) | ||
| 71 | return nil | ||
| 72 | } | ||
| 73 | |||
| 74 | func (rp *RedisProvider) SessionGC() { | ||
| 75 | return | ||
| 76 | } | ||
| 77 | |||
| 78 | func init() { | ||
| 79 | Register("redis", redispder) | ||
| 80 | } |
session/session.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "crypto/rand" | ||
| 5 | "encoding/base64" | ||
| 6 | "fmt" | ||
| 7 | "io" | ||
| 8 | "net/http" | ||
| 9 | "net/url" | ||
| 10 | "time" | ||
| 11 | ) | ||
| 12 | |||
| 13 | type SessionStore interface { | ||
| 14 | Set(key, value interface{}) error //set session value | ||
| 15 | Get(key interface{}) interface{} //get session value | ||
| 16 | Delete(key interface{}) error //delete session value | ||
| 17 | SessionID() string //back current sessionID | ||
| 18 | SessionRelease() // release the resource | ||
| 19 | } | ||
| 20 | |||
| 21 | type Provider interface { | ||
| 22 | SessionInit(maxlifetime int64, savePath string) error | ||
| 23 | SessionRead(sid string) (SessionStore, error) | ||
| 24 | SessionDestroy(sid string) error | ||
| 25 | SessionGC() | ||
| 26 | } | ||
| 27 | |||
| 28 | var provides = make(map[string]Provider) | ||
| 29 | |||
| 30 | // Register makes a session provide available by the provided name. | ||
| 31 | // If Register is called twice with the same name or if driver is nil, | ||
| 32 | // it panics. | ||
| 33 | func Register(name string, provide Provider) { | ||
| 34 | if provide == nil { | ||
| 35 | panic("session: Register provide is nil") | ||
| 36 | } | ||
| 37 | if _, dup := provides[name]; dup { | ||
| 38 | panic("session: Register called twice for provider " + name) | ||
| 39 | } | ||
| 40 | provides[name] = provide | ||
| 41 | } | ||
| 42 | |||
| 43 | type Manager struct { | ||
| 44 | cookieName string //private cookiename | ||
| 45 | provider Provider | ||
| 46 | maxlifetime int64 | ||
| 47 | } | ||
| 48 | |||
| 49 | func NewManager(provideName, cookieName string, maxlifetime int64, savePath string) (*Manager, error) { | ||
| 50 | provider, ok := provides[provideName] | ||
| 51 | if !ok { | ||
| 52 | return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName) | ||
| 53 | } | ||
| 54 | provider.SessionInit(maxlifetime, savePath) | ||
| 55 | return &Manager{provider: provider, cookieName: cookieName, maxlifetime: maxlifetime}, nil | ||
| 56 | } | ||
| 57 | |||
| 58 | //get Session | ||
| 59 | func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session SessionStore) { | ||
| 60 | cookie, err := r.Cookie(manager.cookieName) | ||
| 61 | if err != nil || cookie.Value == "" { | ||
| 62 | sid := manager.sessionId() | ||
| 63 | session, _ = manager.provider.SessionRead(sid) | ||
| 64 | cookie := http.Cookie{Name: manager.cookieName, Value: url.QueryEscape(sid), Path: "/", HttpOnly: true, MaxAge: int(manager.maxlifetime)} | ||
| 65 | http.SetCookie(w, &cookie) | ||
| 66 | } else { | ||
| 67 | sid, _ := url.QueryUnescape(cookie.Value) | ||
| 68 | session, _ = manager.provider.SessionRead(sid) | ||
| 69 | } | ||
| 70 | return | ||
| 71 | } | ||
| 72 | |||
| 73 | //Destroy sessionid | ||
| 74 | func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { | ||
| 75 | cookie, err := r.Cookie(manager.cookieName) | ||
| 76 | if err != nil || cookie.Value == "" { | ||
| 77 | return | ||
| 78 | } else { | ||
| 79 | manager.provider.SessionDestroy(cookie.Value) | ||
| 80 | expiration := time.Now() | ||
| 81 | cookie := http.Cookie{Name: manager.cookieName, Path: "/", HttpOnly: true, Expires: expiration, MaxAge: -1} | ||
| 82 | http.SetCookie(w, &cookie) | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | func (manager *Manager) GC() { | ||
| 87 | manager.provider.SessionGC() | ||
| 88 | time.AfterFunc(time.Duration(manager.maxlifetime)*time.Second, func() { manager.GC() }) | ||
| 89 | } | ||
| 90 | |||
| 91 | func (manager *Manager) sessionId() string { | ||
| 92 | b := make([]byte, 24) | ||
| 93 | if _, err := io.ReadFull(rand.Reader, b); err != nil { | ||
| 94 | return "" | ||
| 95 | } | ||
| 96 | return base64.URLEncoding.EncodeToString(b) | ||
| 97 | } |
-
Please register or sign in to post a comment