service/session.go

138 lines
3.2 KiB
Go
Raw Normal View History

package service
import (
"reflect"
"sync"
"time"
"apigo.cc/gojs"
"apigo.cc/gojs/goja"
"github.com/ssgo/log"
"github.com/ssgo/redis"
)
type Session struct {
id string
conn *redis.Redis
data map[string]any
}
var sessionRedis *redis.Redis
var sessionTimeout = int64(3600)
var memorySessionData = map[string]map[string]any{}
var memorySessionDataLock = sync.RWMutex{}
var lastSessionClearTime int64
func NewSession(id string, logger *log.Logger) *Session {
data := map[string]any{}
conn := sessionRedis
if sessionRedis == nil {
memorySessionDataLock.RLock()
if data1, ok1 := memorySessionData[id]; ok1 && data1 != nil {
data = data1
}
memorySessionDataLock.RUnlock()
} else {
conn = sessionRedis.CopyByLogger(logger)
err := conn.GET("SESS_" + id).To(&data)
if err == nil {
conn.EXPIRE("SESS_"+id, int(sessionTimeout))
}
}
return &Session{
id: id,
conn: conn,
data: data,
}
}
func (session *Session) Set(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(1)
if args.Arguments[0].ExportType().Kind() == reflect.Map {
for key, value := range args.Map(0) {
session.data[key] = value
}
} else {
args.Check(2)
session.data[args.Str(0)] = args.Any(1)
}
return nil
}
func (session *Session) Get(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(1)
if len(args.Arguments) == 1 {
if args.Arguments[0].ExportType().Kind() == reflect.Slice {
out := make(map[string]any)
for _, key := range args.Arr(0).StrArray(0) {
out[key] = session.data[key]
}
return vm.ToValue(out)
} else {
return vm.ToValue(session.data[args.Str(0)])
}
} else {
out := make(map[string]any)
for _, key := range args.StrArray(0) {
out[key] = session.data[key]
}
return vm.ToValue(out)
}
}
func (session *Session) Remove(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(1)
if args.Arguments[0].ExportType().Kind() == reflect.Slice {
out := make(map[string]any)
for _, key := range args.Arr(0).StrArray(0) {
delete(session.data, key)
}
return vm.ToValue(out)
} else {
for _, key := range args.StrArray(0) {
delete(session.data, key)
}
}
return nil
}
func (session *Session) SetAuthLevel(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(1)
session.data["_authLevel"] = args.Int(0)
return nil
}
func (session *Session) Save(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
if session.conn == nil {
now := time.Now().Unix()
session.data["_time"] = now
memorySessionDataLock.Lock()
memorySessionData[session.id] = session.data
clearTimeDiff := now - lastSessionClearTime
if clearTimeDiff > 60 {
lastSessionClearTime = now
}
memorySessionDataLock.Unlock()
if clearTimeDiff > 60 {
go clearMemorySession()
}
} else {
session.conn.SETEX("SESS_"+session.id, int(sessionTimeout), session.data)
}
return nil
}
func clearMemorySession() {
memorySessionDataLock.Lock()
now := time.Now().Unix()
for id, data := range memorySessionData {
if data["_time"] != nil {
if now-data["_time"].(int64) > sessionTimeout {
delete(memorySessionData, id)
}
}
}
memorySessionDataLock.Unlock()
}