Merge branch 'master' into v3.1
大石头 authored at 2024-07-13 19:03:18
3.46 KiB
Stardust
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NewLife;
using NewLife.Caching;
using NewLife.Collections;

namespace Stardust.Server.Common
{
    public class TokenSession
    {
        /// <summary>有效期</summary>
        public TimeSpan Expire { get; set; } = TimeSpan.FromMinutes(20);

        /// <summary>会话存储</summary>
        public ICache Cache { get; set; } = new MemoryCache { Expire = 20 * 60, Period = 60 * 10 };

        /// <summary>创建新的Session</summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public IDictionary<String, Object> CreateSession(String token)
        {
            var key = GetKey(token);
            var dic = Cache.GetDictionary<Object>(key);
            Cache.SetExpire(key, Expire);

            //!! 临时修正可空字典的BUG
            if (Cache is MemoryCache mc)
            {
                dic = new NullableDictionary<String, Object>();
                mc.Set(key, dic);
            }

            return dic;
        }

        /// <summary>根据Token获取session</summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public IDictionary<String, Object> GetSession(String token)
        {
            if (token.IsNullOrEmpty()) return null;

            var key = GetKey(token);
            // 当前缓存没有指定的token 则直接返回null
            if (!Cache.ContainsKey(key)) return null;

            // 采用哈希结构。内存缓存用并行字段,Redis用Set
            var dic = Cache.GetDictionary<Object>(key);
            Cache.SetExpire(key, Expire);

            return dic;
        }

        /// <summary>
        /// 刷新token有效期
        /// </summary>
        /// <param name="token"></param>
        /// <param name="newToken"></param>
        public IDictionary<String, Object> CopySession(String token, String newToken)
        {
            if (newToken.IsNullOrEmpty()) return null;

            var dic = GetSession(token);
            if (dic == null) return null;

            var nkey = GetKey(newToken);
            if (Cache is MemoryCache mc)
            {
                mc.Set(nkey, dic, Expire);
            }
            //else if (Cache is Redis rds)
            //{
            //    // redis.rename
            //}
            else
            {
                //var ndic = Cache.GetDictionary<Object>(nkey);
                var ndic = CreateSession(newToken);
                foreach (var item in dic)
                {
                    ndic[item.Key] = item.Value;
                }
            }

            // 确保建立新的
            return GetSession(newToken);
        }

        ///// <summary>修复session(服务器切换或机房切换情况)</summary>
        ///// <returns></returns>
        //public IDictionary<String, Object> FixSession(String token)
        //{
        //    if (token.IsNullOrEmpty()) return null;
        //    var key = GetKey(token);

        //    // 采用哈希结构。内存缓存用并行字段,Redis用Set
        //    var dic = Cache.GetDictionary<Object>(key);
        //    Cache.SetExpire(key, Expire);

        //    return dic;
        //}

        /// <summary>根据令牌活期缓存Key</summary>
        /// <param name="token"></param>
        /// <returns></returns>
        protected virtual String GetKey(String token) => (!token.IsNullOrEmpty() && token.Length > 16) ? token.MD5() : token;
    }
}