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() }