using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using System.Collections.ObjectModel;
using LeanCloud.Storage;
using LeanCloud.Realtime.Internal.Protocol;
using LeanCloud.Realtime.Internal.Controller;
namespace LeanCloud.Realtime {
public class LCIMClient {
///
/// Conversation cache
///
internal Dictionary ConversationDict;
///
/// Client Id
///
public string Id {
get; private set;
}
///
/// Client tag
///
public string Tag {
get; private set;
}
public string DeviceId {
get; private set;
}
internal string SessionToken {
get; private set;
}
#region 连接状态事件
///
/// Occurs when the connection is lost.
///
public Action OnPaused {
get; set;
}
///
/// Occurs when the connection is recovered.
///
public Action OnResume {
get; set;
}
///
/// Occurs when the connection is closed and there will be no auto reconnection.
/// Possible causes include there is a single device login conflict or the client has been kicked off by the server.
///
public Action OnClose {
get; set;
}
#endregion
#region 对话事件
///
/// Occurs when the current user is added into the blacklist of a conversation.
///
public Action OnBlocked {
get; set;
}
///
/// Occurs when the current user is removed from the blacklist of a conversation.
///
public Action OnUnblocked {
get; set;
}
///
/// Occurs when the current user is muted in a conversation.
///
public Action OnMuted;
///
/// Occurs when the current user is unmuted in a conversation.
///
public Action OnUnmuted;
///
/// Occurs when the properties of a conversation are updated.
///
public Action, string> OnConversationInfoUpdated;
///
/// Occurs when the current user is invited to a conversation.
///
public Action OnInvited {
get; set;
}
///
/// Occurs when the current user is kicked from a conversation.
///
public Action OnKicked {
get; set;
}
///
/// Occurs when a user joined a conversation.
///
public Action, string> OnMembersJoined {
get; set;
}
///
/// Occurs when a user left a conversation.
///
public Action, string> OnMembersLeft {
get; set;
}
///
/// Occurs when a user is added to the blacklist of a conversation.
///
public Action, string> OnMembersBlocked {
get; set;
}
///
/// Occurs when a user is removed from the blacklist of a conversation.
///
public Action, string> OnMembersUnblocked {
get; set;
}
///
/// Occurs when a user is muted in a conversation.
///
public Action, string> OnMembersMuted {
get; set;
}
///
/// Occurs when a user is unmuted in a conversation.
///
public Action, string> OnMembersUnmuted {
get; set;
}
///
/// Occurs when the properties of someone are updated.
///
public Action OnMemberInfoUpdated;
#endregion
#region 消息事件
///
/// Occurs when a new message is delivered to a conversation the current user is already in.
///
public Action OnMessage {
get; set;
}
///
/// Occurs when a message is recalled.
///
public Action OnMessageRecalled {
get; set;
}
///
/// Occurs when a message is updated.
///
public Action OnMessageUpdated {
get; set;
}
///
/// Occurs when a message is delivered.
///
public Action OnMessageDelivered {
get; set;
}
///
/// Occurs when a message is read.
///
public Action OnMessageRead {
get; set;
}
///
/// Occurs when the number of unreadMessagesCount is updatded.
///
public Action> OnUnreadMessagesCountUpdated {
get; set;
}
///
/// Occurs when the last delivered message is updated.
///
public Action OnLastDeliveredAtUpdated {
get; set;
}
///
/// Occurs when the last read message is updated.
///
public Action OnLastReadAtUpdated {
get; set;
}
#endregion
internal ILCIMSignatureFactory SignatureFactory {
get; private set;
}
internal LCIMSessionController SessionController {
get; private set;
}
internal LCIMMessageController MessageController {
get; private set;
}
internal LCIMConversationController ConversationController {
get; private set;
}
#region 接口
public LCIMClient(string clientId,
string tag = null,
string deviceId = null,
ILCIMSignatureFactory signatureFactory = null) {
if (string.IsNullOrEmpty(clientId)) {
throw new ArgumentNullException(nameof(clientId));
}
SetUpClient(clientId, tag, deviceId, signatureFactory);
}
public LCIMClient(LCUser user,
string tag = null,
string deviceId = null,
ILCIMSignatureFactory signatureFactory = null) {
if (user == null) {
throw new ArgumentNullException(nameof(user));
}
if (string.IsNullOrEmpty(user.ObjectId) ||
string.IsNullOrEmpty(user.SessionToken)) {
throw new ArgumentException("User must be authenticacted.");
}
SetUpClient(user.ObjectId, tag, deviceId, signatureFactory);
SessionToken = user.SessionToken;
}
private void SetUpClient(string clientId,
string tag,
string deviceId,
ILCIMSignatureFactory signatureFactory) {
Id = clientId;
Tag = tag;
DeviceId = deviceId;
SignatureFactory = signatureFactory;
ConversationDict = new Dictionary();
// 模块
SessionController = new LCIMSessionController(this);
ConversationController = new LCIMConversationController(this);
MessageController = new LCIMMessageController(this);
}
///
/// Signing in
///
/// If this is ture (default value), and single device sign-on is enabled, users already logged in on another device with the same tag will be logged out.
///
public async Task Open(bool force = true) {
try {
// 打开 Session
await SessionController.Open(force);
} catch (Exception e) {
LCLogger.Error(e);
// 如果 session 阶段异常,则关闭连接
throw e;
}
}
///
/// Closes the session
///
///
public async Task Close() {
// 关闭 session
await SessionController.Close();
}
///
/// Creates a conversation
///
/// The list of clientIds of participants in this conversation (except the creator)
/// The name of this conversation
/// Whether this conversation is unique;
/// if it is true and an existing conversation contains the same composition of members,
/// the existing conversation will be reused, otherwise a new conversation will be created.
/// Custom attributes of this conversation
///
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);
}
///
/// Creates a chatroom
///
/// The name of this chatroom
/// Custom attributes of this chatroom
///
public async Task CreateChatRoom(
string name,
Dictionary properties = null) {
LCIMChatRoom chatRoom = await ConversationController.CreateConv(name: name,
transient: true,
properties: properties) as LCIMChatRoom;
return chatRoom;
}
///
/// Creates a temporary conversation
///
/// The list of clientIds of participants in this temporary conversation (except the creator)
/// TTL of this temporary conversation
/// Custom attributes of this temporary conversation
///
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;
}
///
/// Queries a conversation based on its id.
///
/// objectId
///
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];
}
///
/// Queries conversations based on their ids.
///
/// objectId list
///
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();
}
///
/// Constructs a conversation query.
///
///
public LCIMConversationQuery GetQuery() {
return new LCIMConversationQuery(this);
}
#endregion
internal void HandleNotification(GenericCommand notification) {
switch (notification.Cmd) {
case CommandType.Session:
SessionController.HandleNotification(notification);
break;
case CommandType.Conv:
case CommandType.Unread:
ConversationController.HandleNotification(notification);
break;
case CommandType.Direct:
case CommandType.Patch:
case CommandType.Rcp:
MessageController.HandleNotification(notification);
break;
default:
break;
}
}
internal void HandleDisconnected() {
OnPaused?.Invoke();
}
internal async void HandleReconnected() {
try {
// 打开 Session
await SessionController.Reopen();
// 回调用户
OnResume?.Invoke();
} catch (LCException e) {
LCLogger.Error(e);
// 重连成功,但 session/open 失败
OnClose?.Invoke(e.Code, e.Message);
}
}
internal async Task GetOrQueryConversation(string convId) {
if (ConversationDict.TryGetValue(convId, out LCIMConversation conversation)) {
return conversation;
}
conversation = await GetConversation(convId);
return conversation;
}
}
}