Merge pull request #92 from onerain88/chore
完善开发指南中的接口
commit
d263de14b7
|
@ -3,6 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<ReleaseVersion>0.4.2</ReleaseVersion>
|
<ReleaseVersion>0.4.2</ReleaseVersion>
|
||||||
|
<AssemblyName>Common</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
<ReleaseVersion>0.4.2</ReleaseVersion>
|
<ReleaseVersion>0.4.2</ReleaseVersion>
|
||||||
|
<AssemblyName>LiveQuery</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<ReleaseVersion>0.4.2</ReleaseVersion>
|
<ReleaseVersion>0.4.2</ReleaseVersion>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
<AssemblyName>Realtime</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -10,15 +10,22 @@ using static NUnit.Framework.TestContext;
|
||||||
|
|
||||||
namespace Realtime.Test {
|
namespace Realtime.Test {
|
||||||
public class Client {
|
public class Client {
|
||||||
|
private const string USERNAME1 = "username1";
|
||||||
|
private const string PASSWORD1 = "password1";
|
||||||
|
|
||||||
|
private const string USERNAME2 = "username2";
|
||||||
|
private const string PASSWORD2 = "password2";
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() {
|
public async Task SetUp() {
|
||||||
LCLogger.LogDelegate += Utils.Print;
|
Utils.SetUp();
|
||||||
LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com");
|
await NewUser(USERNAME1, PASSWORD1);
|
||||||
|
await NewUser(USERNAME2, PASSWORD2);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TearDown]
|
[TearDown]
|
||||||
public void TearDown() {
|
public void TearDown() {
|
||||||
LCLogger.LogDelegate -= Utils.Print;
|
Utils.TearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -34,12 +41,12 @@ namespace Realtime.Test {
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task OpenAndCloseByLCUser() {
|
public async Task OpenAndCloseByLCUser() {
|
||||||
LCUser user = await LCUser.Login("hello", "world");
|
LCUser user = await LCUser.Login(USERNAME1, PASSWORD1);
|
||||||
LCIMClient client = new LCIMClient(user);
|
LCIMClient client = new LCIMClient(user);
|
||||||
await client.Open();
|
await client.Open();
|
||||||
|
|
||||||
|
|
||||||
LCUser game = await LCUser.Login("game", "play");
|
LCUser game = await LCUser.Login(USERNAME2, PASSWORD2);
|
||||||
LCIMClient client2 = new LCIMClient(game);
|
LCIMClient client2 = new LCIMClient(game);
|
||||||
await client2.Open();
|
await client2.Open();
|
||||||
|
|
||||||
|
@ -134,5 +141,21 @@ namespace Realtime.Test {
|
||||||
|
|
||||||
await tcs.Task;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,7 @@ namespace Realtime.Test {
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public async Task SetUp() {
|
public async Task SetUp() {
|
||||||
LCLogger.LogDelegate += Utils.Print;
|
Utils.SetUp();
|
||||||
LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com");
|
|
||||||
c1 = new LCIMClient(Guid.NewGuid().ToString());
|
c1 = new LCIMClient(Guid.NewGuid().ToString());
|
||||||
await c1.Open();
|
await c1.Open();
|
||||||
c2 = new LCIMClient(Guid.NewGuid().ToString());
|
c2 = new LCIMClient(Guid.NewGuid().ToString());
|
||||||
|
@ -32,7 +31,7 @@ namespace Realtime.Test {
|
||||||
await c1.Close();
|
await c1.Close();
|
||||||
await c2.Close();
|
await c2.Close();
|
||||||
await lean.Close();
|
await lean.Close();
|
||||||
LCLogger.LogDelegate -= Utils.Print;
|
Utils.TearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LeanCloud;
|
|
||||||
using LeanCloud.Common;
|
|
||||||
using LeanCloud.Realtime;
|
using LeanCloud.Realtime;
|
||||||
|
|
||||||
namespace Realtime.Test {
|
namespace Realtime.Test {
|
||||||
public class ConversationQuery {
|
public class ConversationQuery {
|
||||||
private string clientId = "hello123";
|
private readonly string clientId = "m1";
|
||||||
private LCIMClient client;
|
private LCIMClient client;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public async Task SetUp() {
|
public async Task SetUp() {
|
||||||
LCLogger.LogDelegate += Utils.Print;
|
Utils.SetUp();
|
||||||
LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com");
|
|
||||||
client = new LCIMClient(clientId);
|
client = new LCIMClient(clientId);
|
||||||
await client.Open();
|
await client.Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TearDown]
|
[TearDown]
|
||||||
public async Task TearDown() {
|
public async Task TearDown() {
|
||||||
LCLogger.LogDelegate -= Utils.Print;
|
|
||||||
await client.Close();
|
await client.Close();
|
||||||
|
Utils.TearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -36,7 +33,7 @@ namespace Realtime.Test {
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task QueryMemberConversation() {
|
public async Task QueryMemberConversation() {
|
||||||
string memberId = "cc1";
|
string memberId = "m1";
|
||||||
LCIMConversationQuery query = new LCIMConversationQuery(client);
|
LCIMConversationQuery query = new LCIMConversationQuery(client);
|
||||||
query.WhereEqualTo("m", memberId);
|
query.WhereEqualTo("m", memberId);
|
||||||
ReadOnlyCollection<LCIMConversation> conversations = await query.Find();
|
ReadOnlyCollection<LCIMConversation> conversations = await query.Find();
|
||||||
|
@ -45,5 +42,34 @@ namespace Realtime.Test {
|
||||||
Assert.True(conversation.MemberIds.Contains(memberId));
|
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<LCIMConversation> 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<LCIMConversation> 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,7 @@ namespace Realtime.Test {
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public async Task SetUp() {
|
public async Task SetUp() {
|
||||||
LCLogger.LogDelegate += Utils.Print;
|
Utils.SetUp();
|
||||||
LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com");
|
|
||||||
m1 = new LCIMClient("m1");
|
m1 = new LCIMClient("m1");
|
||||||
m2 = new LCIMClient("m2");
|
m2 = new LCIMClient("m2");
|
||||||
await m1.Open();
|
await m1.Open();
|
||||||
|
@ -45,7 +44,7 @@ namespace Realtime.Test {
|
||||||
public async Task TearDown() {
|
public async Task TearDown() {
|
||||||
await m1.Close();
|
await m1.Close();
|
||||||
await m2.Close();
|
await m2.Close();
|
||||||
LCLogger.LogDelegate -= Utils.Print;
|
Utils.TearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -76,17 +75,19 @@ namespace Realtime.Test {
|
||||||
Assert.NotNull(textMessage.Id);
|
Assert.NotNull(textMessage.Id);
|
||||||
|
|
||||||
LCFile image = new LCFile("hello", "../../../../../assets/hello.png");
|
LCFile image = new LCFile("hello", "../../../../../assets/hello.png");
|
||||||
await image.Save();
|
|
||||||
LCIMImageMessage imageMessage = new LCIMImageMessage(image);
|
LCIMImageMessage imageMessage = new LCIMImageMessage(image);
|
||||||
await conversation.Send(imageMessage);
|
await conversation.Send(imageMessage);
|
||||||
Assert.NotNull(imageMessage.Id);
|
Assert.NotNull(imageMessage.Id);
|
||||||
|
|
||||||
LCFile file = new LCFile("apk", "../../../../../assets/test.apk");
|
LCFile file = new LCFile("apk", "../../../../../assets/test.apk");
|
||||||
await file.Save();
|
|
||||||
LCIMFileMessage fileMessage = new LCIMFileMessage(file);
|
LCIMFileMessage fileMessage = new LCIMFileMessage(file);
|
||||||
await conversation.Send(fileMessage);
|
await conversation.Send(fileMessage);
|
||||||
Assert.NotNull(fileMessage.Id);
|
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;
|
await tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +153,7 @@ namespace Realtime.Test {
|
||||||
[Test]
|
[Test]
|
||||||
[Order(4)]
|
[Order(4)]
|
||||||
public async Task Query() {
|
public async Task Query() {
|
||||||
ReadOnlyCollection<LCIMMessage> messages = await conversation.QueryMessages();
|
ReadOnlyCollection<LCIMMessage> messages = await conversation.QueryMessages(messageType: -6);
|
||||||
Assert.Greater(messages.Count, 0);
|
Assert.Greater(messages.Count, 0);
|
||||||
foreach (LCIMMessage message in messages) {
|
foreach (LCIMMessage message in messages) {
|
||||||
Assert.AreEqual(message.ConversationId, conversation.Id);
|
Assert.AreEqual(message.ConversationId, conversation.Id);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LeanCloud;
|
|
||||||
using LeanCloud.Realtime;
|
using LeanCloud.Realtime;
|
||||||
using LeanCloud.Realtime.Internal.Protocol;
|
using LeanCloud.Realtime.Internal.Protocol;
|
||||||
|
|
||||||
|
@ -14,8 +13,7 @@ namespace Realtime.Test {
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public async Task SetUp() {
|
public async Task SetUp() {
|
||||||
LCLogger.LogDelegate += Utils.Print;
|
Utils.SetUp();
|
||||||
LCApplication.Initialize("ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz", "NUKmuRbdAhg1vrb2wexYo1jo", "https://ikggdre2.lc-cn-n1-shared.com");
|
|
||||||
c1 = new LCIMClient(Guid.NewGuid().ToString());
|
c1 = new LCIMClient(Guid.NewGuid().ToString());
|
||||||
c2 = new LCIMClient(Guid.NewGuid().ToString());
|
c2 = new LCIMClient(Guid.NewGuid().ToString());
|
||||||
await c1.Open();
|
await c1.Open();
|
||||||
|
@ -28,7 +26,7 @@ namespace Realtime.Test {
|
||||||
public async Task TearDown() {
|
public async Task TearDown() {
|
||||||
await c1.Close();
|
await c1.Close();
|
||||||
await c2.Close();
|
await c2.Close();
|
||||||
LCLogger.LogDelegate -= Utils.Print;
|
Utils.TearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
using LeanCloud;
|
using LeanCloud;
|
||||||
using LeanCloud.Common;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace Realtime.Test {
|
namespace Realtime.Test {
|
||||||
public static class Utils {
|
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) {
|
internal static void Print(LCLogLevel level, string info) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case LCLogLevel.Debug:
|
case LCLogLevel.Debug:
|
||||||
|
|
|
@ -28,5 +28,9 @@ namespace LeanCloud.Realtime {
|
||||||
public override Task<LCIMPartiallySuccessResult> AddMembers(IEnumerable<string> clientIds) {
|
public override Task<LCIMPartiallySuccessResult> AddMembers(IEnumerable<string> clientIds) {
|
||||||
throw new Exception("Add members is not allowed in chat room.");
|
throw new Exception("Add members is not allowed in chat room.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Task Read() {
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using LeanCloud.Storage;
|
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -180,9 +179,8 @@ namespace LeanCloud.Realtime {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mark the last message of this conversation as read.
|
/// Mark the last message of this conversation as read.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task Read() {
|
public virtual async Task Read() {
|
||||||
if (LastMessage == null) {
|
if (LastMessage == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -260,10 +258,13 @@ namespace LeanCloud.Realtime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a message in this conversation.
|
/// Sends a message in this conversation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message to send.</param>
|
/// <param name="message">The message to send.</param>
|
||||||
|
/// <param name="options">The options of sending message.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<LCIMMessage> Send(LCIMMessage message,
|
public async Task<LCIMMessage> Send(LCIMMessage message,
|
||||||
LCIMMessageSendOptions options = null) {
|
LCIMMessageSendOptions options = null) {
|
||||||
|
@ -273,6 +274,7 @@ namespace LeanCloud.Realtime {
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
options = LCIMMessageSendOptions.Default;
|
options = LCIMMessageSendOptions.Default;
|
||||||
}
|
}
|
||||||
|
await message.PrepareSend();
|
||||||
await Client.MessageController.Send(Id, message, options);
|
await Client.MessageController.Send(Id, message, options);
|
||||||
LastMessage = message;
|
LastMessage = message;
|
||||||
return message;
|
return message;
|
||||||
|
@ -450,7 +452,7 @@ namespace LeanCloud.Realtime {
|
||||||
/// <param name="start">Start message ID.</param>
|
/// <param name="start">Start message ID.</param>
|
||||||
/// <param name="end">End message ID.</param>
|
/// <param name="end">End message ID.</param>
|
||||||
/// <param name="direction">Query direction (defaults to NewToOld).</param>
|
/// <param name="direction">Query direction (defaults to NewToOld).</param>
|
||||||
/// <param name="limit">Limits the number of returned results. Its default value is 20.</param>
|
/// <param name="limit">Limits the number of returned results. Its default value is 100.</param>
|
||||||
/// <param name="messageType">The message type to query. The default value is 0 (text message).</param>
|
/// <param name="messageType">The message type to query. The default value is 0 (text message).</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<ReadOnlyCollection<LCIMMessage>> QueryMessages(LCIMMessageQueryEndpoint start = null,
|
public async Task<ReadOnlyCollection<LCIMMessage>> QueryMessages(LCIMMessageQueryEndpoint start = null,
|
||||||
|
@ -469,6 +471,17 @@ namespace LeanCloud.Realtime {
|
||||||
await Client.ConversationController.FetchReciptTimestamp(Id);
|
await Client.ConversationController.FetchReciptTimestamp(Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetch conversation from server.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<LCIMConversation> Fetch() {
|
||||||
|
LCIMConversationQuery query = new LCIMConversationQuery(Client);
|
||||||
|
query.WhereEqualTo("objectId", Id);
|
||||||
|
await query.Find();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
internal static bool IsTemporayConversation(string convId) {
|
internal static bool IsTemporayConversation(string convId) {
|
||||||
return convId.StartsWith("_tmp:");
|
return convId.StartsWith("_tmp:");
|
||||||
}
|
}
|
||||||
|
@ -503,9 +516,28 @@ namespace LeanCloud.Realtime {
|
||||||
IEnumerable<string> ids = (muo as IList<object>).Cast<string>();
|
IEnumerable<string> ids = (muo as IList<object>).Cast<string>();
|
||||||
mutedIds = new HashSet<string>(ids);
|
mutedIds = new HashSet<string>(ids);
|
||||||
}
|
}
|
||||||
//if (conv.TryGetValue("lm", out object lmo)) {
|
if (conv.TryGetValue("msg", out object msgo)) {
|
||||||
// LastMessageAt = (DateTime)LCDecoder.Decode(lmo);
|
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<string, object> attr) {
|
internal void MergeInfo(Dictionary<string, object> attr) {
|
||||||
|
|
|
@ -2,15 +2,35 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using LeanCloud.Storage.Internal.Query;
|
using LeanCloud.Storage.Internal.Query;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
public class LCIMConversationQuery {
|
public class LCIMConversationQuery {
|
||||||
|
internal const int CompactFlag = 0x1;
|
||||||
|
internal const int WithLastMessageFlag = 0x2;
|
||||||
|
|
||||||
internal LCCompositionalCondition Condition {
|
internal LCCompositionalCondition Condition {
|
||||||
get; private set;
|
get; private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly LCIMClient client;
|
private readonly LCIMClient client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore the members of conversation.
|
||||||
|
/// </summary>
|
||||||
|
public bool Compact {
|
||||||
|
get; set;
|
||||||
|
} = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// With the last message.
|
||||||
|
/// </summary>
|
||||||
|
public bool WithLastMessageRefreshed {
|
||||||
|
get; set;
|
||||||
|
} = false;
|
||||||
|
|
||||||
public LCIMConversationQuery(LCIMClient client) {
|
public LCIMConversationQuery(LCIMClient client) {
|
||||||
Condition = new LCCompositionalCondition();
|
Condition = new LCCompositionalCondition();
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
@ -250,10 +270,6 @@ namespace LeanCloud.Realtime {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool WithLastMessageRefreshed {
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a list of LCObjects matching this query.
|
/// Retrieves a list of LCObjects matching this query.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -261,5 +277,28 @@ namespace LeanCloud.Realtime {
|
||||||
public async Task<ReadOnlyCollection<LCIMConversation>> Find() {
|
public async Task<ReadOnlyCollection<LCIMConversation>> Find() {
|
||||||
return await client.ConversationController.Find(this);
|
return await client.ConversationController.Find(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the first conversation from the query.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<LCIMConversation> First() {
|
||||||
|
Limit(1);
|
||||||
|
ReadOnlyCollection<LCIMConversation> conversations = await Find();
|
||||||
|
return conversations?.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the conversation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="convId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<LCIMConversation> Get(string convId) {
|
||||||
|
if (string.IsNullOrEmpty(convId)) {
|
||||||
|
throw new ArgumentNullException(nameof(convId));
|
||||||
|
}
|
||||||
|
WhereEqualTo("objectId", convId);
|
||||||
|
return First();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,6 +355,22 @@ namespace LeanCloud.Realtime.Internal.Controller {
|
||||||
LCLogger.Error(e);
|
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;
|
command.ConvMessage = convMessage;
|
||||||
GenericCommand response = await Connection.SendRequest(command);
|
GenericCommand response = await Connection.SendRequest(command);
|
||||||
JsonObjectMessage results = response.ConvMessage.Results;
|
JsonObjectMessage results = response.ConvMessage.Results;
|
||||||
|
|
|
@ -234,15 +234,15 @@ namespace LeanCloud.Realtime.Internal.Controller {
|
||||||
message.MentionIdList.Contains(Client.Id);
|
message.MentionIdList.Contains(Client.Id);
|
||||||
message.PatchedTimestamp = direct.PatchTimestamp;
|
message.PatchedTimestamp = direct.PatchTimestamp;
|
||||||
message.IsTransient = direct.Transient;
|
message.IsTransient = direct.Transient;
|
||||||
// 通知服务端已接收
|
|
||||||
if (!message.IsTransient) {
|
|
||||||
// 只有非暂态消息才需要发送 ack
|
|
||||||
_ = Ack(message.ConversationId, message.Id);
|
|
||||||
}
|
|
||||||
// 获取对话
|
// 获取对话
|
||||||
LCIMConversation conversation = await Client.GetOrQueryConversation(direct.Cid);
|
LCIMConversation conversation = await Client.GetOrQueryConversation(direct.Cid);
|
||||||
conversation.Unread++;
|
conversation.Unread++;
|
||||||
conversation.LastMessage = message;
|
conversation.LastMessage = message;
|
||||||
|
// 通知服务端已接收
|
||||||
|
if (!(conversation is LCIMChatRoom) && !message.IsTransient) {
|
||||||
|
// 只有非暂态消息才需要发送 ack
|
||||||
|
_ = Ack(message.ConversationId, message.Id);
|
||||||
|
}
|
||||||
Client.OnMessage?.Invoke(conversation, message);
|
Client.OnMessage?.Invoke(conversation, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,8 +285,16 @@ namespace LeanCloud.Realtime.Internal.Controller {
|
||||||
LCIMConversation conversation = await Client.GetOrQueryConversation(convId);
|
LCIMConversation conversation = await Client.GetOrQueryConversation(convId);
|
||||||
if (isRead) {
|
if (isRead) {
|
||||||
Client.OnMessageRead?.Invoke(conversation, msgId);
|
Client.OnMessageRead?.Invoke(conversation, msgId);
|
||||||
|
if (timestamp > conversation.LastReadTimestamp) {
|
||||||
|
conversation.LastReadTimestamp = timestamp;
|
||||||
|
Client.OnLastReadAtUpdated?.Invoke(conversation);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Client.OnMessageDelivered?.Invoke(conversation, msgId);
|
Client.OnMessageDelivered?.Invoke(conversation, msgId);
|
||||||
|
if (timestamp > conversation.LastDeliveredTimestamp) {
|
||||||
|
conversation.LastDeliveredTimestamp = timestamp;
|
||||||
|
Client.OnLastDeliveredAtUpdated?.Invoke(conversation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ namespace LeanCloud.Realtime {
|
||||||
get; private set;
|
get; private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 事件
|
|
||||||
|
|
||||||
#region 连接状态事件
|
#region 连接状态事件
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -206,21 +204,19 @@ namespace LeanCloud.Realtime {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when the last delivered message is updated.
|
/// Occurs when the last delivered message is updated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action OnLastDeliveredAtUpdated {
|
public Action<LCIMConversation> OnLastDeliveredAtUpdated {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when the last delivered message is updated.
|
/// Occurs when the last read message is updated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action OnLastReadAtUpdated {
|
public Action<LCIMConversation> OnLastReadAtUpdated {
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
internal ILCIMSignatureFactory SignatureFactory {
|
internal ILCIMSignatureFactory SignatureFactory {
|
||||||
get; private set;
|
get; private set;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
public class LCIMFileMessage : LCIMTextMessage {
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LeanCloud.Realtime {
|
namespace LeanCloud.Realtime {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -125,5 +126,9 @@ namespace LeanCloud.Realtime {
|
||||||
|
|
||||||
internal LCIMMessage() {
|
internal LCIMMessage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal virtual Task PrepareSend() {
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace LeanCloud.Realtime {
|
||||||
/// The priority for sending messages in chatroom.
|
/// The priority for sending messages in chatroom.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum LCIMMessagePriority {
|
public enum LCIMMessagePriority {
|
||||||
Hight = 1,
|
High = 1,
|
||||||
Normal = 2,
|
Normal = 2,
|
||||||
Low = 3
|
Low = 3
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<ReleaseVersion>0.4.2</ReleaseVersion>
|
<ReleaseVersion>0.4.2</ReleaseVersion>
|
||||||
|
<AssemblyName>Storage</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -206,7 +206,7 @@ namespace LeanCloud.Storage.Internal.Http {
|
||||||
}
|
}
|
||||||
// 当前用户 Session Token
|
// 当前用户 Session Token
|
||||||
LCUser currentUser = await LCUser.GetCurrent();
|
LCUser currentUser = await LCUser.GetCurrent();
|
||||||
if (currentUser != null) {
|
if (!headers.Contains("X-LC-Session") && currentUser != null) {
|
||||||
headers.Add("X-LC-Session", currentUser.SessionToken);
|
headers.Add("X-LC-Session", currentUser.SessionToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,14 +212,17 @@ namespace LeanCloud.Storage.Internal.Query {
|
||||||
if (conditionList != null && conditionList.Count > 0) {
|
if (conditionList != null && conditionList.Count > 0) {
|
||||||
dict["where"] = JsonConvert.SerializeObject(Encode());
|
dict["where"] = JsonConvert.SerializeObject(Encode());
|
||||||
}
|
}
|
||||||
if (orderByList != null && orderByList.Count > 0) {
|
string order = BuildOrders();
|
||||||
dict["order"] = string.Join(",", orderByList);
|
if (!string.IsNullOrEmpty(order)) {
|
||||||
|
dict["order"] = order;
|
||||||
}
|
}
|
||||||
if (includes != null && includes.Count > 0) {
|
string includes = BuildIncludes();
|
||||||
dict["include"] = string.Join(",", includes);
|
if (!string.IsNullOrEmpty(includes)) {
|
||||||
|
dict["include"] = includes;
|
||||||
}
|
}
|
||||||
if (selectedKeys != null && selectedKeys.Count > 0) {
|
string keys = BuildKeys();
|
||||||
dict["keys"] = string.Join(",", selectedKeys);
|
if (!string.IsNullOrEmpty(keys)) {
|
||||||
|
dict["keys"] = keys;
|
||||||
}
|
}
|
||||||
if (IncludeACL) {
|
if (IncludeACL) {
|
||||||
dict["returnACL"] = "true";
|
dict["returnACL"] = "true";
|
||||||
|
@ -233,5 +236,26 @@ namespace LeanCloud.Storage.Internal.Query {
|
||||||
}
|
}
|
||||||
return JsonConvert.SerializeObject(Encode());
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace LeanCloud {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LCApplication {
|
public class LCApplication {
|
||||||
// SDK 版本号,用于 User-Agent 统计
|
// SDK 版本号,用于 User-Agent 统计
|
||||||
internal const string SDKVersion = "0.4.6";
|
internal const string SDKVersion = "0.5.0";
|
||||||
|
|
||||||
// 接口版本号,用于接口版本管理
|
// 接口版本号,用于接口版本管理
|
||||||
internal const string APIVersion = "1.1";
|
internal const string APIVersion = "1.1";
|
||||||
|
|
|
@ -346,20 +346,12 @@ namespace LeanCloud.Storage {
|
||||||
return (int)ret["count"];
|
return (int)ret["count"];
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<T> Get(string objectId) {
|
public Task<T> Get(string objectId) {
|
||||||
if (string.IsNullOrEmpty(objectId)) {
|
if (string.IsNullOrEmpty(objectId)) {
|
||||||
throw new ArgumentNullException(nameof(objectId));
|
throw new ArgumentNullException(nameof(objectId));
|
||||||
}
|
}
|
||||||
WhereEqualTo("objectId", objectId);
|
WhereEqualTo("objectId", objectId);
|
||||||
Limit(1);
|
return First();
|
||||||
ReadOnlyCollection<T> results = await Find();
|
|
||||||
if (results != null) {
|
|
||||||
if (results.Count == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return results[0];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ReadOnlyCollection<T>> Find() {
|
public async Task<ReadOnlyCollection<T>> Find() {
|
||||||
|
|
|
@ -430,7 +430,7 @@ namespace LeanCloud.Storage {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="email"></param>
|
/// <param name="email"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task RequestPasswordRestBySmsCode(string mobile) {
|
public static async Task RequestPasswordResetBySmsCode(string mobile) {
|
||||||
if (string.IsNullOrEmpty(mobile)) {
|
if (string.IsNullOrEmpty(mobile)) {
|
||||||
throw new ArgumentNullException(nameof(mobile));
|
throw new ArgumentNullException(nameof(mobile));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue