2020-03-12 16:23:21 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using LeanCloud.Realtime.Internal.WebSocket;
|
|
|
|
|
using LeanCloud.Realtime.Protocol;
|
2020-03-25 16:42:30 +08:00
|
|
|
|
using LeanCloud.Realtime.Internal.Controller;
|
2020-03-12 16:23:21 +08:00
|
|
|
|
|
|
|
|
|
namespace LeanCloud.Realtime {
|
|
|
|
|
public class LCIMClient {
|
2020-03-25 16:42:30 +08:00
|
|
|
|
internal Dictionary<string, LCIMConversation> ConversationDict;
|
2020-03-12 16:23:21 +08:00
|
|
|
|
|
2020-03-25 16:42:30 +08:00
|
|
|
|
public string Id {
|
2020-03-16 11:50:49 +08:00
|
|
|
|
get; private set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 16:42:30 +08:00
|
|
|
|
#region 事件
|
2020-03-17 16:17:19 +08:00
|
|
|
|
|
2020-03-12 16:23:21 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前用户被加入某个对话的黑名单
|
|
|
|
|
/// </summary>
|
2020-03-25 16:42:30 +08:00
|
|
|
|
public Action<LCIMConversation, string> OnBlocked {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当用户被解除黑名单
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, string> OnUnblocked {
|
2020-03-12 16:23:21 +08:00
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 17:42:04 +08:00
|
|
|
|
/// <summary>
|
2020-03-25 16:42:30 +08:00
|
|
|
|
/// 当前用户在某个对话中被禁言
|
2020-03-24 17:42:04 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, string> OnMuted;
|
|
|
|
|
|
2020-03-25 16:42:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前用户在某个对话中被解除禁言
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, string> OnUnmuted;
|
|
|
|
|
|
2020-03-12 16:23:21 +08:00
|
|
|
|
/// <summary>
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// 客户端连接断开
|
2020-03-12 16:23:21 +08:00
|
|
|
|
/// </summary>
|
2020-03-17 11:41:38 +08:00
|
|
|
|
public Action OnPaused {
|
2020-03-12 16:23:21 +08:00
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// 客户端连接恢复正常
|
2020-03-12 16:23:21 +08:00
|
|
|
|
/// </summary>
|
2020-03-17 11:41:38 +08:00
|
|
|
|
public Action OnResume {
|
2020-03-12 16:23:21 +08:00
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// 当前客户端被服务端强行下线
|
2020-03-12 16:23:21 +08:00
|
|
|
|
/// </summary>
|
2020-03-25 16:42:30 +08:00
|
|
|
|
public Action<int, string, string> OnClose {
|
2020-03-12 16:23:21 +08:00
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 17:42:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 客户端连接断开
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action OnDisconnect {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 用户在其他客户端登录,当前客户端被服务端强行下线
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<string> OnConflict {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 该对话信息被更新
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, Dictionary<string, object>, string> OnConversationInfoUpdated;
|
|
|
|
|
|
2020-03-12 16:23:21 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前用户被添加至某个对话
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, string> OnInvited {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前用户被从某个对话中移除
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, string> OnKicked {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 有用户被添加至某个对话
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, List<string>, string> OnMembersJoined {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 17:42:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 有成员被从某个对话中移除
|
|
|
|
|
/// </summary>
|
2020-03-12 16:23:21 +08:00
|
|
|
|
public Action<LCIMConversation, List<string>, string> OnMembersLeft {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 17:42:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 有成员被加入某个对话的黑名单
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, List<string>, string> OnMembersBlocked {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 有成员被移出某个对话的黑名单
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, List<string>, string> OnMembersUnblocked {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 有成员在某个对话中被禁言
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, List<string>, string> OnMembersMuted {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 有成员被移出某个对话的黑名单
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<LCIMConversation, List<string>, string> OnMembersUnmuted {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 有成员的对话信息被更新
|
|
|
|
|
/// </summary>
|
2020-03-25 16:42:30 +08:00
|
|
|
|
public Action<LCIMConversation, string, string, string> OnMemberInfoUpdated;
|
2020-03-24 17:42:04 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前用户收到消息
|
|
|
|
|
/// </summary>
|
2020-03-25 16:42:30 +08:00
|
|
|
|
public Action<LCIMConversation, LCIMMessage> OnMessage {
|
2020-03-18 16:21:29 +08:00
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 17:42:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 消息被撤回
|
|
|
|
|
/// </summary>
|
2020-03-25 16:42:30 +08:00
|
|
|
|
public Action<LCIMConversation, LCIMMessage> OnMessageRecalled {
|
2020-03-24 17:42:04 +08:00
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 消息被修改
|
|
|
|
|
/// </summary>
|
2020-03-25 16:42:30 +08:00
|
|
|
|
public Action<LCIMConversation, LCIMMessage> OnMessageUpdated {
|
2020-03-24 17:42:04 +08:00
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 未读消息数目更新
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action<List<LCIMConversation>> OnUnreadMessagesCountUpdated {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 16:42:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Action OnLastDeliveredAtUpdated {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Action OnLastReadAtUpdated {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2020-03-23 16:21:32 +08:00
|
|
|
|
internal ILCIMSignatureFactory SignatureFactory {
|
|
|
|
|
get; private set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 16:42:30 +08:00
|
|
|
|
internal LCWebSocketConnection Connection {
|
|
|
|
|
get; set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal LCIMSessionController SessionController {
|
|
|
|
|
get; private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal LCIMMessageController MessageController {
|
|
|
|
|
get; private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal LCIMUnreadController UnreadController {
|
|
|
|
|
get; private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal LCIMGoAwayController GoAwayController {
|
|
|
|
|
get; private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal LCIMConversationController ConversationController {
|
|
|
|
|
get; private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public LCIMClient(string clientId,
|
|
|
|
|
ILCIMSignatureFactory signatureFactory = null) {
|
|
|
|
|
Id = clientId;
|
2020-03-23 16:21:32 +08:00
|
|
|
|
SignatureFactory = signatureFactory;
|
2020-03-25 16:42:30 +08:00
|
|
|
|
ConversationDict = new Dictionary<string, LCIMConversation>();
|
|
|
|
|
|
|
|
|
|
SessionController = new LCIMSessionController(this);
|
|
|
|
|
ConversationController = new LCIMConversationController(this);
|
|
|
|
|
MessageController = new LCIMMessageController(this);
|
|
|
|
|
UnreadController = new LCIMUnreadController(this);
|
|
|
|
|
GoAwayController = new LCIMGoAwayController(this);
|
|
|
|
|
|
|
|
|
|
Connection = new LCWebSocketConnection(Id) {
|
|
|
|
|
OnNotification = OnNotification
|
|
|
|
|
};
|
2020-03-12 16:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 连接
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2020-03-12 16:23:21 +08:00
|
|
|
|
public async Task Open() {
|
2020-03-25 16:42:30 +08:00
|
|
|
|
await Connection.Connect();
|
|
|
|
|
// 打开 Session
|
|
|
|
|
await SessionController.Open();
|
2020-03-12 16:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 关闭
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task Close() {
|
2020-03-25 16:42:30 +08:00
|
|
|
|
// 关闭 session
|
|
|
|
|
await SessionController.Close();
|
|
|
|
|
await Connection.Close();
|
2020-03-12 16:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 16:42:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 创建普通对话
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="members"></param>
|
|
|
|
|
/// <param name="name"></param>
|
|
|
|
|
/// <param name="unique"></param>
|
|
|
|
|
/// <param name="properties"></param>
|
|
|
|
|
/// <returns></returns>
|
2020-03-12 16:23:21 +08:00
|
|
|
|
public async Task<LCIMConversation> CreateConversation(
|
|
|
|
|
IEnumerable<string> members,
|
|
|
|
|
string name = null,
|
|
|
|
|
bool unique = true,
|
|
|
|
|
Dictionary<string, object> properties = null) {
|
2020-03-25 16:42:30 +08:00
|
|
|
|
return await ConversationController.CreateConv(members: members,
|
|
|
|
|
name: name,
|
|
|
|
|
unique: unique,
|
|
|
|
|
properties: properties);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 创建聊天室
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name"></param>
|
|
|
|
|
/// <param name="properties"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<LCIMChatRoom> CreateChatRoom(
|
|
|
|
|
string name,
|
|
|
|
|
Dictionary<string, object> properties = null) {
|
|
|
|
|
LCIMChatRoom chatRoom = await ConversationController.CreateConv(name: name,
|
|
|
|
|
transient: true,
|
|
|
|
|
properties: properties) as LCIMChatRoom;
|
|
|
|
|
return chatRoom;
|
2020-03-12 16:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 16:42:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 创建临时对话
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="members"></param>
|
|
|
|
|
/// <param name="ttl"></param>
|
|
|
|
|
/// <param name="properties"></param>
|
|
|
|
|
/// <returns></returns>
|
2020-03-12 16:23:21 +08:00
|
|
|
|
public async Task<LCIMTemporaryConversation> CreateTemporaryConversation(
|
|
|
|
|
IEnumerable<string> members,
|
|
|
|
|
int ttl = 86400,
|
|
|
|
|
Dictionary<string, object> properties = null) {
|
2020-03-25 16:42:30 +08:00
|
|
|
|
LCIMTemporaryConversation tempConversation = await ConversationController.CreateConv(members: members,
|
|
|
|
|
temporary: true,
|
|
|
|
|
temporaryTtl: ttl,
|
|
|
|
|
properties: properties) as LCIMTemporaryConversation;
|
2020-03-12 16:23:21 +08:00
|
|
|
|
return tempConversation;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// <summary>
|
2020-03-26 16:08:35 +08:00
|
|
|
|
/// 根据 id 获取对话
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id"></param>
|
|
|
|
|
/// <returns></returns>
|
2020-03-12 16:23:21 +08:00
|
|
|
|
public async Task<LCIMConversation> GetConversation(string id) {
|
2020-03-17 11:41:38 +08:00
|
|
|
|
if (string.IsNullOrEmpty(id)) {
|
|
|
|
|
throw new ArgumentNullException(nameof(id));
|
|
|
|
|
}
|
2020-03-26 16:08:35 +08:00
|
|
|
|
if (LCIMConversation.IsTemporayConversation(id)) {
|
|
|
|
|
List<LCIMTemporaryConversation> temporaryConversationList = await ConversationController.GetTemporaryConversations(new string[] { id });
|
|
|
|
|
if (temporaryConversationList == null || temporaryConversationList.Count < 1) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return temporaryConversationList[0];
|
|
|
|
|
}
|
2020-03-24 17:42:04 +08:00
|
|
|
|
LCIMConversationQuery query = GetQuery()
|
|
|
|
|
.WhereEqualTo("objectId", id)
|
2020-03-17 11:41:38 +08:00
|
|
|
|
.Limit(1);
|
2020-03-26 16:08:35 +08:00
|
|
|
|
List<LCIMConversation> results = await ConversationController.Find(query);
|
2020-03-17 11:41:38 +08:00
|
|
|
|
if (results == null || results.Count < 1) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return results[0];
|
2020-03-12 16:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取某些特定的对话
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="ids"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<List<LCIMConversation>> GetConversationList(IEnumerable<string> ids) {
|
|
|
|
|
if (ids == null || ids.Count() == 0) {
|
|
|
|
|
throw new ArgumentNullException(nameof(ids));
|
|
|
|
|
}
|
2020-03-26 16:08:35 +08:00
|
|
|
|
// 区分临时对话
|
|
|
|
|
IEnumerable<string> tempConvIds = ids.Where(item => {
|
|
|
|
|
return LCIMConversation.IsTemporayConversation(item);
|
|
|
|
|
});
|
|
|
|
|
IEnumerable<string> convIds = ids.Where(item => {
|
|
|
|
|
return !tempConvIds.Contains(item);
|
|
|
|
|
});
|
|
|
|
|
List<LCIMTemporaryConversation> temporaryConversations = await ConversationController.GetTemporaryConversations(tempConvIds);
|
|
|
|
|
LCIMConversationQuery query = GetQuery()
|
|
|
|
|
.WhereContainedIn("objectId", convIds)
|
|
|
|
|
.Limit(999);
|
|
|
|
|
List<LCIMConversation> conversations = await ConversationController.Find(query);
|
|
|
|
|
conversations.AddRange(temporaryConversations);
|
|
|
|
|
return conversations;
|
2020-03-12 16:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 11:41:38 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取对话查询对象
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public LCIMConversationQuery GetQuery() {
|
|
|
|
|
return new LCIMConversationQuery(this);
|
2020-03-12 16:23:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 17:42:04 +08:00
|
|
|
|
private async Task OnNotification(GenericCommand notification) {
|
2020-03-12 16:23:21 +08:00
|
|
|
|
switch (notification.Cmd) {
|
2020-03-24 17:42:04 +08:00
|
|
|
|
case CommandType.Session:
|
2020-03-25 16:42:30 +08:00
|
|
|
|
await SessionController.OnNotification(notification);
|
2020-03-24 17:42:04 +08:00
|
|
|
|
break;
|
2020-03-12 16:23:21 +08:00
|
|
|
|
case CommandType.Conv:
|
2020-03-25 16:42:30 +08:00
|
|
|
|
await ConversationController.OnNotification(notification);
|
2020-03-12 16:23:21 +08:00
|
|
|
|
break;
|
2020-03-18 16:21:29 +08:00
|
|
|
|
case CommandType.Direct:
|
2020-03-25 16:42:30 +08:00
|
|
|
|
await MessageController.OnNotification(notification);
|
2020-03-24 17:42:04 +08:00
|
|
|
|
break;
|
|
|
|
|
case CommandType.Unread:
|
2020-03-25 16:42:30 +08:00
|
|
|
|
await UnreadController.OnNotification(notification);
|
2020-03-12 16:23:21 +08:00
|
|
|
|
break;
|
2020-03-25 16:42:30 +08:00
|
|
|
|
case CommandType.Goaway:
|
|
|
|
|
await GoAwayController.OnNotification(notification);
|
2020-03-24 17:42:04 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal async Task<LCIMConversation> GetOrQueryConversation(string convId) {
|
2020-03-25 16:42:30 +08:00
|
|
|
|
if (ConversationDict.TryGetValue(convId, out LCIMConversation conversation)) {
|
2020-03-24 17:42:04 +08:00
|
|
|
|
return conversation;
|
2020-03-16 11:50:49 +08:00
|
|
|
|
}
|
2020-03-24 17:42:04 +08:00
|
|
|
|
conversation = await GetConversation(convId);
|
2020-03-16 11:50:49 +08:00
|
|
|
|
return conversation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal GenericCommand NewCommand(CommandType cmd, OpType op) {
|
2020-03-25 16:42:30 +08:00
|
|
|
|
GenericCommand command = NewCommand(cmd);
|
|
|
|
|
command.Op = op;
|
|
|
|
|
return command;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal GenericCommand NewCommand(CommandType cmd) {
|
2020-03-12 16:23:21 +08:00
|
|
|
|
return new GenericCommand {
|
|
|
|
|
Cmd = cmd,
|
|
|
|
|
AppId = LCApplication.AppId,
|
2020-03-25 16:42:30 +08:00
|
|
|
|
PeerId = Id,
|
2020-03-16 11:50:49 +08:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal GenericCommand NewDirectCommand() {
|
|
|
|
|
return new GenericCommand {
|
|
|
|
|
Cmd = CommandType.Direct,
|
|
|
|
|
AppId = LCApplication.AppId,
|
2020-03-25 16:42:30 +08:00
|
|
|
|
PeerId = Id,
|
2020-03-12 16:23:21 +08:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|