diff --git a/Common/Common-Unity/Common-Unity.csproj b/Common/Common-Unity/Common-Unity.csproj index 9ab3475..8cc5107 100644 --- a/Common/Common-Unity/Common-Unity.csproj +++ b/Common/Common-Unity/Common-Unity.csproj @@ -3,6 +3,7 @@ netstandard2.0 0.4.2 + Common diff --git a/LiveQuery/LiveQuery-Unity/LiveQuery-Unity.csproj b/LiveQuery/LiveQuery-Unity/LiveQuery-Unity.csproj index b2522ba..e967d73 100644 --- a/LiveQuery/LiveQuery-Unity/LiveQuery-Unity.csproj +++ b/LiveQuery/LiveQuery-Unity/LiveQuery-Unity.csproj @@ -4,6 +4,7 @@ netstandard2.0 true 0.4.2 + LiveQuery diff --git a/Realtime/Realtime-Unity/Realtime-Unity.csproj b/Realtime/Realtime-Unity/Realtime-Unity.csproj index 7e1a4a8..81beca1 100644 --- a/Realtime/Realtime-Unity/Realtime-Unity.csproj +++ b/Realtime/Realtime-Unity/Realtime-Unity.csproj @@ -4,6 +4,7 @@ netstandard2.0 0.4.2 true + Realtime diff --git a/Realtime/Realtime.Test/Client.cs b/Realtime/Realtime.Test/Client.cs index e43a7bf..6ac6774 100644 --- a/Realtime/Realtime.Test/Client.cs +++ b/Realtime/Realtime.Test/Client.cs @@ -10,15 +10,22 @@ using static NUnit.Framework.TestContext; namespace Realtime.Test { public class Client { + private const string USERNAME1 = "username1"; + private const string PASSWORD1 = "password1"; + + private const string USERNAME2 = "username2"; + private const string PASSWORD2 = "password2"; + [SetUp] - public void SetUp() { - LCLogger.LogDelegate += Utils.Print; - LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com"); + public async Task SetUp() { + Utils.SetUp(); + await NewUser(USERNAME1, PASSWORD1); + await NewUser(USERNAME2, PASSWORD2); } [TearDown] public void TearDown() { - LCLogger.LogDelegate -= Utils.Print; + Utils.TearDown(); } [Test] @@ -34,12 +41,12 @@ namespace Realtime.Test { [Test] public async Task OpenAndCloseByLCUser() { - LCUser user = await LCUser.Login("hello", "world"); + LCUser user = await LCUser.Login(USERNAME1, PASSWORD1); LCIMClient client = new LCIMClient(user); await client.Open(); - LCUser game = await LCUser.Login("game", "play"); + LCUser game = await LCUser.Login(USERNAME2, PASSWORD2); LCIMClient client2 = new LCIMClient(game); await client2.Open(); @@ -134,5 +141,21 @@ namespace Realtime.Test { await tcs.Task; } + + private async Task NewUser(string username, string password) { + try { + await LCUser.Login(username, password); + } catch (LCException e) { + if (e.Code == 211) { + LCUser user1 = new LCUser { + Username = username, + Password = password + }; + await user1.SignUp(); + } else { + throw e; + } + } + } } } diff --git a/Realtime/Realtime.Test/Conversation.cs b/Realtime/Realtime.Test/Conversation.cs index 31f34cc..cf4050f 100644 --- a/Realtime/Realtime.Test/Conversation.cs +++ b/Realtime/Realtime.Test/Conversation.cs @@ -16,8 +16,7 @@ namespace Realtime.Test { [SetUp] public async Task SetUp() { - LCLogger.LogDelegate += Utils.Print; - LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com"); + Utils.SetUp(); c1 = new LCIMClient(Guid.NewGuid().ToString()); await c1.Open(); c2 = new LCIMClient(Guid.NewGuid().ToString()); @@ -32,7 +31,7 @@ namespace Realtime.Test { await c1.Close(); await c2.Close(); await lean.Close(); - LCLogger.LogDelegate -= Utils.Print; + Utils.TearDown(); } [Test] diff --git a/Realtime/Realtime.Test/ConversationQuery.cs b/Realtime/Realtime.Test/ConversationQuery.cs index 4741ceb..dfdd125 100644 --- a/Realtime/Realtime.Test/ConversationQuery.cs +++ b/Realtime/Realtime.Test/ConversationQuery.cs @@ -1,27 +1,24 @@ using NUnit.Framework; using System.Collections.ObjectModel; using System.Threading.Tasks; -using LeanCloud; -using LeanCloud.Common; using LeanCloud.Realtime; namespace Realtime.Test { public class ConversationQuery { - private string clientId = "hello123"; + private readonly string clientId = "m1"; private LCIMClient client; [SetUp] public async Task SetUp() { - LCLogger.LogDelegate += Utils.Print; - LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com"); + Utils.SetUp(); client = new LCIMClient(clientId); await client.Open(); } [TearDown] public async Task TearDown() { - LCLogger.LogDelegate -= Utils.Print; await client.Close(); + Utils.TearDown(); } [Test] @@ -36,7 +33,7 @@ namespace Realtime.Test { [Test] public async Task QueryMemberConversation() { - string memberId = "cc1"; + string memberId = "m1"; LCIMConversationQuery query = new LCIMConversationQuery(client); query.WhereEqualTo("m", memberId); ReadOnlyCollection conversations = await query.Find(); @@ -45,5 +42,34 @@ namespace Realtime.Test { Assert.True(conversation.MemberIds.Contains(memberId)); } } + + [Test] + public async Task QueryCompact() { + string memberId = "m1"; + LCIMConversationQuery query = new LCIMConversationQuery(client) + .WhereEqualTo("m", memberId); + query.Compact = true; + ReadOnlyCollection conversations = await query.Find(); + foreach (LCIMConversation conversation in conversations) { + Assert.True(conversation.MemberIds.Count == 0); + await conversation.Fetch(); + Assert.True(conversation.MemberIds.Count > 0); + } + } + + [Test] + public async Task QueryWithLastMessage() { + string memberId = "m1"; + LCIMConversationQuery query = new LCIMConversationQuery(client) + .WhereEqualTo("m", memberId); + query.WithLastMessageRefreshed = true; + ReadOnlyCollection conversations = await query.Find(); + foreach (LCIMConversation conversation in conversations) { + Assert.True(!string.IsNullOrEmpty(conversation.LastMessage.Id)); + if (conversation.LastMessage is LCIMBinaryMessage binaryMessage) { + TestContext.WriteLine(System.Text.Encoding.UTF8.GetString(binaryMessage.Data)); + } + } + } } } diff --git a/Realtime/Realtime.Test/Message.cs b/Realtime/Realtime.Test/Message.cs index fefb78f..5fa81dc 100644 --- a/Realtime/Realtime.Test/Message.cs +++ b/Realtime/Realtime.Test/Message.cs @@ -32,8 +32,7 @@ namespace Realtime.Test { [SetUp] public async Task SetUp() { - LCLogger.LogDelegate += Utils.Print; - LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com"); + Utils.SetUp(); m1 = new LCIMClient("m1"); m2 = new LCIMClient("m2"); await m1.Open(); @@ -45,7 +44,7 @@ namespace Realtime.Test { public async Task TearDown() { await m1.Close(); await m2.Close(); - LCLogger.LogDelegate -= Utils.Print; + Utils.TearDown(); } [Test] @@ -76,17 +75,19 @@ namespace Realtime.Test { Assert.NotNull(textMessage.Id); LCFile image = new LCFile("hello", "../../../../../assets/hello.png"); - await image.Save(); LCIMImageMessage imageMessage = new LCIMImageMessage(image); await conversation.Send(imageMessage); Assert.NotNull(imageMessage.Id); LCFile file = new LCFile("apk", "../../../../../assets/test.apk"); - await file.Save(); LCIMFileMessage fileMessage = new LCIMFileMessage(file); await conversation.Send(fileMessage); Assert.NotNull(fileMessage.Id); + LCIMBinaryMessage binaryMessage = new LCIMBinaryMessage(System.Text.Encoding.UTF8.GetBytes("LeanCloud")); + await conversation.Send(binaryMessage); + Assert.NotNull(binaryMessage.Id); + await tcs.Task; } @@ -152,7 +153,7 @@ namespace Realtime.Test { [Test] [Order(4)] public async Task Query() { - ReadOnlyCollection messages = await conversation.QueryMessages(); + ReadOnlyCollection messages = await conversation.QueryMessages(messageType: -6); Assert.Greater(messages.Count, 0); foreach (LCIMMessage message in messages) { Assert.AreEqual(message.ConversationId, conversation.Id); diff --git a/Realtime/Realtime.Test/Throttle.cs b/Realtime/Realtime.Test/Throttle.cs index b0f5efa..0f6d475 100644 --- a/Realtime/Realtime.Test/Throttle.cs +++ b/Realtime/Realtime.Test/Throttle.cs @@ -1,7 +1,6 @@ using NUnit.Framework; using System; using System.Threading.Tasks; -using LeanCloud; using LeanCloud.Realtime; using LeanCloud.Realtime.Internal.Protocol; @@ -14,8 +13,7 @@ namespace Realtime.Test { [SetUp] public async Task SetUp() { - LCLogger.LogDelegate += Utils.Print; - LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com"); + Utils.SetUp(); c1 = new LCIMClient(Guid.NewGuid().ToString()); c2 = new LCIMClient(Guid.NewGuid().ToString()); await c1.Open(); @@ -28,7 +26,7 @@ namespace Realtime.Test { public async Task TearDown() { await c1.Close(); await c2.Close(); - LCLogger.LogDelegate -= Utils.Print; + Utils.TearDown(); } [Test] diff --git a/Realtime/Realtime.Test/Utils.cs b/Realtime/Realtime.Test/Utils.cs index 70aa219..77e42d4 100644 --- a/Realtime/Realtime.Test/Utils.cs +++ b/Realtime/Realtime.Test/Utils.cs @@ -1,10 +1,18 @@ using System; using LeanCloud; -using LeanCloud.Common; using NUnit.Framework; namespace Realtime.Test { public static class Utils { + internal static void SetUp() { + LCLogger.LogDelegate += Print; + LCApplication.Initialize("3zWMOXuO9iSdnjXM942i6DdI-gzGzoHsz", "bkwiNq4Tj417eUaHlTWS5sPm", "https://3zwmoxuo.lc-cn-n1-shared.com"); + } + + internal static void TearDown() { + LCLogger.LogDelegate -= Print; + } + internal static void Print(LCLogLevel level, string info) { switch (level) { case LCLogLevel.Debug: diff --git a/Realtime/Realtime/Conversation/LCIMChatRoom.cs b/Realtime/Realtime/Conversation/LCIMChatRoom.cs index 6bccd42..5b77f92 100644 --- a/Realtime/Realtime/Conversation/LCIMChatRoom.cs +++ b/Realtime/Realtime/Conversation/LCIMChatRoom.cs @@ -28,5 +28,9 @@ namespace LeanCloud.Realtime { public override Task AddMembers(IEnumerable clientIds) { throw new Exception("Add members is not allowed in chat room."); } + + public override Task Read() { + return Task.CompletedTask; + } } } diff --git a/Realtime/Realtime/Conversation/LCIMConversation.cs b/Realtime/Realtime/Conversation/LCIMConversation.cs index b0a65f4..c2553d5 100644 --- a/Realtime/Realtime/Conversation/LCIMConversation.cs +++ b/Realtime/Realtime/Conversation/LCIMConversation.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Threading.Tasks; using System.Linq; using System.Collections.ObjectModel; -using LeanCloud.Storage; namespace LeanCloud.Realtime { /// @@ -180,9 +179,8 @@ namespace LeanCloud.Realtime { /// /// Mark the last message of this conversation as read. /// - /// /// - public async Task Read() { + public virtual async Task Read() { if (LastMessage == null) { return; } @@ -260,10 +258,13 @@ namespace LeanCloud.Realtime { } } + + /// /// Sends a message in this conversation. /// /// The message to send. + /// The options of sending message. /// public async Task Send(LCIMMessage message, LCIMMessageSendOptions options = null) { @@ -273,6 +274,7 @@ namespace LeanCloud.Realtime { if (options == null) { options = LCIMMessageSendOptions.Default; } + await message.PrepareSend(); await Client.MessageController.Send(Id, message, options); LastMessage = message; return message; @@ -450,7 +452,7 @@ namespace LeanCloud.Realtime { /// Start message ID. /// End message ID. /// Query direction (defaults to NewToOld). - /// Limits the number of returned results. Its default value is 20. + /// Limits the number of returned results. Its default value is 100. /// The message type to query. The default value is 0 (text message). /// public async Task> QueryMessages(LCIMMessageQueryEndpoint start = null, @@ -469,6 +471,17 @@ namespace LeanCloud.Realtime { await Client.ConversationController.FetchReciptTimestamp(Id); } + /// + /// Fetch conversation from server. + /// + /// + public async Task Fetch() { + LCIMConversationQuery query = new LCIMConversationQuery(Client); + query.WhereEqualTo("objectId", Id); + await query.Find(); + return this; + } + internal static bool IsTemporayConversation(string convId) { return convId.StartsWith("_tmp:"); } @@ -503,9 +516,28 @@ namespace LeanCloud.Realtime { IEnumerable ids = (muo as IList).Cast(); mutedIds = new HashSet(ids); } - //if (conv.TryGetValue("lm", out object lmo)) { - // LastMessageAt = (DateTime)LCDecoder.Decode(lmo); - //} + if (conv.TryGetValue("msg", out object msgo)) { + if (conv.TryGetValue("bin", out object bino)) { + string msg = msgo as string; + bool bin = (bool)bino; + if (bin) { + byte[] bytes = Convert.FromBase64String(msg); + LastMessage = LCIMBinaryMessage.Deserialize(bytes); + } else { + LastMessage = LCIMTypedMessage.Deserialize(msg); + } + } + LastMessage.ConversationId = Id; + if (conv.TryGetValue("msg_mid", out object msgId)) { + LastMessage.Id = msgId as string; + } + if (conv.TryGetValue("msg_from", out object msgFrom)) { + LastMessage.FromClientId = msgFrom as string; + } + if (conv.TryGetValue("msg_timestamp", out object timestamp)) { + LastMessage.SentTimestamp = (long)timestamp; + } + } } internal void MergeInfo(Dictionary attr) { diff --git a/Realtime/Realtime/Conversation/LCIMConversationQuery.cs b/Realtime/Realtime/Conversation/LCIMConversationQuery.cs index 372c1f8..e65f193 100644 --- a/Realtime/Realtime/Conversation/LCIMConversationQuery.cs +++ b/Realtime/Realtime/Conversation/LCIMConversationQuery.cs @@ -2,15 +2,35 @@ using System.Collections; using System.Collections.ObjectModel; using LeanCloud.Storage.Internal.Query; +using System.Linq; +using System.Collections.Generic; +using System; namespace LeanCloud.Realtime { public class LCIMConversationQuery { + internal const int CompactFlag = 0x1; + internal const int WithLastMessageFlag = 0x2; + internal LCCompositionalCondition Condition { get; private set; } private readonly LCIMClient client; + /// + /// Ignore the members of conversation. + /// + public bool Compact { + get; set; + } = false; + + /// + /// With the last message. + /// + public bool WithLastMessageRefreshed { + get; set; + } = false; + public LCIMConversationQuery(LCIMClient client) { Condition = new LCCompositionalCondition(); this.client = client; @@ -250,10 +270,6 @@ namespace LeanCloud.Realtime { return this; } - public bool WithLastMessageRefreshed { - get; set; - } - /// /// Retrieves a list of LCObjects matching this query. /// @@ -261,5 +277,28 @@ namespace LeanCloud.Realtime { public async Task> Find() { return await client.ConversationController.Find(this); } + + /// + /// Retrieves the first conversation from the query. + /// + /// + public async Task First() { + Limit(1); + ReadOnlyCollection conversations = await Find(); + return conversations?.First(); + } + + /// + /// Retrieves the conversation. + /// + /// + /// + public Task Get(string convId) { + if (string.IsNullOrEmpty(convId)) { + throw new ArgumentNullException(nameof(convId)); + } + WhereEqualTo("objectId", convId); + return First(); + } } } diff --git a/Realtime/Realtime/Internal/Controller/LCIMConversationController.cs b/Realtime/Realtime/Internal/Controller/LCIMConversationController.cs index 8bb4c35..a343635 100644 --- a/Realtime/Realtime/Internal/Controller/LCIMConversationController.cs +++ b/Realtime/Realtime/Internal/Controller/LCIMConversationController.cs @@ -355,6 +355,22 @@ namespace LeanCloud.Realtime.Internal.Controller { LCLogger.Error(e); } } + int flag = 0; + if (query.Compact) { + flag += LCIMConversationQuery.CompactFlag; + } + if (query.WithLastMessageRefreshed) { + flag += LCIMConversationQuery.WithLastMessageFlag; + } + if (flag > 0) { + convMessage.Flag = flag; + } + convMessage.Skip = query.Condition.Skip; + convMessage.Limit = query.Condition.Limit; + string orders = query.Condition.BuildOrders(); + if (!string.IsNullOrEmpty(orders)) { + convMessage.Sort = orders; + } command.ConvMessage = convMessage; GenericCommand response = await Connection.SendRequest(command); JsonObjectMessage results = response.ConvMessage.Results; diff --git a/Realtime/Realtime/Internal/Controller/LCIMMessageController.cs b/Realtime/Realtime/Internal/Controller/LCIMMessageController.cs index 97a2dcd..fcddb60 100644 --- a/Realtime/Realtime/Internal/Controller/LCIMMessageController.cs +++ b/Realtime/Realtime/Internal/Controller/LCIMMessageController.cs @@ -234,15 +234,15 @@ namespace LeanCloud.Realtime.Internal.Controller { message.MentionIdList.Contains(Client.Id); message.PatchedTimestamp = direct.PatchTimestamp; message.IsTransient = direct.Transient; - // 通知服务端已接收 - if (!message.IsTransient) { - // 只有非暂态消息才需要发送 ack - _ = Ack(message.ConversationId, message.Id); - } // 获取对话 LCIMConversation conversation = await Client.GetOrQueryConversation(direct.Cid); conversation.Unread++; conversation.LastMessage = message; + // 通知服务端已接收 + if (!(conversation is LCIMChatRoom) && !message.IsTransient) { + // 只有非暂态消息才需要发送 ack + _ = Ack(message.ConversationId, message.Id); + } Client.OnMessage?.Invoke(conversation, message); } @@ -285,8 +285,16 @@ namespace LeanCloud.Realtime.Internal.Controller { LCIMConversation conversation = await Client.GetOrQueryConversation(convId); if (isRead) { Client.OnMessageRead?.Invoke(conversation, msgId); + if (timestamp > conversation.LastReadTimestamp) { + conversation.LastReadTimestamp = timestamp; + Client.OnLastReadAtUpdated?.Invoke(conversation); + } } else { Client.OnMessageDelivered?.Invoke(conversation, msgId); + if (timestamp > conversation.LastDeliveredTimestamp) { + conversation.LastDeliveredTimestamp = timestamp; + Client.OnLastDeliveredAtUpdated?.Invoke(conversation); + } } } diff --git a/Realtime/Realtime/LCIMClient.cs b/Realtime/Realtime/LCIMClient.cs index f88f296..a7ef349 100644 --- a/Realtime/Realtime/LCIMClient.cs +++ b/Realtime/Realtime/LCIMClient.cs @@ -37,8 +37,6 @@ namespace LeanCloud.Realtime { get; private set; } - #region 事件 - #region 连接状态事件 /// @@ -206,21 +204,19 @@ namespace LeanCloud.Realtime { /// /// Occurs when the last delivered message is updated. /// - public Action OnLastDeliveredAtUpdated { + public Action OnLastDeliveredAtUpdated { get; set; } /// - /// Occurs when the last delivered message is updated. + /// Occurs when the last read message is updated. /// - public Action OnLastReadAtUpdated { + public Action OnLastReadAtUpdated { get; set; } #endregion - #endregion - internal ILCIMSignatureFactory SignatureFactory { get; private set; } diff --git a/Realtime/Realtime/Message/LCIMFileMessage.cs b/Realtime/Realtime/Message/LCIMFileMessage.cs index 0f9340a..1c8656c 100644 --- a/Realtime/Realtime/Message/LCIMFileMessage.cs +++ b/Realtime/Realtime/Message/LCIMFileMessage.cs @@ -2,6 +2,7 @@ using System.IO; using System.Collections.Generic; using LeanCloud.Storage; +using System.Threading.Tasks; namespace LeanCloud.Realtime { public class LCIMFileMessage : LCIMTextMessage { @@ -125,5 +126,11 @@ namespace LeanCloud.Realtime { } } } + + internal override async Task PrepareSend() { + if (File != null && string.IsNullOrEmpty(File.ObjectId)) { + await File.Save(); + } + } } } diff --git a/Realtime/Realtime/Message/LCIMMessage.cs b/Realtime/Realtime/Message/LCIMMessage.cs index bdf91b0..4652845 100644 --- a/Realtime/Realtime/Message/LCIMMessage.cs +++ b/Realtime/Realtime/Message/LCIMMessage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace LeanCloud.Realtime { /// @@ -125,5 +126,9 @@ namespace LeanCloud.Realtime { internal LCIMMessage() { } + + internal virtual Task PrepareSend() { + return Task.CompletedTask; + } } } diff --git a/Realtime/Realtime/Message/LCIMMessageSendOptions.cs b/Realtime/Realtime/Message/LCIMMessageSendOptions.cs index 194864b..a3f33f3 100644 --- a/Realtime/Realtime/Message/LCIMMessageSendOptions.cs +++ b/Realtime/Realtime/Message/LCIMMessageSendOptions.cs @@ -5,7 +5,7 @@ namespace LeanCloud.Realtime { /// The priority for sending messages in chatroom. /// public enum LCIMMessagePriority { - Hight = 1, + High = 1, Normal = 2, Low = 3 } diff --git a/Storage/Storage-Unity/Storage-Unity.csproj b/Storage/Storage-Unity/Storage-Unity.csproj index 42d8e68..eb1c493 100644 --- a/Storage/Storage-Unity/Storage-Unity.csproj +++ b/Storage/Storage-Unity/Storage-Unity.csproj @@ -3,6 +3,7 @@ netstandard2.0 0.4.2 + Storage diff --git a/Storage/Storage/Internal/Http/LCHttpClient.cs b/Storage/Storage/Internal/Http/LCHttpClient.cs index 5a4bb6a..85b4d1f 100644 --- a/Storage/Storage/Internal/Http/LCHttpClient.cs +++ b/Storage/Storage/Internal/Http/LCHttpClient.cs @@ -206,7 +206,7 @@ namespace LeanCloud.Storage.Internal.Http { } // 当前用户 Session Token LCUser currentUser = await LCUser.GetCurrent(); - if (currentUser != null) { + if (!headers.Contains("X-LC-Session") && currentUser != null) { headers.Add("X-LC-Session", currentUser.SessionToken); } } diff --git a/Storage/Storage/Internal/Query/LCCompositionalCondition.cs b/Storage/Storage/Internal/Query/LCCompositionalCondition.cs index 7217927..3a0ac27 100644 --- a/Storage/Storage/Internal/Query/LCCompositionalCondition.cs +++ b/Storage/Storage/Internal/Query/LCCompositionalCondition.cs @@ -212,14 +212,17 @@ namespace LeanCloud.Storage.Internal.Query { if (conditionList != null && conditionList.Count > 0) { dict["where"] = JsonConvert.SerializeObject(Encode()); } - if (orderByList != null && orderByList.Count > 0) { - dict["order"] = string.Join(",", orderByList); + string order = BuildOrders(); + if (!string.IsNullOrEmpty(order)) { + dict["order"] = order; } - if (includes != null && includes.Count > 0) { - dict["include"] = string.Join(",", includes); + string includes = BuildIncludes(); + if (!string.IsNullOrEmpty(includes)) { + dict["include"] = includes; } - if (selectedKeys != null && selectedKeys.Count > 0) { - dict["keys"] = string.Join(",", selectedKeys); + string keys = BuildKeys(); + if (!string.IsNullOrEmpty(keys)) { + dict["keys"] = keys; } if (IncludeACL) { dict["returnACL"] = "true"; @@ -233,5 +236,26 @@ namespace LeanCloud.Storage.Internal.Query { } return JsonConvert.SerializeObject(Encode()); } + + public string BuildOrders() { + if (orderByList != null && orderByList.Count > 0) { + return string.Join(",", orderByList); + } + return null; + } + + public string BuildIncludes() { + if (includes != null && includes.Count > 0) { + return string.Join(",", includes); + } + return null; + } + + public string BuildKeys() { + if (selectedKeys != null && selectedKeys.Count > 0) { + return string.Join(",", selectedKeys); + } + return null; + } } } diff --git a/Storage/Storage/LCApplication.cs b/Storage/Storage/LCApplication.cs index 846315a..694e7cd 100644 --- a/Storage/Storage/LCApplication.cs +++ b/Storage/Storage/LCApplication.cs @@ -9,7 +9,7 @@ namespace LeanCloud { /// public class LCApplication { // SDK 版本号,用于 User-Agent 统计 - internal const string SDKVersion = "0.4.6"; + internal const string SDKVersion = "0.5.0"; // 接口版本号,用于接口版本管理 internal const string APIVersion = "1.1"; diff --git a/Storage/Storage/LCQuery.cs b/Storage/Storage/LCQuery.cs index 799b354..928bc1e 100644 --- a/Storage/Storage/LCQuery.cs +++ b/Storage/Storage/LCQuery.cs @@ -346,20 +346,12 @@ namespace LeanCloud.Storage { return (int)ret["count"]; } - public async Task Get(string objectId) { + public Task Get(string objectId) { if (string.IsNullOrEmpty(objectId)) { throw new ArgumentNullException(nameof(objectId)); } WhereEqualTo("objectId", objectId); - Limit(1); - ReadOnlyCollection results = await Find(); - if (results != null) { - if (results.Count == 0) { - return null; - } - return results[0]; - } - return null; + return First(); } public async Task> Find() { diff --git a/Storage/Storage/LCUser.cs b/Storage/Storage/LCUser.cs index a8b1f9a..af1aa03 100644 --- a/Storage/Storage/LCUser.cs +++ b/Storage/Storage/LCUser.cs @@ -430,7 +430,7 @@ namespace LeanCloud.Storage { /// /// /// - public static async Task RequestPasswordRestBySmsCode(string mobile) { + public static async Task RequestPasswordResetBySmsCode(string mobile) { if (string.IsNullOrEmpty(mobile)) { throw new ArgumentNullException(nameof(mobile)); }