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/…