using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Linq; using System.Collections.ObjectModel; using LeanCloud.Common; using LeanCloud.Realtime.Protocol; using LeanCloud.Realtime.Internal.Controller; using LeanCloud.Realtime.Internal.Connection; namespace LeanCloud.Realtime { /// /// 通信客户端 /// public class LCIMClient { internal Dictionary ConversationDict; public string Id { get; private set; } #region 事件 /// /// 当前用户被加入某个对话的黑名单 /// public Action OnBlocked { get; set; } /// /// 当用户被解除黑名单 /// public Action OnUnblocked { get; set; } /// /// 当前用户在某个对话中被禁言 /// public Action OnMuted; /// /// 当前用户在某个对话中被解除禁言 /// public Action OnUnmuted; /// /// 客户端连接断开 /// public Action OnPaused { get; set; } /// /// 客户端连接恢复正常 /// public Action OnResume { get; set; } /// /// 当前客户端被服务端强行下线 /// public Action OnClose { get; set; } /// /// 客户端连接断开 /// public Action OnDisconnect { get; set; } /// /// 客户端正在重连 /// public Action OnReconnecting { get; set; } /// /// 客户端重连成功 /// public Action OnReconnected { get; set; } /// /// 客户端重连失败,连接成功,登录失败 /// public Action OnReconnectError { get; set; } /// /// 用户在其他客户端登录,当前客户端被服务端强行下线 /// public Action OnConflict { get; set; } /// /// 该对话信息被更新 /// public Action, string> OnConversationInfoUpdated; /// /// 当前用户被添加至某个对话 /// public Action OnInvited { get; set; } /// /// 当前用户被从某个对话中移除 /// public Action OnKicked { get; set; } /// /// 有用户被添加至某个对话 /// public Action, string> OnMembersJoined { get; set; } /// /// 有成员被从某个对话中移除 /// public Action, string> OnMembersLeft { get; set; } /// /// 有成员被加入某个对话的黑名单 /// public Action, string> OnMembersBlocked { get; set; } /// /// 有成员被移出某个对话的黑名单 /// public Action, string> OnMembersUnblocked { get; set; } /// /// 有成员在某个对话中被禁言 /// public Action, string> OnMembersMuted { get; set; } /// /// 有成员被移出某个对话的黑名单 /// public Action, string> OnMembersUnmuted { get; set; } /// /// 有成员的对话信息被更新 /// public Action OnMemberInfoUpdated; /// /// 当前用户收到消息 /// public Action OnMessage { get; set; } /// /// 消息被撤回 /// public Action OnMessageRecalled { get; set; } /// /// 消息被修改 /// public Action OnMessageUpdated { get; set; } /// /// 消息已送达 /// public Action OnMessageDelivered { get; set; } /// /// 消息已读 /// public Action OnMessageRead { get; set; } /// /// 未读消息数目更新 /// public Action> OnUnreadMessagesCountUpdated { get; set; } /// /// /// public Action OnLastDeliveredAtUpdated { get; set; } public Action OnLastReadAtUpdated { get; set; } #endregion internal ILCIMSignatureFactory SignatureFactory { get; private set; } internal LCConnection 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; } internal LCIMRcpController RcpController { get; private set; } #region 接口 public LCIMClient(string clientId, ILCIMSignatureFactory signatureFactory = null) { Id = clientId; SignatureFactory = signatureFactory; ConversationDict = new Dictionary(); SessionController = new LCIMSessionController(this); ConversationController = new LCIMConversationController(this); MessageController = new LCIMMessageController(this); UnreadController = new LCIMUnreadController(this); GoAwayController = new LCIMGoAwayController(this); RcpController = new LCIMRcpController(this); Connection = new LCConnection(Id) { OnNotification = OnConnectionNotification, OnDisconnect = OnConnectionDisconnect, OnReconnected = OnConnectionReconnect }; } /// /// 连接 /// /// public async Task Open() { await Connection.Connect(); // 打开 Session await SessionController.Open(); } /// /// 关闭 /// /// public async Task Close() { // 关闭 session await SessionController.Close(); await Connection.Close(); } /// /// 创建普通对话 /// /// /// /// /// /// public async Task CreateConversation( IEnumerable members, string name = null, bool unique = true, Dictionary properties = null) { return await ConversationController.CreateConv(members: members, name: name, unique: unique, properties: properties); } /// /// 创建聊天室 /// /// /// /// public async Task CreateChatRoom( string name, Dictionary properties = null) { LCIMChatRoom chatRoom = await ConversationController.CreateConv(name: name, transient: true, properties: properties) as LCIMChatRoom; return chatRoom; } /// /// 创建临时对话 /// /// /// /// /// public async Task CreateTemporaryConversation( IEnumerable members, int ttl = 86400, Dictionary properties = null) { LCIMTemporaryConversation tempConversation = await ConversationController.CreateConv(members: members, temporary: true, temporaryTtl: ttl, properties: properties) as LCIMTemporaryConversation; return tempConversation; } /// /// 根据 id 获取对话 /// /// /// public async Task GetConversation(string id) { if (string.IsNullOrEmpty(id)) { throw new ArgumentNullException(nameof(id)); } if (LCIMConversation.IsTemporayConversation(id)) { List temporaryConversationList = await ConversationController.GetTemporaryConversations(new string[] { id }); if (temporaryConversationList == null || temporaryConversationList.Count < 1) { return null; } return temporaryConversationList[0]; } LCIMConversationQuery query = GetQuery() .WhereEqualTo("objectId", id) .Limit(1); ReadOnlyCollection results = await ConversationController.Find(query); if (results == null || results.Count < 1) { return null; } return results[0]; } /// /// 获取某些特定的对话 /// /// /// public async Task> GetConversationList(IEnumerable ids) { if (ids == null || ids.Count() == 0) { throw new ArgumentNullException(nameof(ids)); } // 区分临时对话 IEnumerable tempConvIds = ids.Where(item => { return LCIMConversation.IsTemporayConversation(item); }); IEnumerable convIds = ids.Where(item => { return !tempConvIds.Contains(item); }); List conversationList = new List(); if (tempConvIds.Count() > 0) { List temporaryConversations = await ConversationController.GetTemporaryConversations(tempConvIds); conversationList.AddRange(temporaryConversations); } if (convIds.Count() > 0) { LCIMConversationQuery query = GetQuery() .WhereContainedIn("objectId", convIds) .Limit(convIds.Count()); ReadOnlyCollection conversations = await ConversationController.Find(query); conversationList.AddRange(conversations); } return conversationList.AsReadOnly(); } /// /// 获取对话查询对象 /// /// public LCIMConversationQuery GetQuery() { return new LCIMConversationQuery(this); } #endregion private void OnConnectionNotification(GenericCommand notification) { switch (notification.Cmd) { case CommandType.Session: _ = SessionController.OnNotification(notification); break; case CommandType.Conv: _ = ConversationController.OnNotification(notification); break; case CommandType.Direct: _ = MessageController.OnNotification(notification); break; case CommandType.Unread: _ = UnreadController.OnNotification(notification); break; case CommandType.Goaway: _ = GoAwayController.OnNotification(notification); break; case CommandType.Rcp: _ = RcpController.OnNotification(notification); break; default: break; } } private void OnConnectionDisconnect() { OnDisconnect?.Invoke(); } private void OnConnectionReconnect() { _ = HandleReconnected(); } private async Task HandleReconnected() { try { // 打开 Session await SessionController.Open(); // 回调用户 OnReconnected?.Invoke(); } catch (Exception e) { LCLogger.Error(e.Message); await Connection.Close(); OnReconnectError?.Invoke(); } } internal async Task GetOrQueryConversation(string convId) { if (ConversationDict.TryGetValue(convId, out LCIMConversation conversation)) { return conversation; } conversation = await GetConversation(convId); return conversation; } internal GenericCommand NewCommand(CommandType cmd, OpType op) { GenericCommand command = NewCommand(cmd); command.Op = op; return command; } internal GenericCommand NewCommand(CommandType cmd) { return new GenericCommand { Cmd = cmd, AppId = LCApplication.AppId, PeerId = Id, }; } internal GenericCommand NewDirectCommand() { return new GenericCommand { Cmd = CommandType.Direct, AppId = LCApplication.AppId, PeerId = Id, }; } } }