(本文适用于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) ;
}
}
//
![](http://img.e-com-net.com/image/info5/8ff8465881fe40bba54d0575b44a9c32.png)
我们需要另外一个组件来负责发送OverdueMessage给目标用户,那就是OverdueMessageSender,它可以让你指定在多久之后发送OverdueMessage给指定的用户,如果没有指定这个时间间隔,就立即发送。
![ESFramework介绍之(27)-- 支持OverdueMessage_第1张图片](http://img.e-com-net.com/image/info5/74b9d26e373a44e09779365a170aa006.jpg)
OverdueMessageSender
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链接到这一时机。
![ESFramework介绍之(27)-- 支持OverdueMessage_第2张图片](http://img.e-com-net.com/image/info5/1e16360a03894f6d8b82ffd7eefb5e29.jpg)
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处理。
(ESFramework V0.2 将会在五一假期后上载)
感谢关注!
上一篇文章:ESFramework介绍之(26)-- 支持复杂插件(InnerDealer 和 InnerDispatcher)
转到 :ESFramework 可复用的通信框架(序)