The following functions implement session: set, get, and remove
Implement set first and add it in context.go
package context
//context/context.go
import (
"context"
"encoding/json"
"errors"
"github.com/gin-gonic/gin"
"myGin/redis"
"strings"
"time"
)
type Context struct {
*gin.Context
}
type HandlerFunc func(*Context)
func (c *Context) Domain(a) string {
return c.Request.Host[:strings.Index(c.Request.Host, ":")]}// Session returns a Session instance
func (c *Context) Session(a) *Session {
var session Session
cookie, ok := c.Get("_session")
if! ok {return nil
}
session = cookie.(Session)
return &session
}
type Session struct {
Cookie string `json:"cookie"`
ExpireTime int64 `json:"expire_time"`
SessionList map[string]interface{} `json:"session_list"`
}
func (s *Session) Set(key string, value interface{}) error {
sessionString, err := redis.Client().Get(context.TODO(), s.Cookie).Result()
iferr ! =nil {
return err
}
var session Session
err = json.Unmarshal([]byte(sessionString), &session)
iferr ! =nil {
return err
}
/ / set
session.SessionList[key] = value
sessionStringNew, err := json.Marshal(session)
// Calculate the new expiration time
e := s.ExpireTime - time.Now().Unix()
if e < 0 {
return errors.New("the session has expired")
}
redis.Client().Set(context.TODO(), s.Cookie, sessionStringNew, time.Duration(e)*time.Second)
return nil
}
Copy the code
Called in the Index controller
package controller
//controller/Index.go
import (
"myGin/context"
"myGin/response"
)
func Index(context *context.Context) *response.Response {
context.Session().Set("msg"."PHP is the best language in the world!")
return response.Resp().String(context.Domain())
}
Copy the code
Check it out in Redis
Set up the success
Then get and remove
func (s *Session) Get(key string) (interface{}, error) {
sessionString, err := redis.Client().Get(context.TODO(), s.Cookie).Result()
iferr ! =nil {
return nil, err
}
var session Session
err = json.Unmarshal([]byte(sessionString), &session)
iferr ! =nil {
return nil, err
}
value, ok := session.SessionList[key]
if ok {
return value, nil
}
return nil, errors.New("not found key :" + key)
}
func (s *Session) Remove(key string) error {
sessionString, err := redis.Client().Get(context.TODO(), s.Cookie).Result()
iferr ! =nil {
return err
}
var session Session
err = json.Unmarshal([]byte(sessionString), &session)
iferr ! =nil {
return err
}
delete(session.SessionList, key)
sessionStringNew, err := json.Marshal(session)
iferr ! =nil {
return err
}
// Calculate the new expiration time
e := s.ExpireTime - time.Now().Unix()
if e < 0 {
return errors.New("the session has expired")
}
redis.Client().Set(context.TODO(), s.Cookie, sessionStringNew, time.Duration(e)*time.Second)
return nil
}
Copy the code
call
package controller
//controller/Index.go
import (
"myGin/context"
"myGin/response"
)
func Index(context *context.Context) *response.Response {
context.Session().Set("msg"."PHP is the best language in the world!")
return response.Resp().String(context.Domain())
}
func Index2(context *context.Context) *response.Response {
msg, _ := context.Session().Get("msg")
return response.Resp().String(msg.(string))}func Index3(context *context.Context) *response.Response {
context.Session().Remove("msg")
return response.Resp().String("")}Copy the code
So at this point, session functionality is pretty much in place, but now let’s look at an interesting question.
func Index4(context *context.Context) *response.Response {
session := context.Session()
for i := 0; i < 100; i++ {
go func(index int) {
session.Set("msg"+strconv.Itoa(index), index)
}(i)
}
return response.Resp().String("")}Copy the code
Accessing this request, the result in Redis looks like this
The loop above performed 100 coroutines. There are only 2 coroutines in Redis, where there should be 100.
The reason for this is that each session is set in parallel, and the read result is not the final result, so the session setting also needs a lock.
The complete code is as follows
package context
//context/context.go
import (
"context"
"encoding/json"
"errors"
"github.com/gin-gonic/gin"
"myGin/redis"
"strings"
"sync"
"time"
)
type Context struct {
*gin.Context
}
type HandlerFunc func(*Context)
func (c *Context) Domain(a) string {
return c.Request.Host[:strings.Index(c.Request.Host, ":")]}// Session returns a Session instance
func (c *Context) Session(a) *Session {
var session Session
cookie, ok := c.Get("_session")
if! ok {return nil
}
session = cookie.(Session)
session.Lock = &sync.Mutex{}
return &session
}
type Session struct {
Cookie string `json:"cookie"`
ExpireTime int64 `json:"expire_time"`
SessionList map[string]interface{} `json:"session_list"`
Lock *sync.Mutex
}
func (s *Session) Set(key string, value interface{}) error {
// Lock to prevent parallel reading
s.Lock.Lock()
defer s.Lock.Unlock()
sessionString, err := redis.Client().Get(context.TODO(), s.Cookie).Result()
iferr ! =nil {
return err
}
var session Session
err = json.Unmarshal([]byte(sessionString), &session)
iferr ! =nil {
return err
}
/ / set
session.SessionList[key] = value
sessionStringNew, err := json.Marshal(session)
// Calculate the new expiration time
e := s.ExpireTime - time.Now().Unix()
if e < 0 {
return errors.New("the session has expired")
}
redis.Client().Set(context.TODO(), s.Cookie, sessionStringNew, time.Duration(e)*time.Second)
return nil
}
func (s *Session) Get(key string) (interface{}, error) {
sessionString, err := redis.Client().Get(context.TODO(), s.Cookie).Result()
iferr ! =nil {
return nil, err
}
var session Session
err = json.Unmarshal([]byte(sessionString), &session)
iferr ! =nil {
return nil, err
}
value, ok := session.SessionList[key]
if ok {
return value, nil
}
return nil, errors.New("not found key :" + key)
}
func (s *Session) Remove(key string) error {
s.Lock.Lock()
defer s.Lock.Unlock()
sessionString, err := redis.Client().Get(context.TODO(), s.Cookie).Result()
iferr ! =nil {
return err
}
var session Session
err = json.Unmarshal([]byte(sessionString), &session)
iferr ! =nil {
return err
}
delete(session.SessionList, key)
sessionStringNew, err := json.Marshal(session)
iferr ! =nil {
return err
}
// Calculate the new expiration time
e := s.ExpireTime - time.Now().Unix()
if e < 0 {
return errors.New("the session has expired")
}
redis.Client().Set(context.TODO(), s.Cookie, sessionStringNew, time.Duration(e)*time.Second)
return nil
}
Copy the code
Source code: github.com/PeterYangs/…