diff --git a/Realtime/Conversation/LCIMConversation.cs b/Realtime/Conversation/LCIMConversation.cs index d34fce3..3d4aaad 100644 --- a/Realtime/Conversation/LCIMConversation.cs +++ b/Realtime/Conversation/LCIMConversation.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Threading.Tasks; using System.Linq; +using Newtonsoft.Json; using LeanCloud.Realtime.Protocol; +using LeanCloud.Storage.Internal.Codec; namespace LeanCloud.Realtime { public class LCIMConversation { @@ -11,7 +13,11 @@ namespace LeanCloud.Realtime { } public string Name { - get; set; + get { + return this["name"] as string; + } set { + this["name"] = value; + } } public string CreatorId { @@ -30,7 +36,22 @@ namespace LeanCloud.Realtime { get; set; } - public bool IsMute => false; + public DateTime LastMessageAt { + get; internal set; + } + + public object this[string key] { + get { + return customProperties[key]; + } + set { + customProperties[key] = value; + } + } + + public bool IsMute { + get; private set; + } public virtual bool IsSystem => false; @@ -38,39 +59,122 @@ namespace LeanCloud.Realtime { private readonly LCIMClient client; + private Dictionary customProperties; + internal LCIMConversation(LCIMClient client) { this.client = client; + customProperties = new Dictionary(); } - public void Set(string key, object value) { - // 自定义属性 - - } - + /// + /// 获取对话人数,或暂态对话的在线人数 + /// + /// public async Task Count() { - return 0; + ConvCommand conv = new ConvCommand { + Cid = Id, + }; + GenericCommand command = client.NewCommand(CommandType.Conv, OpType.Count); + command.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(command); + return response.ConvMessage.Count; } public async Task Save() { + ConvCommand conv = new ConvCommand { + Cid = Id, + }; + // 注意序列化是否与存储一致 + string json = JsonConvert.SerializeObject(LCEncoder.Encode(customProperties)); + conv.Attr = new JsonObjectMessage { + Data = json + }; + GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Update); + request.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(request); + JsonObjectMessage attr = response.ConvMessage.AttrModified; + // 更新自定义属性 + if (attr != null) { + Dictionary data = JsonConvert.DeserializeObject>(attr.Data); + Dictionary objectData = LCDecoder.Decode(data) as Dictionary; + foreach (KeyValuePair kv in objectData) { + customProperties[kv.Key] = kv.Value; + } + } return this; } - public async Task Add(List clientIdList) { + /// + /// 添加用户到对话 + /// + /// 用户 Id + /// + public async Task Add(IEnumerable clientIds) { + if (clientIds == null || clientIds.Count() == 0) { + throw new ArgumentNullException(nameof(clientIds)); + } + ConvCommand conv = new ConvCommand { + Cid = Id, + }; + conv.M.AddRange(clientIds); + // TODO 签名参数 + GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Add); + request.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(request); + List allowedIds = response.ConvMessage.AllowedPids.ToList(); + List failedIds = response.ConvMessage.FailedPids.ToList(); + // TODO 转化为返回 + + return this; } - public async Task Remove(List removeIdList) { + /// + /// 删除用户 + /// + /// 用户 Id + /// + public async Task Remove(IEnumerable removeIds) { + if (removeIds == null || removeIds.Count() == 0) { + throw new ArgumentNullException(nameof(removeIds)); + } + ConvCommand conv = new ConvCommand { + Cid = Id, + }; + conv.M.AddRange(removeIds); + // TODO 签名参数 + GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Remove); + request.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(request); + List allowedIds = response.ConvMessage.AllowedPids.ToList(); + List failedIds = response.ConvMessage.FailedPids.ToList(); + // TODO 转化为返回 + + return this; } + /// + /// 加入对话 + /// + /// public async Task Join() { - return this; + return await Add(new string[] { client.ClientId }); } + /// + /// 离开对话 + /// + /// public async Task Quit() { - return this; + return await Remove(new string[] { client.ClientId }); } + /// + /// 发送消息 + /// + /// + /// public async Task Send(LCIMMessage message) { DirectCommand direct = new DirectCommand { FromPeerId = client.ClientId, @@ -88,30 +192,108 @@ namespace LeanCloud.Realtime { } public async Task Recall(LCIMMessage message) { + if (message == null) { + throw new ArgumentNullException(nameof(message)); + } + PatchCommand patch = new PatchCommand(); + PatchItem item = new PatchItem { + Cid = Id, + Mid = message.Id, + Recall = true + }; + patch.Patches.Add(item); + GenericCommand request = client.NewCommand(CommandType.Patch, OpType.Modify); + request.PatchMessage = patch; + GenericCommand response = await client.client.SendRequest(request); return null; } + /// + /// 静音 + /// + /// public async Task Mute() { + ConvCommand conv = new ConvCommand { + Cid = Id + }; + GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Mute); + request.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(request); + IsMute = true; return this; } + /// + /// 取消静音 + /// + /// public async Task Unmute() { + ConvCommand conv = new ConvCommand { + Cid = Id + }; + GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Unmute); + request.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(request); + IsMute = false; return this; } - public async Task MuteMemberList(List clientIdList) { + /// + /// 禁言 + /// + /// + /// + public async Task MuteMembers(IEnumerable clientIds) { + if (clientIds == null || clientIds.Count() == 0) { + throw new ArgumentNullException(nameof(clientIds)); + } + ConvCommand conv = new ConvCommand { + Cid = Id + }; + conv.M.AddRange(clientIds); + GenericCommand request = client.NewCommand(CommandType.Conv, OpType.AddShutup); + request.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(request); } - public async Task UnmuteMemberList(List clientIdList) { - + /// + /// 取消禁言 + /// + /// + /// + public async Task UnmuteMembers(IEnumerable clientIds) { + if (clientIds == null || clientIds.Count() == 0) { + throw new ArgumentNullException(nameof(clientIds)); + } + ConvCommand conv = new ConvCommand { + Cid = Id + }; + conv.M.AddRange(clientIds); + GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Remove); + request.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(request); } - public async Task BlockMemberList(List clientIdList) { - + /// + /// 将用户加入黑名单 + /// + /// + /// + public async Task BlockMembers(IEnumerable clientIds) { + if (clientIds == null || clientIds.Count() == 0) { + throw new ArgumentNullException(nameof(clientIds)); + } + BlacklistCommand blacklist = new BlacklistCommand { + SrcCid = Id, + + }; + GenericCommand request = client.NewCommand(CommandType.Blacklist, OpType.Block); + request.BlacklistMessage = blacklist; + await client.client.SendRequest(request); } - public async Task UnblockMemberList(List clientIdList) { + public async Task UnblockMembers(IEnumerable clientIds) { } @@ -124,6 +306,10 @@ namespace LeanCloud.Realtime { } public async Task GetMemberInfo(string memberId) { + if (string.IsNullOrEmpty(memberId)) { + throw new ArgumentNullException(nameof(memberId)); + } + return null; } diff --git a/Realtime/Conversation/LCIMConversationQuery.cs b/Realtime/Conversation/LCIMConversationQuery.cs index fa966c0..cff39a0 100644 --- a/Realtime/Conversation/LCIMConversationQuery.cs +++ b/Realtime/Conversation/LCIMConversationQuery.cs @@ -1,7 +1,256 @@ using System; +using System.Threading.Tasks; +using System.Collections; +using System.Collections.Generic; +using LeanCloud.Storage.Internal.Query; +using LeanCloud.Realtime.Protocol; + namespace LeanCloud.Realtime { public class LCIMConversationQuery { - public LCIMConversationQuery() { + private LCCompositionalCondition condition; + + private LCIMClient client; + + public LCIMConversationQuery(LCIMClient client) { + condition = new LCCompositionalCondition(); + this.client = client; + } + + /// + /// 等于 + /// + /// + /// + /// + public LCIMConversationQuery WhereEqualTo(string key, object value) { + condition.WhereEqualTo(key, value); + return this; + } + + /// + /// 不等于 + /// + /// + /// + /// + public LCIMConversationQuery WhereNotEqualTo(string key, object value) { + condition.WhereNotEqualTo(key, value); + return this; + } + + /// + /// 包含 + /// + /// + /// + /// + public LCIMConversationQuery WhereContainedIn(string key, IEnumerable values) { + condition.WhereContainedIn(key, values); + return this; + } + + /// + /// 包含全部 + /// + /// + /// + /// + public LCIMConversationQuery WhereContainsAll(string key, IEnumerable values) { + condition.WhereContainsAll(key, values); + return this; + } + + /// + /// 存在 + /// + /// + /// + public LCIMConversationQuery WhereExists(string key) { + condition.WhereExists(key); + return this; + } + + /// + /// 不存在 + /// + /// + /// + public LCIMConversationQuery WhereDoesNotExist(string key) { + condition.WhereDoesNotExist(key); + return this; + } + + /// + /// 长度等于 + /// + /// + /// + /// + public LCIMConversationQuery WhereSizeEqualTo(string key, int size) { + condition.WhereSizeEqualTo(key, size); + return this; + } + + /// + /// 大于 + /// + /// + /// + /// + public LCIMConversationQuery WhereGreaterThan(string key, object value) { + condition.WhereGreaterThan(key, value); + return this; + } + + /// + /// 大于等于 + /// + /// + /// + /// + public LCIMConversationQuery WhereGreaterThanOrEqualTo(string key, object value) { + condition.WhereGreaterThanOrEqualTo(key, value); + return this; + } + + /// + /// 小于 + /// + /// + /// + /// + public LCIMConversationQuery WhereLessThan(string key, object value) { + condition.WhereLessThan(key, value); + return this; + } + + /// + /// 小于等于 + /// + /// + /// + /// + public LCIMConversationQuery WhereLessThanOrEqualTo(string key, object value) { + condition.WhereLessThanOrEqualTo(key, value); + return this; + } + + /// + /// 前缀 + /// + /// + /// + /// + public LCIMConversationQuery WhereStartsWith(string key, string prefix) { + condition.WhereStartsWith(key, prefix); + return this; + } + + /// + /// 后缀 + /// + /// + /// + /// + public LCIMConversationQuery WhereEndsWith(string key, string suffix) { + condition.WhereEndsWith(key, suffix); + return this; + } + + /// + /// 字符串包含 + /// + /// + /// + /// + public LCIMConversationQuery WhereContains(string key, string subString) { + condition.WhereContains(key, subString); + return this; + } + + /// + /// 按 key 升序 + /// + /// + /// + public LCIMConversationQuery OrderBy(string key) { + condition.OrderBy(key); + return this; + } + + /// + /// 按 key 降序 + /// + /// + /// + public LCIMConversationQuery OrderByDescending(string key) { + condition.OrderByDescending(key); + return this; + } + + /// + /// 拉取 key 的完整对象 + /// + /// + /// + public LCIMConversationQuery Include(string key) { + condition.Include(key); + return this; + } + + /// + /// 包含 key + /// + /// + /// + public LCIMConversationQuery Select(string key) { + condition.Select(key); + return this; + } + + /// + /// 跳过 + /// + /// + /// + public LCIMConversationQuery Skip(int value) { + condition.Skip = value; + return this; + } + + /// + /// 限制数量 + /// + /// + /// + public LCIMConversationQuery Limit(int value) { + condition.Limit = value; + return this; + } + + public bool WithLastMessageRefreshed { + get; set; + } + + public async Task> Find() { + GenericCommand command = new GenericCommand { + Cmd = CommandType.Conv, + Op = OpType.Query, + AppId = LCApplication.AppId, + PeerId = client.ClientId, + }; + ConvCommand conv = new ConvCommand(); + string where = condition.BuildWhere(); + if (!string.IsNullOrEmpty(where)) { + conv.Where = JsonObjectMessage.Parser.ParseJson(where); + } + command.ConvMessage = conv; + GenericCommand response = await client.client.SendRequest(command); + JsonObjectMessage results = response.ConvMessage.Results; + List convList = null; + // TODO 反序列化 + + return convList; } } } diff --git a/Realtime/Conversation/LCIMTemporaryConversation.cs b/Realtime/Conversation/LCIMTemporaryConversation.cs index b4e26b3..3fc19c3 100644 --- a/Realtime/Conversation/LCIMTemporaryConversation.cs +++ b/Realtime/Conversation/LCIMTemporaryConversation.cs @@ -2,6 +2,16 @@ namespace LeanCloud.Realtime { public class LCIMTemporaryConversation : LCIMConversation { + public DateTime ExpiredAt { + get; + } + + public bool IsExpired { + get { + return DateTime.Now > ExpiredAt; + } + } + public LCIMTemporaryConversation(LCIMClient client) : base(client) { } } diff --git a/Realtime/LCIMClient.cs b/Realtime/LCIMClient.cs index 92caeb0..1bbaf35 100644 --- a/Realtime/LCIMClient.cs +++ b/Realtime/LCIMClient.cs @@ -24,24 +24,24 @@ namespace LeanCloud.Realtime { get; set; } - /// - /// 当前客户端被服务端强行下线 - /// - public Action OnClosed { - get; set; - } - /// /// 客户端连接断开 /// - public Action OnDisconnected { + public Action OnPaused { get; set; } /// /// 客户端连接恢复正常 /// - public Action OnReconnect { + public Action OnResume { + get; set; + } + + /// + /// 当前客户端被服务端强行下线 + /// + public Action OnOffline { get; set; } @@ -75,6 +75,10 @@ namespace LeanCloud.Realtime { conversationDict = new Dictionary(); } + /// + /// 连接 + /// + /// public async Task Open() { client = new LCWebSocketClient { OnNotification = OnNotification @@ -86,6 +90,14 @@ namespace LeanCloud.Realtime { await client.SendRequest(command); } + /// + /// 关闭 + /// + /// + public async Task Close() { + await client.Close(); + } + public async Task CreateChatRoom( string name, Dictionary properties = null) { @@ -143,16 +155,48 @@ namespace LeanCloud.Realtime { return conversation; } + /// + /// 获取某个特定的对话 + /// + /// + /// public async Task GetConversation(string id) { - return null; + if (string.IsNullOrEmpty(id)) { + throw new ArgumentNullException(nameof(id)); + } + LCIMConversationQuery query = GetQuery(); + query.WhereEqualTo("objectId", id) + .Limit(1); + List results = await query.Find(); + if (results == null || results.Count < 1) { + return null; + } + return results[0]; } - public async Task> GetConversationList(List idList) { - return null; + /// + /// 获取某些特定的对话 + /// + /// + /// + public async Task> GetConversationList(IEnumerable ids) { + if (ids == null || ids.Count() == 0) { + throw new ArgumentNullException(nameof(ids)); + } + List conversationList = new List(); + foreach (string id in ids) { + LCIMConversation conversation = await GetConversation(id); + conversationList.Add(conversation); + } + return conversationList; } - public async Task GetConversationQuery() { - return null; + /// + /// 获取对话查询对象 + /// + /// + public LCIMConversationQuery GetQuery() { + return new LCIMConversationQuery(this); } private void OnNotification(GenericCommand notification) { @@ -166,12 +210,22 @@ namespace LeanCloud.Realtime { } private void OnConversationNotification(GenericCommand notification) { + ConvCommand conv = notification.ConvMessage; switch (notification.Op) { case OpType.Joined: - OnConversationJoined(notification.ConvMessage); + OnConversationJoined(conv); break; case OpType.MembersJoined: - OnConversationMembersJoined(notification.ConvMessage); + OnConversationMembersJoined(conv); + break; + case OpType.Left: + OnConversationLeft(conv); + break; + case OpType.MembersLeft: + OnConversationMemberLeft(conv); + break; + case OpType.Updated: + OnPropertiesUpdated(conv); break; default: break; @@ -190,6 +244,26 @@ namespace LeanCloud.Realtime { OnMembersJoined?.Invoke(conversation, conv.M.ToList(), conv.InitBy); } + private void OnConversationLeft(ConvCommand conv) { + if (conversationDict.TryGetValue(conv.Cid, out LCIMConversation conversation)) { + OnKicked?.Invoke(conversation, conv.InitBy); + } + } + + private void OnConversationMemberLeft(ConvCommand conv) { + if (conversationDict.TryGetValue(conv.Cid, out LCIMConversation conversation)) { + List leftIdList = conv.M.ToList(); + OnMembersLeft?.Invoke(conversation, leftIdList, conv.InitBy); + } + } + + private void OnPropertiesUpdated(ConvCommand conv) { + if (conversationDict.TryGetValue(conv.Cid, out LCIMConversation conversation)) { + // TODO + + } + } + private LCIMConversation GetOrCreateConversation(string convId) { if (!conversationDict.TryGetValue(convId, out LCIMConversation conversation)) { conversation = new LCIMConversation(this); diff --git a/Storage/Internal/Codec/LCDecoder.cs b/Storage/Internal/Codec/LCDecoder.cs index 06d0a50..b5acfa2 100644 --- a/Storage/Internal/Codec/LCDecoder.cs +++ b/Storage/Internal/Codec/LCDecoder.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using LeanCloud.Storage.Internal.Object; namespace LeanCloud.Storage.Internal.Codec { - internal static class LCDecoder { - internal static object Decode(object obj) { + public static class LCDecoder { + public static object Decode(object obj) { if (obj is IDictionary dict) { if (dict.Contains("__type")) { string type = dict["__type"].ToString(); diff --git a/Storage/Internal/Codec/LCEncoder.cs b/Storage/Internal/Codec/LCEncoder.cs index efe49c1..5af75bf 100644 --- a/Storage/Internal/Codec/LCEncoder.cs +++ b/Storage/Internal/Codec/LCEncoder.cs @@ -5,8 +5,8 @@ using LeanCloud.Storage.Internal.Operation; using LeanCloud.Storage.Internal.Query; namespace LeanCloud.Storage.Internal.Codec { - internal static class LCEncoder { - internal static object Encode(object obj) { + public static class LCEncoder { + public static object Encode(object obj) { if (obj is DateTime dateTime) { return EncodeDateTime(dateTime); } else if (obj is byte[] bytes) { diff --git a/Storage/Internal/Query/ILCQueryCondition.cs b/Storage/Internal/Query/ILCQueryCondition.cs index 8dcd68d..a08650f 100644 --- a/Storage/Internal/Query/ILCQueryCondition.cs +++ b/Storage/Internal/Query/ILCQueryCondition.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; namespace LeanCloud.Storage.Internal.Query { - internal interface ILCQueryCondition { + public interface ILCQueryCondition { bool Equals(ILCQueryCondition other); Dictionary Encode(); } diff --git a/Storage/Internal/Query/LCCompositionalCondition.cs b/Storage/Internal/Query/LCCompositionalCondition.cs index 917b2bf..74a8039 100644 --- a/Storage/Internal/Query/LCCompositionalCondition.cs +++ b/Storage/Internal/Query/LCCompositionalCondition.cs @@ -4,9 +4,9 @@ using Newtonsoft.Json; using LeanCloud.Storage.Internal.Codec; namespace LeanCloud.Storage.Internal.Query { - internal class LCCompositionalCondition : ILCQueryCondition { - internal const string And = "$and"; - internal const string Or = "$or"; + public class LCCompositionalCondition : ILCQueryCondition { + public const string And = "$and"; + public const string Or = "$or"; readonly string composition; @@ -16,93 +16,93 @@ namespace LeanCloud.Storage.Internal.Query { HashSet includes; HashSet selectedKeys; - internal int Skip { + public int Skip { get; set; } - internal int Limit { + public int Limit { get; set; } - internal LCCompositionalCondition(string composition = And) { + public LCCompositionalCondition(string composition = And) { this.composition = composition; Skip = 0; Limit = 30; } // 查询条件 - internal void WhereEqualTo(string key, object value) { + public void WhereEqualTo(string key, object value) { Add(new LCEqualCondition(key, value)); } - internal void WhereNotEqualTo(string key, object value) { + public void WhereNotEqualTo(string key, object value) { AddOperation(key, "$ne", value); } - internal void WhereContainedIn(string key, IEnumerable values) { + public void WhereContainedIn(string key, IEnumerable values) { AddOperation(key, "$in", values); } - internal void WhereNotContainedIn(string key, IEnumerable values) { + public void WhereNotContainedIn(string key, IEnumerable values) { AddOperation(key, "nin", values); } - internal void WhereContainsAll(string key, IEnumerable values) { + public void WhereContainsAll(string key, IEnumerable values) { AddOperation(key, "$all", values); } - internal void WhereExists(string key) { + public void WhereExists(string key) { AddOperation(key, "$exists", true); } - internal void WhereDoesNotExist(string key) { + public void WhereDoesNotExist(string key) { AddOperation(key, "$exists", false); } - internal void WhereSizeEqualTo(string key, int size) { + public void WhereSizeEqualTo(string key, int size) { AddOperation(key, "$size", size); } - internal void WhereGreaterThan(string key, object value) { + public void WhereGreaterThan(string key, object value) { AddOperation(key, "$gt", value); } - internal void WhereGreaterThanOrEqualTo(string key, object value) { + public void WhereGreaterThanOrEqualTo(string key, object value) { AddOperation(key, "$gte", value); } - internal void WhereLessThan(string key, object value) { + public void WhereLessThan(string key, object value) { AddOperation(key, "$lt", value); } - internal void WhereLessThanOrEqualTo(string key, object value) { + public void WhereLessThanOrEqualTo(string key, object value) { AddOperation(key, "$lte", value); } - internal void WhereNear(string key, LCGeoPoint point) { + public void WhereNear(string key, LCGeoPoint point) { AddOperation(key, "$nearSphere", point); } - internal void WhereWithinGeoBox(string key, LCGeoPoint southwest, LCGeoPoint northeast) { + public void WhereWithinGeoBox(string key, LCGeoPoint southwest, LCGeoPoint northeast) { Dictionary value = new Dictionary { { "$box", new List { southwest, northeast } } }; AddOperation(key, "$within", value); } - internal void WhereRelatedTo(LCObject parent, string key) { + public void WhereRelatedTo(LCObject parent, string key) { Add(new LCRelatedCondition(parent, key)); } - internal void WhereStartsWith(string key, string prefix) { + public void WhereStartsWith(string key, string prefix) { AddOperation(key, "$regex", $"^{prefix}.*"); } - internal void WhereEndsWith(string key, string suffix) { + public void WhereEndsWith(string key, string suffix) { AddOperation(key, "$regex", $".*{suffix}$"); } - internal void WhereContains(string key, string subString) { + public void WhereContains(string key, string subString) { AddOperation(key, "$regex", $".*{subString}.*"); } @@ -111,7 +111,7 @@ namespace LeanCloud.Storage.Internal.Query { Add(cond); } - internal void Add(ILCQueryCondition cond) { + public void Add(ILCQueryCondition cond) { if (cond == null) { return; } @@ -123,25 +123,25 @@ namespace LeanCloud.Storage.Internal.Query { } // 筛选条件 - internal void OrderBy(string key) { + public void OrderBy(string key) { if (orderByList == null) { orderByList = new List(); } orderByList.Add(key); } - internal void OrderByDescending(string key) { + public void OrderByDescending(string key) { OrderBy($"-{key}"); } - internal void Include(string key) { + public void Include(string key) { if (includes == null) { includes = new HashSet(); } includes.Add(key); } - internal void Select(string key) { + public void Select(string key) { if (selectedKeys == null) { selectedKeys = new HashSet(); } @@ -165,7 +165,7 @@ namespace LeanCloud.Storage.Internal.Query { }; } - internal Dictionary BuildParams() { + public Dictionary BuildParams() { Dictionary dict = new Dictionary { { "skip", Skip }, { "limit", Limit } @@ -185,7 +185,7 @@ namespace LeanCloud.Storage.Internal.Query { return dict; } - internal string BuildWhere() { + public string BuildWhere() { if (conditionList == null || conditionList.Count == 0) { return null; } diff --git a/Storage/Internal/Query/LCEqualCondition.cs b/Storage/Internal/Query/LCEqualCondition.cs index 57dab0d..cefe9a4 100644 --- a/Storage/Internal/Query/LCEqualCondition.cs +++ b/Storage/Internal/Query/LCEqualCondition.cs @@ -2,11 +2,11 @@ using LeanCloud.Storage.Internal.Codec; namespace LeanCloud.Storage.Internal.Query { - internal class LCEqualCondition : ILCQueryCondition { + public class LCEqualCondition : ILCQueryCondition { readonly string key; readonly object value; - internal LCEqualCondition(string key, object value) { + public LCEqualCondition(string key, object value) { this.key = key; this.value = value; } diff --git a/Storage/Internal/Query/LCOperationCondition.cs b/Storage/Internal/Query/LCOperationCondition.cs index 79d5763..1a38c8b 100644 --- a/Storage/Internal/Query/LCOperationCondition.cs +++ b/Storage/Internal/Query/LCOperationCondition.cs @@ -2,12 +2,12 @@ using LeanCloud.Storage.Internal.Codec; namespace LeanCloud.Storage.Internal.Query { - internal class LCOperationCondition : ILCQueryCondition { + public class LCOperationCondition : ILCQueryCondition { readonly string key; readonly string op; readonly object value; - internal LCOperationCondition(string key, string op, object value) { + public LCOperationCondition(string key, string op, object value) { this.key = key; this.op = op; this.value = value; diff --git a/Storage/Internal/Query/LCRelatedCondition.cs b/Storage/Internal/Query/LCRelatedCondition.cs index 6e2d2b1..3dd92d7 100644 --- a/Storage/Internal/Query/LCRelatedCondition.cs +++ b/Storage/Internal/Query/LCRelatedCondition.cs @@ -2,11 +2,11 @@ using LeanCloud.Storage.Internal.Codec; namespace LeanCloud.Storage.Internal.Query { - internal class LCRelatedCondition : ILCQueryCondition { + public class LCRelatedCondition : ILCQueryCondition { readonly LCObject parent; readonly string key; - internal LCRelatedCondition(LCObject parent, string key) { + public LCRelatedCondition(LCObject parent, string key) { this.parent = parent; this.key = key; } diff --git a/Test/Realtime.Test/Conversation.cs b/Test/Realtime.Test/Conversation.cs index f747d58..c3e61eb 100644 --- a/Test/Realtime.Test/Conversation.cs +++ b/Test/Realtime.Test/Conversation.cs @@ -91,5 +91,34 @@ namespace Realtime.Test { await tcs.Task; } + + [Test] + public async Task Query() { + LCIMClient client = new LCIMClient("hello123"); + await client.Open(); + + LCIMConversationQuery query = new LCIMConversationQuery(client); + await query.Find(); + } + + [Test] + public async Task Save() { + string clientId = Guid.NewGuid().ToString(); + LCIMClient client = new LCIMClient(clientId); + + await client.Open(); + + string otherId = Guid.NewGuid().ToString(); + LCIMConversation conversation = await client.CreateConversation(new List { otherId }); + + conversation.Name = "leancloud"; + conversation["k1"] = "v1"; + conversation["k2"] = "v2"; + await conversation.Save(); + + Assert.AreEqual(conversation.Name, "leancloud"); + Assert.AreEqual(conversation["k1"], "v1"); + Assert.AreEqual(conversation["k2"], "v2"); + } } }