zoukankan      html  css  js  c++  java
  • 【转载】ESFramework介绍之(27)-- 支持OverdueMessage (离线消息)

    ESFramework介绍之(27)-- 支持OverdueMessage (离线消息)

       (本文适用于ESFramework V0.2+)
         QQ上,你给好友发消息,如果对方不在线,则服务器会把这个消息持久化存起来,等好友下次上线时,再转发给他。像这样的消息在ESFramework中称为OverdueMessage。显然,MSN没有支持OverdueMessage。 当然了,ESFramework中的OverdueMessage不仅仅是文字消息,而是可以为任何类型的消息,比如,音频、视频、文件等等。

        ESFramework中对所有P2P的消息的处理都是由P2PMessageDealer完成的,当P2PMessageDealer转发一个消息时,发现目标用户不在线,就会将这个消息交给一个称为IOverdueMessageHandler的组件处理,IOverdueMessageHandler组件可以持久化存储这个消息,也可以直接将其保存在内存中,具体采用哪种方式,取决于你的应用。
        IOverdueMessageHandler组件有如下职责:
    (1)保存(或持久化)存储OverdueMessage
    (2)提取指定目标用户的所有OverdueMessage
    (3)当OverdueMessage成功发送给目标用户后,改变OverdueMessage的状态或删除这些OverdueMessage。

        基于此,IOverdueMessageHandler接口设计如下:

        public interface IOverdueMessageHandler
        {
            
    bool  Enabled{set ;}
            
    void  HandleOverdueP2PMessage(NetMessage revMsg) ; 
            IList PickupOverdueP2PMessage(string destUserID) ; //列表中为NetMessage元素
            void  SetOverdueMessageSended(string destUserID) ;
        }

        对应的类图:
        
        IOverdueMessageHandler由应用实现,因为只有你的应用需求才能决定处理OverdueMessage的物理方式。P2PMessageDealer的实现中引入了IOverdueMessageHandler,如下:

                int result = this.toClientSender.HookAndSendMessage(reqMsg.Header.DestUserID ,reqMsg) ;
                
    if(result != DataSendResult.Succeed) //处理没有发送成功的消息
                {
                    
    if(this.overdueMessageHandler != null)
                    {
                        
    this.overdueMessageHandler.HandleOverdueP2PMessage(reqMsg) ;
                    }
                }      
                
    //

        我们需要另外一个组件来负责发送OverdueMessage给目标用户,那就是OverdueMessageSender,它可以让你指定在多久之后发送OverdueMessage给指定的用户,如果没有指定这个时间间隔,就立即发送。
       


        public class OverdueMessageSender
        {
            
    #region property
            
    #region ToClientSender
            
    private IToClientSender toClientSender = null ; 
            
    public  IToClientSender ToClientSender
            {
                
    set
                {
                    
    this.toClientSender = value ;
                }
            }
            
    #endregion

            
    #region OverdueMessageHandler
            
    private IOverdueMessageHandler overdueMessageHandler = null ; 
            
    public  IOverdueMessageHandler OverdueMessageHandler
            {
                
    set
                {
                    
    this.overdueMessageHandler = value ;
                }
            }
            
    #endregion    

            
    #region SendDelay
            
    private int sendDelay = 0 ; //ms 
            public  int SendDelay
            {
                
    set
                {
                    
    this.sendDelay = value ;
                }
            }
            
    #endregion

            
    #region EsbLogger
            
    private IEsbLogger esbLogger = null ; 
            
    public  IEsbLogger EsbLogger
            {
                
    set
                {
                    
    this.esbLogger = value ;
                }
            }
            
    #endregion        
            
    #endregion

            
    public OverdueMessageSender()
            {            
            }

            
    public void SendOverdueMessage(string userID)
            {
                IList list 
    = this.overdueMessageHandler.PickupOverdueP2PMessage(userID) ;
                
    if(list == null)
                {
                    
    return ;
                }

                
    if(this.sendDelay <=0)
                {
                    
    this.DoSend(list ,userID) ;
                }      
                  
    else
                {
                    CbDoSend cb 
    = new CbDoSend(this.DoSend) ;
                    cb.BeginInvoke(list ,userID ,
    null ,null) ;            
                }
            }        

            
    #region DoSend
            
    private void DoSend(IList msgList ,string userID )
            {
                
    try
                {
                    
    if(this.sendDelay >0)
                    {
                        System.Threading.Thread.Sleep(
    this.sendDelay) ;
                    }
                    
                    
    foreach(NetMessage msg in msgList)
                    {
                        
    int result = this.toClientSender.HookAndSendMessage(userID ,msg) ;
                        
    if(result != DataSendResult.Succeed)
                        {
                            
    return ;
                        }
                    }

                    
    this.overdueMessageHandler.SetOverdueMessageSended(userID) ;
                }
                
    catch(Exception ee)
                {
                    
    this.esbLogger.Log(ee.GetType().ToString() ,ee.Message ,"ESFramework.Network.OverdueP2PMessageSender.DoSend" ,ErrorLevel.Standard) ;
                }
            }
            
    #endregion
        }

        
    internal delegate void CbDoSend(IList msgList ,string userID) ;

        注意,OverdueMessageSender借助OverdueMessageHandler来取出指定目标用户的OverdueMessage,并借助IToClientSender组件来发送这些OverdueMessage,最后,当发送成功,就调用OverdueMessageHandler的SetOverdueMessageSended方法。

        很多应用都要求在目标用户登录时,将属于他的OverdueMessage发送给它,这个时机可以从IBasicRequestDealer组件的SomeOneLogon事件切入,ESFramework对这一常见需求进行了支持,那就是OverdueMessageBridge。OverdueMessageBridge将OverdueMessageSender链接到这一时机。
       

        public class OverdueMessageBridge
        {

            
    #region BasicRequestDealer        
            
    public IBasicRequestDealer BasicRequestDealer
            {
                
    set
                {
                    
    if(value != null)
                    {
                        value.SomeOneLogon 
    += new CbLogon(value_SomeOneLogon);
                    }                
                }
            }
            
    #endregion
            
            
    #region OverdueMessageSender
            
    private OverdueMessageSender overdueMessageSender = null ; 
            
    public  OverdueMessageSender OverdueMessageSender
            {
                
    set
                {
                    
    this.overdueMessageSender = value ;
                }
            }
            
    #endregion

            
    public OverdueMessageBridge()
            {            
            }

            
    private void value_SomeOneLogon(string userID, NetMessage logonMsg)
            {
                
    this.overdueMessageSender.SendOverdueMessage(userID) ;
            }
        }

        如果你需要在其它时刻来发送OverdueMessage,自己构造一个对应的Bridge即可。

        细心的朋友可能会问,如果使用了Hook,那么Hook会不会对IOverdueMessageHandler.PickupOverdueP2PMessage()取出的消息产生影响?答案是不会。因为OverdueMessageSender采用的是和P2PMessageDealer一样的方式来发送OverdueMessage,所以如果存在Hook,OverdueMessage也会经过相同的Hook处理。

  • 相关阅读:
    Linux Shell 用法
    gdb调试用法
    grep 用法总结
    Cmake用法
    Win64/Linux 上PyMouse安装
    两道拓扑排序的问题
    hiho一下第76周《Suzhou Adventure》
    这类问题需要利用二进制的特殊性
    这种题应该诸位处理
    两道人数多,课程少,query多的题
  • 原文地址:https://www.cnblogs.com/fx2008/p/2263402.html
Copyright © 2011-2022 走看看