obsidian/笔记文件/2.笔记/更完善的 通用消息缓存器.md
2025-03-26 00:02:56 +08:00

23 KiB

#灵感/代码缓存

SessionMgr

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using HTFramework.Utility;
using IslandMatch;
using UnityEngine;
using Newtonsoft.Json;
using UnityEngine.Networking;

namespace CGBU_SDK
{

    /// <summary>
    /// 会话时间管理类
    /// </summary>
    public class SessionMgr : MonoSingleton<SessionMgr>
    {
        // private const string appId = "3f99e16c541a";
        // private const string reportUrl = "https://global-receiver-ias.icongamesg.com/report/?appid=" + appId;
        
        private const string StartSession = "start_session";
        private const string EndSession = "end_session";
        // private const string sessionCachePrefsKey = "sessionCachePrefsKey";

        private const string ReSendUrl = "&batch=1";
        
        private string _sessionId;
        private string _publicString;
        private long  _startEventTimestamp;
        private long _endEventTimestamp;
        private Dictionary<string, object> _eventDic;
        private Dictionary<string, object> _userDataDic;

        private string _uid = String.Empty;
        private string _uuid = String.Empty;


        #region 生命周期
        
        private void Awake()
        {
            _uid = SystemInfo.deviceUniqueIdentifier;
        }
        

        private void OnDestroy()
        {
            StopNetworkRequest();
        }

        /// <summary>
        /// 切后台 暂停游戏
        /// </summary>
        /// <param name="pauseStatus"></param>
        private void OnApplicationPause(bool pauseStatus)
        {
            if (pauseStatus)
            {
                SendEndSessionEvent();
            }
            ReSend();
        }
        

        /// <summary>
        /// 退出游戏
        /// </summary>
        private void OnApplicationQuit()
        {
            AddToList(CreateEndEvent());
        }

        private SessionEventData CreateEndEvent()
        {
            _endEventTimestamp = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
            SessionEventData _sessionEndEventData = new SessionEventData
            {
                uuid =  _uuid,
                event_name = EndSession,
                event_timestamp = _endEventTimestamp,
                public_properties = _publicString,
                event_properties = _eventDic
            };

            _sessionEndEventData.event_name = EndSession;
            _sessionEndEventData.event_timestamp = _endEventTimestamp;
            
            _sessionEndEventData.event_properties["session_dur"] = _endEventTimestamp - _startEventTimestamp;
            _sessionEndEventData.event_properties["user_properties"] = _userDataDic;
            return _sessionEndEventData;
        }
        

        #endregion

        #region 会话收发&业务逻辑

        /// <summary>
        /// 发送结束会话事件
        /// </summary>
        private void SendEndSessionEvent()
        {
            SessionEventData endData = CreateEndEvent();
            ReportEvent(endData);
        }


        /// <summary>
        /// 初始化 发送开始会话事件
        /// </summary>
        /// <param name="wake"></param>
        /// <param name="publicString"></param>
        /// <param name="uid"></param>
        /// <param name="eventDataDic"></param>
        /// <param name="userDataDic"></param>
        public void OnInit(bool wake,string publicString,string uid = null,Dictionary<string,object> eventDataDic = null,Dictionary<string,object> userDataDic = null)
        {

            // if (PlayerPrefs.HasKey(sessionCachePrefsKey))
            // {
            //     PlayerPrefs.DeleteKey(sessionCachePrefsKey);
            //     PlayerPrefs.Save();
            // }
            // return;
            
            if (!wake)
            {
                Destroy(gameObject);
                return;
            }

            SessionCache.Instance.OnInit(publicString, 7);
            
            _uid = uid != null ? uid : _uid;
            _publicString = publicString;
            _startEventTimestamp = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
            // _sessionId = _uid + _startEventTimestamp + GenerateRandomString(10);
            _sessionId = DateTime.Now.ToUniversalTime().Ticks.ToString();

            _uuid = Guid.NewGuid().ToString();

            _userDataDic = new Dictionary<string, object>();
            _eventDic = new Dictionary<string, object>
            {
                ["session_id"] = _sessionId,
                ["session_dur"] = 0,
                ["user_properties"] = _userDataDic
                
            };
            
            SessionEventData _sessionStartEventData = new SessionEventData
            {
                uuid =  _uuid,
                event_name = StartSession,
                event_timestamp = _startEventTimestamp,
                public_properties = _publicString,
                event_properties = _eventDic
            };
            
            ChangeEventDataDic(eventDataDic);
            ChangeUserDataDic(userDataDic);
            ReportEvent(_sessionStartEventData);
            ReSend();
        }

        
        /// <summary>
        /// 修改事件数据
        /// </summary>
        /// <param name="eventDataDic"></param>
        public void ChangeEventDataDic(Dictionary<string, object> eventDataDic)
        {
            if (eventDataDic != null)
            {
                Dictionary<string, object> mergedDict = _eventDic.Union(eventDataDic.Where(kvp => !_eventDic.ContainsKey(kvp.Key)))
                    .ToDictionary(pair => pair.Key, pair => pair.Value);
                _eventDic = mergedDict;
            }
        }

        /// <summary>
        /// 修改用户数据
        /// </summary>
        /// <param name="userDataDic"></param>
        public void ChangeUserDataDic(Dictionary<string,object> userDataDic)
        {
            _userDataDic = userDataDic == null ? _userDataDic : userDataDic;
        }
        
        private void ReportEvent(SessionEventData eventData)
        {
            AddToList(eventData);
            StartNetworkRequest(Instance.SendSessionEvent(eventData));
        }
        
        /// <summary>
        /// 单独发送 会话数据
        /// </summary>
        /// <param name="eventDataStr"></param>
        /// <param name="eventData"></param>
        /// <returns></returns>
        private IEnumerator SendSessionEvent(SessionEventData eventData)
        {
            string eventDataStr = JsonConvert.SerializeObject(eventData);
            // 发送POST请求
            using (UnityWebRequest www = new UnityWebRequest(GlobalConst.AnalyseUrl + GlobalConst.AnalyseAppId, "POST"))
            {
                byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(eventDataStr);
                www.uploadHandler = new UploadHandlerRaw(bodyRaw);
                www.downloadHandler = new DownloadHandlerBuffer();
                www.SetRequestHeader("Content-Type", "application/json");
                yield return www.SendWebRequest();


                // 检查是否有错误发生
                if (www.result != UnityWebRequest.Result.Success)
                {
                    // Debug.Log("Error: " + www.error);
                }
                else
                {
                    // 获取服务器响应的文本内容
                    // string responseText = www.downloadHandler.text;
                
                    // 输出服务器响应内容
                    // Debug.Log("Server Response: " + responseText);
                    
                    if (eventData != null) //如果是批量重发,就清空缓存器
                    {
                        SessionCache.Instance.RemoveEventData(eventData.event_name,eventData.uuid);
                    }
                }

                if (www.isNetworkError || www.isHttpError)
                {
                    // Debug.LogError("Error: " + www.error);
                }
            }
        }

        private void ReSend()
        {
            string ListStr = String.Empty;
            Dictionary<string,List<string>> showDic = SessionCache.Instance.CleanDelayAndCollectEvent(ref ListStr);

            if (ListStr != String.Empty && ListStr.Length > 0)
            {
                StartNetworkRequest(Instance.SendCacheEvent(ListStr,showDic));
            }
        }
        
        


        /// <summary>
        /// 发送缓存数据
        /// </summary>
        /// <returns></returns>
        private IEnumerator SendCacheEvent(string ListStr,Dictionary<string,List<string>> showDic)
        {
            // 发送POST请求
            using (UnityWebRequest www = new UnityWebRequest(GlobalConst.AnalyseUrl + GlobalConst.AnalyseAppId + ReSendUrl, "POST"))
            {
                byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(ListStr);
                www.uploadHandler = new UploadHandlerRaw(bodyRaw);
                www.downloadHandler = new DownloadHandlerBuffer();
                www.SetRequestHeader("Content-Type", "application/json");
                yield return www.SendWebRequest();


                // 检查是否有错误发生
                if (www.result != UnityWebRequest.Result.Success)
                {
                    // Debug.Log("Error: " + www.error);
                }
                else
                {
                    // 获取服务器响应的文本内容
                    // string responseText = www.downloadHandler.text;
                
                    // 输出服务器响应内容
                    // Debug.Log("Server Response: " + responseText);

                    foreach (KeyValuePair<string,List<string>> keyValuePair in showDic)
                    {
                        for (int i = 0; i < keyValuePair.Value.Count; i++)
                        {
                            if (SessionCache.Instance.SessionDic.ContainsKey(keyValuePair.Key) &&
                                SessionCache.Instance.SessionDic[keyValuePair.Key].ContainsKey(keyValuePair.Value[i]))
                            {
                                SessionCache.Instance.SessionDic[keyValuePair.Key].Remove(keyValuePair.Value[i]);
                            }
                        }
                        keyValuePair.Value.Clear();
                    }
                    showDic.Clear();
                    ReSend();
                }

                if (www.isNetworkError || www.isHttpError)
                {
                    // Debug.LogError("Error: " + www.error);
                }
            }
        }
        

        private void AddToList(SessionEventData sessionEventData)
        {
            SessionCache.Instance.AddEvetData(Session_Name.start_end_session,sessionEventData);
        }
        

        #endregion
        

        #region 协程处理

        private Coroutine networkCoroutine;

        private void StartNetworkRequest(IEnumerator coroutine)
        {
            if (networkCoroutine == null) //检查是否已有协程在运行
            {
                networkCoroutine = StartCoroutine(coroutine);
            }
            else
            {
                StopCoroutine(networkCoroutine);
                networkCoroutine = StartCoroutine(coroutine);
            }
        }
        
        private void StopNetworkRequest()
        {
            if (networkCoroutine != null)
            {
                StopCoroutine(networkCoroutine);
                networkCoroutine = null;
            }
        }

        #endregion

    }
    

    /// <summary>
    /// 消息事件 缓存器
    /// </summary>
    public class SessionCache : Singleton<SessionCache>
    {


        public Dictionary<string, Dictionary<string,object>> SessionDic;
        private const string sessionCacheKey = "sessionCacheKey";
        private const string tempIdCacheKey = "tempIdCacheKey";
        private string _publicString = String.Empty;
        private int _deleteDay; //延迟几天删除

        public void OnInit(string publicString,int day)
        {
            // if (PlayerPrefs.HasKey(sessionCacheKey))
            // {
            //     PlayerPrefs.DeleteKey(sessionCacheKey);
            //     PlayerPrefs.Save();
            // }
            // return;

            _publicString = publicString;
            _deleteDay = day;

            InitData();

        }

        private void InitData()
        {

            if (PlayerPrefs.HasKey(sessionCacheKey))
            {
                SessionDic = JsonConvert.DeserializeObject<Dictionary<string,Dictionary<string,object>>>(PlayerPrefs.GetString(sessionCacheKey, ""));
            }
            else
            {
                SessionDic = new Dictionary<string, Dictionary<string,object>>();
            }
        }

        public void AddEvetData(Session_Name event_Name,object eventData)
        {
            switch (event_Name)
            {
                case Session_Name.start_end_session:
                    SessionEventData start_end_session  = eventData as SessionEventData;
                    start_end_session.public_properties = String.Empty;
                    if (!SessionDic.ContainsKey(Session_Name.start_end_session.ToString()))
                    {
                        Dictionary<string,object> start_sessionDic = new Dictionary<string, object>();
                        SessionDic.Add(Session_Name.start_end_session.ToString(), start_sessionDic);
                    }

                    if (!SessionDic[Session_Name.start_end_session.ToString()].ContainsKey(start_end_session.uuid))
                    {
                        SessionDic[Session_Name.start_end_session.ToString()].Add(start_end_session.uuid,JsonConvert.SerializeObject(start_end_session));
                    }
                    break;
                case Session_Name.default_session:
                    EventData default_session = eventData as EventData;
                    default_session.public_properties = String.Empty;
                    if (!SessionDic.ContainsKey(Session_Name.default_session.ToString()))
                    {
                        Dictionary<string,object> default_sessionDic = new Dictionary<string, object>();
                        SessionDic.Add(Session_Name.default_session.ToString(), default_sessionDic);
                    }
                    if (!SessionDic[Session_Name.default_session.ToString()].ContainsKey(default_session.uuid))
                    {
                        SessionDic[Session_Name.default_session.ToString()].Add(default_session.uuid,JsonConvert.SerializeObject(default_session));
                    }
                    break;
            }
            SaveCache();

        }

        /// <summary>
        /// 保存缓存数据
        /// </summary>
        public void SaveCache()
        {
            PlayerPrefs.SetString(sessionCacheKey,JsonConvert.SerializeObject(SessionDic));
            PlayerPrefs.Save();
        }

        
        /// <summary>
        /// 移除特定缓存数据
        /// </summary>
        /// <param name="event_Name">对应缓存eventName名称</param>
        /// <param name="uuid"></param>
        public void RemoveEventData(string event_Name, string uuid)
        {
            if (SessionDic.ContainsKey(event_Name) && SessionDic[event_Name].ContainsKey(uuid))
            {
                SessionDic[event_Name].Remove(uuid);
            }
        }

        
        /// <summary>
        /// 清理过期数据
        /// </summary>
        /// <returns></returns>
        public Dictionary<string,List<string>> CleanDelayAndCollectEvent(ref string ListStr)
        {
            Dictionary<string, List<string>> _deleteDic = new Dictionary<string, List<string>>(); //过期需要清理的缓存数据
            Dictionary<string, List<string>> _showDic = new Dictionary<string, List<string>>(); //单次缓存数据的存储
            List<object> eventList = new List<object>(10); //和服务端沟通 定单次缓存的 数组容量为10
            foreach (KeyValuePair<string,Dictionary<string,object>> keyValuePair in SessionDic)
            {
                switch (keyValuePair.Key)
                {
                    case "start_end_session":
                        foreach (KeyValuePair<string,object> valuePair in keyValuePair.Value)
                        {
                            SessionEventData start_end_session_SessionEventData = JsonConvert.DeserializeObject<SessionEventData>(valuePair.Value.ToString());
                            start_end_session_SessionEventData.public_properties = _publicString;
                            if (GetDeleyTime(start_end_session_SessionEventData.event_timestamp))
                            {
                                if (!_deleteDic.ContainsKey(Session_Name.start_end_session.ToString()))
                                {
                                    List<string> uuidList = new List<string>();
                                    _deleteDic.Add(Session_Name.start_end_session.ToString(),uuidList);
                                }

                                _deleteDic[Session_Name.start_end_session.ToString()].Add(start_end_session_SessionEventData.uuid);
                            }
                            else
                            {
                                if (eventList.Count < 10)
                                {
                                    eventList.Add(start_end_session_SessionEventData);
                                    if (!_showDic.ContainsKey(Session_Name.start_end_session.ToString()))
                                    {
                                        List<string> uuidList = new List<string>();
                                        _showDic.Add(Session_Name.start_end_session.ToString(),uuidList);
                                    }

                                    _showDic[Session_Name.start_end_session.ToString()].Add(start_end_session_SessionEventData.uuid);
                                }
                            }
                        }
                        break;
                    case "default_session":
                        foreach (KeyValuePair<string,object> valuePair in keyValuePair.Value)
                        {
                            EventData default_session_SessionEventData = JsonConvert.DeserializeObject<EventData>(valuePair.Value.ToString());
                            default_session_SessionEventData.public_properties = _publicString;
                            if (GetDeleyTime(default_session_SessionEventData.event_timestamp))
                            {
                                if (!_deleteDic.ContainsKey(Session_Name.default_session.ToString()))
                                {
                                    List<string> uuidList = new List<string>();
                                    _deleteDic.Add(Session_Name.default_session.ToString(),uuidList);
                                }
            
                                _deleteDic[Session_Name.default_session.ToString()].Add(default_session_SessionEventData.uuid);
                            }
                            else
                            {
                                if (eventList.Count < 10)
                                {
                                    eventList.Add(default_session_SessionEventData);
                                    if (!_showDic.ContainsKey(Session_Name.default_session.ToString()))
                                    {
                                        List<string> uuidList = new List<string>();
                                        _showDic.Add(Session_Name.default_session.ToString(),uuidList);
                                    }

                                    _showDic[Session_Name.default_session.ToString()].Add(default_session_SessionEventData.uuid);
                                }
                            }
                        }
                        break;
                }
            }
            
            foreach (KeyValuePair<string,List<string>> keyValuePair in _deleteDic)
            {
                for (int i = 0; i < keyValuePair.Value.Count; i++)
                {
                    SessionDic[keyValuePair.Key].Remove(keyValuePair.Value[i]);
                }
            }

            if (eventList.Count > 0)
            {
                ListStr = JsonConvert.SerializeObject(eventList);
            }
            else
            {
                ListStr = String.Empty;
            }

            return _showDic;

        }
        
        private bool GetDeleyTime(long t)
        {
            double time = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000 - t;
            if (Math.Floor(time / 86400) > _deleteDay)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 处理临时id
        /// </summary>
        /// <returns></returns>
        public long TempId()
        {
            //缓存临时id的机制
            long _uid;
            if (EliminateModule.TempUid())
            {
                if (!PlayerPrefs.HasKey(tempIdCacheKey))
                {
                    PlayerPrefs.SetString(tempIdCacheKey,EliminateModule.GetUid());
                    PlayerPrefs.Save();
                }

                _uid = long.Parse(PlayerPrefs.GetString(tempIdCacheKey));
            }
            else
            {
                if (PlayerPrefs.HasKey(tempIdCacheKey))
                {
                    EventData match_tmp_event = new EventData
                    {
                        uuid =  Guid.NewGuid().ToString(),
                        event_name = "match_tmp_id",
                        event_properties =
                        {
                            {"tmp_uid",long.Parse(PlayerPrefs.GetString(tempIdCacheKey))},
                            {"real_uid",long.Parse(EliminateModule.GetUid())}
                        }
                    };
                    AddEvetData(Session_Name.default_session, match_tmp_event);

                    PlayerPrefs.DeleteKey(tempIdCacheKey);
                    PlayerPrefs.Save();
                }
                
                _uid = long.Parse(EliminateModule.GetUid());
            }
            return _uid;
        }

    }
    
    /// <summary>
    /// 开始&结束会话
    /// </summary>
    [Serializable]
    public class SessionEventData
    {
        public string uuid;
        public string event_name;
        public long event_timestamp;
        public string public_properties;
        public Dictionary<string, object> event_properties;
    }
    
    /// <summary>
    /// 普通会话
    /// </summary>
    [Serializable]
    public class EventData
    {
        public string uuid;
        public string event_name;
        public long event_timestamp;
        public string public_properties;
        public Dictionary<string, object> event_properties;
        public int tempUf;
    }

    public enum Session_Name
    {
        start_end_session, //开始/结束会话
        default_session //普通会话
    }
}