傲瑞组件开发手册(06) -- 消息推送组件 NPush
NPush是跨客户端平台的消息推送框架。用于实现类似微信的朋友圈功能,支持推送朋友圈消息,拉取朋友圈消息,查看目标好友的动态,点赞,评论等功能。
NPush服务端基于.NET,DB支持SqlServer和MySQL,客户端平台支持PC(.NET)、Android、iOS、HTTP。
一.基本概念
在NPush中,一条朋友圈动态消息被称为一个Moment(精彩瞬间)。发送一条Moment,称之为Push;获取朋友圈动态称之为Pull。对Moment的评论称之为Remark(点赞是Remark的一种特殊形式,可在应用层自定义)。
当Pull的时候,可以分为下拉和上拉。下拉,即请求最新的动态。上拉,则是请求较老的动态。就像在微信朋友圈UI中向上滑动和向下滑动的含义一样。在NPush中,使用bool参数latest(是否最新)来区分当前的Pull请求是下拉(latest为true)还是上拉(latest为false)。
NPush框架提供了服务端引擎 IServerEngine和客户端引擎 IMomentsClient,了解了这两个核心组件,就可以使用NPush来开发朋友圈功能了。
二.NPush 服务端引擎
NPush服务端引擎接口IServerEngine相当简洁,方便使用,其定义如下所示:
/// <summary> /// NPush服务端引擎接口。 /// </summary> public interface IServerEngine { /// <summary> /// 日志文件的路径。默认为运行目录下的AppLog.txt文件。 /// </summary> string LogFilePath { get; set; } /// <summary> /// NPush服务器配置选项。必须在Initialize方法调用之前设置才有效。 /// </summary> NPushConfiguration Configuration { get; set; } /// <summary> /// 当前用户数。 /// </summary> int UserCount { get; } /// <summary> /// 初始化。 /// </summary> /// <param name="port">为客户端提供服务的端口</param> /// <param name="verifier">用户帐号密码验证器。如果不需要验证,可以传入null。</param> /// <param name="friendProvider">好友关系提供者</param> /// <param name="persister">数据持久化接口</param> void Initialize(int port, IUserVerifier verifier, IFriendProvider friendProvider, IMomentsPersister persister); /// <summary> /// 获取在线用户列表。 /// </summary> List<string> GetUsers(); }
最简单地,只要调用引擎的Initialize方法,即可启动服务端。 Initialize方法需要注入三个关键的组件:
(1)IUserVerifier 用于验证登录的用户是否合法。
(2)IFriendProvider 用于提供好友关系。即当我推送一个Moment时,服务端通过该接口知道我有哪些好友,然后将该Moment推送给他们。
(3)IMomentsPersister 用于服务端与DB之间的交互,完成Moment的持久化存储。NPush内置了DBMomentsPersister类,支持SqlServer和MySQL。
如果需要支持其它的数据库类型,如Oracle等,则只需要自己实现 IMomentsPersister 接口即可。
另外,IServerEngine 的 Configuration 属性也很重要,在使用时,需要根据具体应用设置合适的值。
/// <summary> /// NPush服务器配置选项。 /// </summary> [Serializable] public class NPushConfiguration {
/// <summary> /// 针对每个用户的Push队列和Pull队列的大小。默认值:200。 /// </summary> public int MaxQueueSize {get; set;}
/// <summary> /// 对于Pull请求,每次回复的列表中包含Moments的最大个数。默认值:20。 /// </summary> public int MaxCountOfMoments4Request {get; set;}
/// <summary> /// 当服务端重启时,为目标用户重建Push队列或Pull队列时,需要重DB中加载最新的消息的数量。默认值:20。 /// </summary> public int LoadLatestCountOnStart {get; set;} }
注释已经描述得很清楚了,不再赘言。
三.NPush 客户端引擎
NPush客户端引擎接口是IMomentsClient,二次开发时,我们只需要使用这一个接口即可。
1.基础API
/// <summary> /// 当与节点服务器之间的TCP连接断开时,触发此事件。(连接断开将会自动重连) /// </summary> event CbGeneric ConnectionInterrupted; /// <summary> /// 当同名的帐号登录当前连接的服务器时,自己将被挤掉线(不再自动重连),触发此事件。 /// </summary> event CbGeneric PushedOut; /// <summary> /// 当与服务器重连上并登录完成后,触发此事件。请注意查看事件参数LoginResultType,如果登录失败,则表示当前客户端实例已经失效。 /// </summary> event CbGeneric<LoginResultType> RelogonCompleted; /// <summary> /// 与节点服务器之间的TCP连接是否正常? /// </summary> bool Connected { get; } /// <summary> /// 当前对象是否已经被释放? /// </summary> bool IsDisposed { get; } /// <summary> /// 初始化,并登录到服务器。 /// </summary> /// <param name="serverIP">服务器的IP</param> /// <param name="port">服务器的端口</param> /// <param name="userID">登录帐号</param> /// <param name="pwd">登录密码</param> /// <returns>登录结果</returns> LoginResultType Initialize(string serverIP, int port, string userID, string pwd);
(1)调用 IMomentsClient 的Initialize方法,将会与NPush服务端建立TCP连接,并用帐号密码登录。
(2)如果在客户端运行的过程中,与服务器之间的TCP连接中断,则将触发 ConnectionInterrupted 事件,并开始自动重连。
当重连成功并重新登录,则触发 RelogonCompleted 事件。
(3)Connetcted 属性反应了当前与服务器的连接是否正常。
(4)如果在客户端运行的过程中,有同名用户在其它地方重复登录,当前 IMomentsClient 将被挤掉线,并触发 PushedOut 事件。
2. 发送/推送 Moment
/// <summary> /// 在朋友圈发送消息。 /// </summary> /// <param name="msgType">消息类型。</param> /// <param name="content">消息内容</param> /// <param name="tag">附加tag</param> /// <returns>返回PassiveID</returns> string Push(int msgType, byte[] content, string tag);
通过这三个参数,我们可以自定义不同类型、各种格式的 Moment。
请注意 Push 方法的返回值,这个返回值称为PassiveID,是由客户端引擎为当前发送的Moment生成的一个ID,在服务端全局而言,它并不一定是唯一的。PassiveID最主要的作用,是用于删除自己刚发送的 Moment 或 Remark。后面的删除Moment/Remark 的API支持使用PassiveID作为参数,这样,对于二次开发是很方便的。
3.拉取Moment
/// <summary> /// 当调用Pull方法请求moment列表,得到服务器的回复时,触发此事件。 /// </summary> event CbGeneric<UserMoments> ResponseMomentReceived; /// <summary> /// 拉取我的朋友们发的消息。当收到服务器回复,将触发ResponseMomentsReceived事件。 /// </summary> /// <param name="startPullIndex">从哪个index的消息开始拉取(不包含该index对应的那条)。如果startPullIndex小于0,表示拉取最新的N条。</param> /// <param name="latest">latest为true,表示拉取更新的(大于startPullIndex);为false表示拉取之前的(小于startPullIndex)。</param> void Pull(long startPullIndex, bool latest); /// <summary> /// 拉取目标用户所发的消息。当收到服务器回复,将触发ResponseMomentsReceived事件。 /// </summary> /// <param name="ownerID">所要拉取的目标用户的ID</param> /// <param name="startPushIndex">从哪个index的消息开始拉取(不包含该index对应的那条)。如果startPushIndex小于0,表示拉取最新的N条。</param> /// <param name="latest">latest为true,表示拉取更新的(大于startPullIndex);为false表示拉取之前的(小于startPullIndex)。</param> void Pull(string ownerID, long startPushIndex, bool latest);
(1)Pull方法有个重载。带两个参数的Pull方法,用户获取自己所有好友的动态。带三个参数的Pull方法用于获取指定好友发送的动态 -- 相当于查看他的主页。
(2)第一个Pull方法使用了 PullIndex 作为参数 ;第二个Pull方法,使用 PushIndex 作为参数。这里要重点解释一下 PullIndex 和 PushIndex的区别。
可以想象这样的模型: 服务端为每个用户都建立了两个队列,一个是Push队列,一个是Pull队列。每个Push队列和Pull队列都有一个自己的Index计数。
当一个用户发送一个Moment时,会在他的Push队列中加入一个Moment,并生成一个PushIndex值(连续增长)来标记它。
同时,会在该用户的每个好友的Pull队列里,加入一个指针指向源Moment,并生成一个PullIndex 值(连续增长)来标记这个指针。
至此,当调用第一个Pull方法时,服务端会从该用户的Pull队列中获取数据;当调用第二个方法时,则从目标用户的Push队列中获取数据。
(3)Pull请求被服务器处理后,返回的结果将触发 ResponseMomentReceived 事件。
4.评论、删除、通知
/// <summary> /// 当朋友圈有新的动态时,触发该事件。参数:ownerID - infoType - pullIndex /// </summary> event CbGeneric<string, int ,long> NewMomentNotified; /// <summary> /// 当朋友圈有我相关的新评论时,触发该事件。参数:remarkUserID - ownerID - pushIndex - remarkType - content - tosb /// </summary> event CbGeneric<string ,string, long , int ,string ,string> NewRemarkNotified; /// <summary> /// 当朋友圈消息被删除时,触发此事件。参数:ownerID - pushIndex /// </summary> event CbGeneric<string, long> RemoveMomentNotified; /// <summary> /// 当评论被删除时,触发此事件。参数:ownerID - pushIndex - remarkPassiveID /// </summary> event CbGeneric<string, long, string> RemoveRemarkNotified; /// <summary> /// 为朋友圈某条消息评论、点赞、回复评论。 /// </summary> /// <param name="ownerID">目标消息的发送者ID</param> /// <param name="momentPushIndex">目标消息的PushIndex</param> /// <param name="remarkType">评论的类型。自定义。比如0表示赞,1表示评论,2表示回复。</param> /// <param name="content">评论或回复的内容</param> /// <param name="tosb">如果是评论回复,则@用户的帐号</param> /// <returns>返回PassiveID</returns> string Remark(string ownerID ,long momentPushIndex ,int remarkType ,string content ,string tosb); /// <summary> /// 删除自己发的某条消息。 /// </summary> /// <param name="momentPushIndex">目标消息的PushIndex</param> void RemoveMoment(long momentPushIndex); /// <summary> /// 删除自己发的某条消息。 /// </summary> /// <param name="momentPassiveID">目标消息的PassiveID</param> void RemoveMoment(string momentPassiveID); /// <summary> /// 删除自己发的某条评论。 /// </summary> /// <param name="ownerID">目标消息的发送者ID</param> /// <param name="momentPushIndex">目标消息的PushIndex</param> /// <param name="remarkPassiveID">目标评论的PassiveID</param> void RemoveRemark(string ownerID, long momentPushIndex, string remarkPassiveID);
(1)Remark 方法的 remarkType 参数,使得我们可以定义多种类型的评论。比如,使用一个特殊的 remarkType 值,用来表示常见的 “点赞”功能。
(2)当删除一个 Moment 或 Remark 时,在服务器上并不是真的将其删除,而是将其 IsValid 属性设置为false。所以,客户端在加载显示时,要判断 IsValid 的值。
四.NPush入门Demo
Q Q:168757008