ESFramework 开发手册(04) -- 动态组
最新的 ESFramework v7.0 新增了动态组功能,位于 ESPlus.Application.DynamicGroup 命名空间,动态组包含两种:持久组和临时组。
(1)持久组:不仅在运行进程的内存中存在,而且还存在于持久化介质中,如数据库中。
(2)临时组:仅仅在运行进程的内存中存在,不需要持久化存储。
正如其名,临时组是一个临时的东西,当第一个用户加入时创建它,当最后一个用户从组中退出时,就销毁它了。
比如:微信群就是一个持久组,而在微信群中发起一个群视频聊天,就是临时组。
一. 动态组约定
ESFramework 动态组有如下约定:
(1)当第一个人加入组时,服务端将在内存中创建组,当最后一个人从组中退出时,则在内存中销毁该组。
(2)可以通过动态组的属性来控制:当目标用户掉线时,是否要从组中移除。
(3)ESFramework 动态组不直接与数据库关联,而是:动态组服务端提供API允许向 ESFramework 注入从数据库中加载的持久组;以及提供事件通知上层应用去更新DB中的持久组。
二. 动态组功能服务端详解
在服务端定义了ESPlus.Application.DynamicGroup.IDynamicGroupController接口,当服务端引擎初始化成功后,可以通过其暴露的DynamicGroupController属性来使用动态组功能。
/// <summary> /// 动态组控制器。 /// 1.动态组分为两种类型:组员掉线就从组中移除,或者不移除(默认值)。服务端通过IDynamicGroupController.SetGroupActionType方法可以设定这个类型。 /// 2.巧妙使用PresetGroup方法,可以在服务端启动的时候,就预设一些已经存在的组(比如从DB中加载的群)。 /// </summary> public interface IDynamicGroupController { /// <summary> /// 当服务端接收到要在组内转发的广播消息时,触发此事件。参数:broadcasterID - groupID - broadcastType - broadcastContent - tag /// </summary> event CbGeneric<string, string, int, byte[], string> BroadcastReceived; /// <summary> /// 第一个成员加入组将导致动态组被创建,触发该事件。参数:groupID /// </summary> event CbGeneric<string> GroupCreated; /// <summary> /// 最后一个成员退出组将导致动态组被销毁,触发该事件。参数:groupID /// </summary> event CbGeneric<string> GroupDestroyed; /// <summary> /// 当新成员加入组时,触发该事件。参数:groupID - memberID /// </summary> event CbGeneric<string, string> SomeoneJoinGroup; /// <summary> /// 当成员退出组时,触发该事件。参数:groupID - memberID /// </summary> event CbGeneric<string, string> SomeoneQuitGroup; /// <summary> /// 当某些人被拉入组时,触发该事件。参数:groupID - memberIDs - operatorID。 /// 当OperatorID为null时,表示操作者是服务端。 /// </summary> event CbGeneric<string, List<string>, string> SomeoneBePulledIntoGroup; /// <summary> /// 当某些人被移除组时,触发该事件。参数:groupID - memberIDs - operatorID /// 当OperatorID为null时,表示操作者是服务端。 /// </summary> event CbGeneric<string, List<string>, string> SomeoneBeRemovedFromGroup; /// <summary> /// 当目标组的Tag发生变化时,触发该事件。groupID - newTag - operatorID /// </summary> event CbGeneric<string, string, string> GroupTagChanged; /// <summary> /// 在组内广播信息。 /// </summary> /// <param name="groupID">接收广播信息的组ID</param> /// <param name="broadcastType">广播信息的类型</param> /// <param name="broadcastContent">广播的内容</param> /// <param name="tag">附加信息</param> void Broadcast(string groupID, int broadcastType, byte[] broadcastContent, string tag); /// <summary> /// 将用户拉入组。 /// </summary> void PullIntoGroup(string groupID, List<string> members); /// <summary> /// 将用户从动态组中移除。 /// </summary> void RemoveFromGroup(string groupID, List<string> members); /// <summary> /// 获取组信息。 /// </summary> GroupInfo GetGroup(string groupID); /// <summary> /// 获取所有组友列表。 /// </summary> List<string> GetGroupmates(string userID); /// <summary> /// 获取所有动态组的ID列表。 /// </summary> List<string> GetGroupList(); /// <summary> /// 设置组反应类型(当组成员掉线时)。 /// 注意:最好是在GroupCreated事件中,即组被创建时就立即设置该组的ActionType。 /// 如果不设置,则默认为:当目标组中的成员掉线时,不会从该组中移除成员。 /// </summary> /// <param name="groupID">目标组ID</param> /// <param name="quitGroupWhenOffline">当目标组中的成员掉线时,是否从该组中移除?默认值:false。</param> void SetGroupActionType(string groupID, bool quitGroupWhenOffline); /// <summary> /// 预设组。 /// 如果目标组ID已经存在,将抛出异常。 /// </summary> /// <param name="groupID">组ID</param> /// <param name="members">组成员列表</param> void PresetGroup(string groupID, List<string> members); /// <summary> /// 设置目标组的Tag。组成员将收到GroupTagChanged事件通知。 /// 前提:目标组必须存在,否则将忽略该调用。 /// </summary> /// <param name="groupID">目标组ID</param> /// <param name="tag">新的tag</param> void SetGroupTag(string groupID, string tag);
/// <summary> /// 获取目标组的Tag。 /// </summary> /// <param name="groupID">目标组ID</param> string GetGroupTag(string groupID); }
(1)BroadcastReceived 当服务端接收到要在组内转发的广播消息时,触发此事件,如组内成员调用在客户端调用 IDynamicGroupOutter 的 Broadcast 方法广播消息时,就会触发。
(2)SetGroupActionType 第二个参数quitGroupWhenOffline 当目标组中的成员掉线时,是否从该组中移除,该参数可将组分为不同的类型。
true:一般用于临时群,组成员掉线后,直接将该成员从组中移除; false:一般用于持久群。
(3)PresetGroup 可以在服务端启动时,预先将一些已经存在的群组装载进去(如装载DB中的群)。
三. 动态组功能客户端详解
在客户端,定义了ESPlus.Application.DynamicGroup.Passive.IDynamicGroupOutter 接口,我们可以通过IRapidPassiveEngine暴露出的DynamicGroupOutter属性,来使用动态组功能。
public interface IDynamicGroupOutter { /// <summary> /// 当接收到某个组内的广播消息时,触发此事件。参数:broadcasterID - groupID - broadcastType - broadcastContent - tag。 /// 如果broadcasterID为null,表示是服务端发送的广播。 /// </summary> event CbGeneric<string, string, int, byte[], string> BroadcastReceived; /// <summary> /// 当某个动态组的组友掉线时,触发此事件。 /// </summary> event CbGeneric<string> GroupmateOffline; /// <summary> /// 当某个动态组的组友上线时,触发此事件。 /// </summary> event CbGeneric<string> GroupmateOnline; /// <summary> /// 当新成员加入组时,触发该事件。参数:groupID - memberID /// </summary> event CbGeneric<string, string> SomeoneJoinGroup; /// <summary> /// 当成员退出组时,触发该事件。参数:groupID - memberID /// </summary> event CbGeneric<string, string> SomeoneQuitGroup; /// <summary> /// 当某人被拉入组时,触发该事件。参数:groupID - memberIDList - operatorID。 /// 当OperatorID为null时,表示操作者是服务端。 /// </summary> event CbGeneric<string, List<string> ,string> SomeoneBePulledIntoGroup; /// <summary> /// 当某人被移除组时,触发该事件。参数:groupID - memberIDList - operatorID /// 当OperatorID为null时,表示操作者是服务端。 /// </summary> event CbGeneric<string, List<string>, string> SomeoneBeRemovedFromGroup; /// <summary> /// 当自己被拉入组时,触发该事件。参数:groupInformation - operatorID。 /// 当OperatorID为null时,表示操作者是服务端。 /// </summary> event CbGeneric<GroupInfo, string> BePulledIntoGroup; /// <summary> /// 当自己被移除组时,触发该事件。参数:groupID - operatorID /// 当OperatorID为null时,表示操作者是服务端。 /// </summary> event CbGeneric<string, string> BeRemovedFromGroup; /// <summary> /// 当收到加入组的邀请时,触发该事件。参数:GroupInformation - OperatorID。 /// 注意:收到邀请时,自己尚未加入组。若接受邀请,则可以调用JoinGroup加入目标组。 /// </summary> event CbGeneric<GroupIn, string> BeInvitedJoinGroup; /// <summary> /// 当目标组的Tag发生变化时,触发该事件。GroupID - newTag - OperatorID /// </summary> event CbGeneric<string, string, string> GroupTagChanged; /// <summary> /// 在目标组内广播消息。 /// </summary> /// <param name="groupID">目标组ID</param> /// <param name="broadcastType">广播消息类型</param> /// <param name="broadcastContent">广播消息内容</param> /// <param name="tag">Tag</param> void Broadcast(string groupID, int broadcastType, byte[] broadcastContent, string tag); /// <summary> /// 获取我的所有组。 /// </summary> /// <returns>组ID列表</returns> List<string> GetMyGroups(); /// <summary> /// 获取组信息。 /// </summary> /// <param name="groupID">目标组ID</param> /// <param name="useLocalCache">是否使用本地缓存?如果为true且本地有缓存,则直接从本地缓存获取组信息。</param> /// <returns></returns> GroupInfo GetGroupInformation(string groupID, bool useLocalCache); /// <summary> /// 获取所有在线组友的列表。 /// </summary> List<string> GetOnlineGroupmates(); /// <summary> /// 设置目标组的Tag。其它组成员将收到GroupTagChanged事件通知。 /// 前提:目标组必须存在,否则将忽略该调用。 /// </summary> /// <param name="groupID">目标组ID</param> /// <param name="tag">新的tag</param> void SetGroupTag(string groupID, string tag); /// <summary> /// 加入组。 /// </summary> void JoinGroup(string groupID); /// <summary> /// 退出组。 /// </summary> void QuitGroup(string groupID); /// <summary> /// 将用户拉入组。 /// </summary> void PullIntoGroup(string groupID, List<string> members); /// <summary> /// 将用户从动态组中移除。 /// </summary> void RemoveFromGroup(string groupID, List<string> members); /// <summary> /// 邀请用户加入动态组。被邀请的用户将会触发BeInvitedJoinGroup事件。 /// </summary> void InviteJoinGroup(string groupID, List<string> users); /// <summary> /// 清空本地缓存的所有组信息。(在掉线重连成功后,本地缓存有可能已经过时) /// </summary> void ClearLocalCache(); }
(1)GetMyGroups 获取我所在的所有的组。
(2)GetOnlineGroupmates 获取所有在线组友的列表 (所有组中的在线组友集合)。
(3)GetGroupInformation 方法可以查询指定组的 详细信息(包括该组的ID、所有成员ID、组Tag)。
(4)JoinGroup 加入群组 ,当传入的groupID在服务端不存在时,会自动生成该组,并将该调用者加入到该群组中。 同时服务端也会触发 GroupCreated 事件。
(5)PullIntoGroup 将某些用户拉入到指定的组中去,被拉入的用户将会触发 BePulledIntoGroup 事件,同时该组中其他的组友将会触发 SomeoneBePulledIntoGroup 事件。
(6)Broadcast 向指定组发送广播消息, 其他组内成员将会触发 BroadcastReceived 事件(同时服务端也会触发 BroadcastReceived 事件)来接收该广播消息。
四.补充说明
1.如何实现在客户端创建群?
在客户端调用IDynamicGroupOutter 的 JoinGroup方法或 PullIntoGroup 方法,都可以动态创建一个群。
如果需要将该群持久化存储到DB中,可以在服务端预定IDynamicGroupController 的 GroupCreated 事件来得到通知。
2.如何实现客户端加群申请?
这个可以通过ESFramework的自定义消息来实现:
申请者A向管理者B发送一条自定义消息表示申请加入某群,当A收到B的同意加入的回复后,就调用IDynamicGroupOutter 的 JoinGroup方法正式加入群中。
3.如何在服务端方便地保存动态组的相关信息(如管理员ID、群公告、群说明等等)?
可以巧妙使用Group的Tag来保存与动态组相关的信息,服务端和客户端都可以通过SetGroupTag来修改动态组携带的Tag信息。
-----------------------------------------------------------------------------------------------------------------------------------------------
Q Q:168757008