diff --git a/AppRouter/AppRouter/AppRouter.csproj b/AppRouter/AppRouter/AppRouter.csproj deleted file mode 100644 index 722603d..0000000 --- a/AppRouter/AppRouter/AppRouter.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netstandard2.0 - 0.1.0 - - - - - - - - - - diff --git a/RTM/RTM.PCL/Properties/AssemblyInfo.cs b/RTM/RTM.PCL/Properties/AssemblyInfo.cs deleted file mode 100644 index 669b160..0000000 --- a/RTM/RTM.PCL/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle("RTM.PCL")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("${AuthorCopyright}")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". -// The form "{Major}.{Minor}.*" will automatically update the build and revision, -// and "{Major}.{Minor}.{Build}.*" will update just the revision. - -[assembly: AssemblyVersion("1.0.*")] - -// The following attributes are used to specify the signing key for the assembly, -// if desired. See the Mono documentation for more information about signing. - -//[assembly: AssemblyDelaySign(false)] -//[assembly: AssemblyKeyFile("")] diff --git a/RTM/RTM.PCL/RTM.PCL.csproj b/RTM/RTM.PCL/RTM.PCL.csproj deleted file mode 100644 index a67701e..0000000 --- a/RTM/RTM.PCL/RTM.PCL.csproj +++ /dev/null @@ -1,210 +0,0 @@ - - - - Debug - AnyCPU - {92B2B40E-A3CD-4672-AC84-2E894E1A6CE5} - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - RTM.PCL - RTM.PCL - v4.5 - Profile111 - 0.1.0 - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - - - true - bin\Release - prompt - 4 - - - - - Internal\AVIMCorePlugins.cs - - - Internal\IAVIMPlatformHooks.cs - - - Internal\Command\AVIMCommand.cs - - - Internal\Command\AVIMCommandRunner.cs - - - Internal\Command\AckCommand.cs - - - Internal\Command\ConversationCommand.cs - - - Internal\Command\IAVIMCommandRunner.cs - - - Internal\Command\MessageCommand.cs - - - Internal\Command\PatchCommand.cs - - - Internal\Command\ReadCommand.cs - - - Internal\Command\SessionCommand.cs - - - Internal\DataEngine\Controller\DateTimeEngine.cs - - - Internal\DataEngine\Controller\DictionaryEngine.cs - - - Internal\DataEngine\Controller\StringEngine.cs - - - Internal\Message\Subclassing\FreeStyleMessageClassInfo.cs - - - Internal\Message\Subclassing\FreeStyleMessageClassingController.cs - - - Internal\Message\Subclassing\IFreeStyleMessageClassingController.cs - - - Internal\Protocol\AVIMProtocol.cs - - - Internal\Router\AVRouterController.cs - - - Internal\Router\IAVRouterController.cs - - - Internal\Router\State\RouterState.cs - - - Internal\Timer\IAVTimer.cs - - - Internal\Timer\Portable\AVTimer.Portable.cs - - - Internal\WebSocket\IWebSocketClient.cs - - - Internal\WebSocket\Portable\DefaultWebSocketClient.Portable.cs - - - Public\AVIMAudioMessage.cs - - - Public\AVIMBinaryMessage.cs - - - Public\AVIMClient.cs - - - Public\AVIMConversation.cs - - - Public\AVIMConversationQuery.cs - - - Public\AVIMEnumerator.cs - - - Public\AVIMEventArgs.cs - - - Public\AVIMException.cs - - - Public\AVIMImageMessage.cs - - - Public\AVIMMessage.cs - - - Public\AVIMMessageClassNameAttribute.cs - - - Public\AVIMMessageFieldNameAttribute.cs - - - Public\AVIMMessageListener.cs - - - Public\AVIMNotice.cs - - - Public\AVIMRecalledMessage.cs - - - Public\AVIMSignature.cs - - - Public\AVIMTemporaryConversation.cs - - - Public\AVIMTextMessage.cs - - - Public\AVIMTypedMessage.cs - - - Public\AVIMTypedMessageTypeIntAttribute.cs - - - Public\AVRealtime.cs - - - Public\IAVIMListener.cs - - - Public\IAVIMMessage.cs - - - Public\ICacheEngine.cs - - - Public\ISignatureFactory.cs - - - Public\Listener\AVIMConversationListener.cs - - - Public\Listener\ConversationUnreadListener.cs - - - Public\Listener\GoAwayListener.cs - - - Public\Listener\MessagePatchListener.cs - - - Public\Listener\OfflineMessageListener.cs - - - Public\Listener\SessionListener.cs - - - - - - - - ..\..\packages\Websockets.Pcl.1.1.9\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10\WebSockets.PCL.dll - - - - \ No newline at end of file diff --git a/RTM/RTM.PCL/packages.config b/RTM/RTM.PCL/packages.config deleted file mode 100644 index 105fd5f..0000000 --- a/RTM/RTM.PCL/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/RTM/RTM.Test/RTM.Test.csproj b/RTM/RTM.Test/RTM.Test.csproj deleted file mode 100644 index 66eada9..0000000 --- a/RTM/RTM.Test/RTM.Test.csproj +++ /dev/null @@ -1,41 +0,0 @@ - - - - Debug - AnyCPU - {A1BBD0B5-41C6-4579-B9A3-5EF778BE7F95} - Library - RTM.Test - RTM.Test - v4.7 - 0.1.0 - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - - - true - bin\Release - prompt - 4 - - - - - ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - - - - - - - - - \ No newline at end of file diff --git a/RTM/RTM.Test/Test.cs b/RTM/RTM.Test/Test.cs deleted file mode 100644 index 4f8a269..0000000 --- a/RTM/RTM.Test/Test.cs +++ /dev/null @@ -1,10 +0,0 @@ -using NUnit.Framework; -using System; -namespace RTM.Test { - [TestFixture()] - public class Test { - [Test()] - public void TestCase() { - } - } -} diff --git a/RTM/RTM.Test/packages.config b/RTM/RTM.Test/packages.config deleted file mode 100644 index bbb222f..0000000 --- a/RTM/RTM.Test/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/RTM/RTM.Unity/Properties/AssemblyInfo.cs b/RTM/RTM.Unity/Properties/AssemblyInfo.cs deleted file mode 100644 index 5485e9a..0000000 --- a/RTM/RTM.Unity/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle("RTM.Unity")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("${AuthorCopyright}")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". -// The form "{Major}.{Minor}.*" will automatically update the build and revision, -// and "{Major}.{Minor}.{Build}.*" will update just the revision. - -[assembly: AssemblyVersion("1.0.*")] - -// The following attributes are used to specify the signing key for the assembly, -// if desired. See the Mono documentation for more information about signing. - -//[assembly: AssemblyDelaySign(false)] -//[assembly: AssemblyKeyFile("")] diff --git a/RTM/RTM.Unity/RTM.Unity.csproj b/RTM/RTM.Unity/RTM.Unity.csproj deleted file mode 100644 index 2d18b38..0000000 --- a/RTM/RTM.Unity/RTM.Unity.csproj +++ /dev/null @@ -1,219 +0,0 @@ - - - - Debug - AnyCPU - {1E608FCD-9039-4FF7-8EE7-BA8B00E15D1C} - Library - RTM.Unity - RTM.Unity - v4.7 - 0.1.0 - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - true - bin\Release - prompt - 4 - false - - - - - ..\..\Libs\UnityEngine.dll - - - ..\..\Libs\websocket-sharp.dll - - - - - - Internal\AVIMCorePlugins.cs - - - Internal\IAVIMPlatformHooks.cs - - - Internal\Command\AVIMCommand.cs - - - Internal\Command\AVIMCommandRunner.cs - - - Internal\Command\AckCommand.cs - - - Internal\Command\ConversationCommand.cs - - - Internal\Command\IAVIMCommandRunner.cs - - - Internal\Command\MessageCommand.cs - - - Internal\Command\PatchCommand.cs - - - Internal\Command\ReadCommand.cs - - - Internal\Command\SessionCommand.cs - - - Internal\DataEngine\Controller\DateTimeEngine.cs - - - Internal\DataEngine\Controller\DictionaryEngine.cs - - - Internal\DataEngine\Controller\StringEngine.cs - - - Internal\Message\Subclassing\FreeStyleMessageClassInfo.cs - - - Internal\Message\Subclassing\FreeStyleMessageClassingController.cs - - - Internal\Message\Subclassing\IFreeStyleMessageClassingController.cs - - - Internal\Protocol\AVIMProtocol.cs - - - Internal\Router\AVRouterController.cs - - - Internal\Router\IAVRouterController.cs - - - Internal\Router\State\RouterState.cs - - - Internal\Timer\IAVTimer.cs - - - Internal\Timer\Unity\AVTimer.Unity.cs - - - Internal\WebSocket\IWebSocketClient.cs - - - Internal\WebSocket\Unity\DefaultWebSocketClient.Unity.cs - - - Public\AVIMAudioMessage.cs - - - Public\AVIMBinaryMessage.cs - - - Public\AVIMClient.cs - - - Public\AVIMConversation.cs - - - Public\AVIMConversationQuery.cs - - - Public\AVIMEnumerator.cs - - - Public\AVIMEventArgs.cs - - - Public\AVIMException.cs - - - Public\AVIMImageMessage.cs - - - Public\AVIMMessage.cs - - - Public\AVIMMessageClassNameAttribute.cs - - - Public\AVIMMessageFieldNameAttribute.cs - - - Public\AVIMMessageListener.cs - - - Public\AVIMNotice.cs - - - Public\AVIMRecalledMessage.cs - - - Public\AVIMSignature.cs - - - Public\AVIMTemporaryConversation.cs - - - Public\AVIMTextMessage.cs - - - Public\AVIMTypedMessage.cs - - - Public\AVIMTypedMessageTypeIntAttribute.cs - - - Public\AVRealtime.cs - - - Public\IAVIMListener.cs - - - Public\IAVIMMessage.cs - - - Public\ICacheEngine.cs - - - Public\ISignatureFactory.cs - - - Public\Listener\AVIMConversationListener.cs - - - Public\Listener\ConversationUnreadListener.cs - - - Public\Listener\GoAwayListener.cs - - - Public\Listener\MessagePatchListener.cs - - - Public\Listener\OfflineMessageListener.cs - - - Public\Listener\SessionListener.cs - - - Public\Unity\AVRealtimeBehavior.cs - - - - - Internal\WebSocket\Unity\websocket-sharp.dll - - - - \ No newline at end of file diff --git a/RTM/Source/Internal/AVIMCorePlugins.cs b/RTM/Source/Internal/AVIMCorePlugins.cs deleted file mode 100644 index 859e0bc..0000000 --- a/RTM/Source/Internal/AVIMCorePlugins.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class AVIMCorePlugins - { - private static readonly AVIMCorePlugins instance = new AVIMCorePlugins(); - public static AVIMCorePlugins Instance - { - get - { - return instance; - } - } - - private readonly object mutex = new object(); - - private IAVRouterController routerController; - public IAVRouterController RouterController - { - get - { - lock (mutex) - { - routerController = routerController ?? new AVRouterController(); - return routerController; - } - } - internal set - { - lock (mutex) - { - routerController = value; - } - } - } - - - private IFreeStyleMessageClassingController freeStyleClassingController; - public IFreeStyleMessageClassingController FreeStyleClassingController - { - get - { - lock (mutex) - { - freeStyleClassingController = freeStyleClassingController ?? new FreeStyleMessageClassingController(); - return freeStyleClassingController; - } - } - } - } -} diff --git a/RTM/Source/Internal/Command/AVIMCommand.cs b/RTM/Source/Internal/Command/AVIMCommand.cs deleted file mode 100644 index 18300e5..0000000 --- a/RTM/Source/Internal/Command/AVIMCommand.cs +++ /dev/null @@ -1,176 +0,0 @@ -using LeanCloud; -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - /// - /// Command. - /// - public class AVIMCommand - { - protected readonly string cmd; - protected readonly string op; - protected string appId; - protected string peerId; - protected AVIMSignature signature; - protected readonly IDictionary arguments; - - public int TimeoutInSeconds { get; set; } - - protected readonly IDictionary estimatedData = new Dictionary(); - internal readonly object mutex = new object(); - internal static readonly object Mutex = new object(); - - public AVIMCommand() : - this(arguments: new Dictionary()) - { - - } - protected AVIMCommand(string cmd = null, - string op = null, - string appId = null, - string peerId = null, - AVIMSignature signature = null, - IDictionary arguments = null) - { - this.cmd = cmd; - this.op = op; - this.arguments = arguments == null ? new Dictionary() : arguments; - this.peerId = peerId; - this.signature = signature; - } - - protected AVIMCommand(AVIMCommand source, - string cmd = null, - string op = null, - string appId = null, - string peerId = null, - IDictionary arguments = null, - AVIMSignature signature = null) - { - if (source == null) - { - throw new ArgumentNullException("source", "Source can not be null"); - } - this.cmd = source.cmd; - this.op = source.op; - this.arguments = source.arguments; - this.peerId = source.peerId; - this.appId = source.appId; - this.signature = source.signature; - - if (cmd != null) - { - this.cmd = cmd; - } - if (op != null) - { - this.op = op; - } - if (arguments != null) - { - this.arguments = arguments; - } - if (peerId != null) - { - this.peerId = peerId; - } - if (appId != null) - { - this.appId = appId; - } - if (signature != null) - { - this.signature = signature; - } - } - - public AVIMCommand Command(string cmd) - { - return new AVIMCommand(this, cmd: cmd); - } - public AVIMCommand Option(string op) - { - return new AVIMCommand(this, op: op); - } - public AVIMCommand Argument(string key, object value) - { - lock (mutex) - { - this.arguments[key] = value; - return new AVIMCommand(this); - } - } - public AVIMCommand AppId(string appId) - { - this.appId = appId; - return new AVIMCommand(this, appId: appId); - } - - public AVIMCommand PeerId(string peerId) - { - this.peerId = peerId; - return new AVIMCommand(this, peerId: peerId); - } - - public AVIMCommand IDlize() - { - this.Argument("i", AVIMCommand.NextCmdId); - return this; - } - - public virtual IDictionary Encode() - { - lock (mutex) - { - estimatedData.Clear(); - estimatedData.Merge(arguments); - estimatedData.Add("cmd", cmd); - estimatedData.Add("appId", this.appId); - if (!string.IsNullOrEmpty(op)) - estimatedData.Add("op", op); - if (!string.IsNullOrEmpty(peerId)) - estimatedData.Add("peerId", peerId); - - return estimatedData; - } - } - - public virtual string EncodeJsonString() - { - var json = this.Encode(); - return Json.Encode(json); - } - - public bool IsValid - { - get - { - return !string.IsNullOrEmpty(this.cmd); - } - } - - private static Int32 lastCmdId = -65536; - internal static Int32 NextCmdId - { - get - { - lock (Mutex) - { - lastCmdId++; - - if (lastCmdId > ushort.MaxValue) - { - lastCmdId = -65536; - } - return lastCmdId; - } - } - } - } -} diff --git a/RTM/Source/Internal/Command/AVIMCommandRunner.cs b/RTM/Source/Internal/Command/AVIMCommandRunner.cs deleted file mode 100644 index 2052c46..0000000 --- a/RTM/Source/Internal/Command/AVIMCommandRunner.cs +++ /dev/null @@ -1,92 +0,0 @@ -using LeanCloud; -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - public class AVIMCommandRunner : IAVIMCommandRunner - { - private readonly IWebSocketClient webSocketClient; - public AVIMCommandRunner(IWebSocketClient webSocketClient) - { - this.webSocketClient = webSocketClient; - } - - public void RunCommand(AVIMCommand command) - { - command.IDlize(); - var requestString = command.EncodeJsonString(); - AVRealtime.PrintLog("websocket=>" + requestString); - webSocketClient.Send(requestString); - } - - /// - /// - /// - /// - /// - /// - public Task>> RunCommandAsync(AVIMCommand command, CancellationToken cancellationToken = default(CancellationToken)) - { - var tcs = new TaskCompletionSource>>(); - - command.IDlize(); - - var requestString = command.EncodeJsonString(); - if (!command.IsValid) - { - requestString = "{}"; - } - AVRealtime.PrintLog("websocket=>" + requestString); - webSocketClient.Send(requestString); - var requestJson = command.Encode(); - - - Action onMessage = null; - onMessage = (response) => - { - //AVRealtime.PrintLog("response<=" + response); - var responseJson = Json.Parse(response) as IDictionary; - if (responseJson.Keys.Contains("i")) - { - if (requestJson["i"].ToString() == responseJson["i"].ToString()) - { - var result = new Tuple>(-1, responseJson); - if (responseJson.Keys.Contains("code")) - { - var errorCode = int.Parse(responseJson["code"].ToString()); - var reason = string.Empty; - int appCode = 0; - - if (responseJson.Keys.Contains("reason")) - { - reason = responseJson["reason"].ToString(); - } - if (responseJson.Keys.Contains("appCode")) - { - appCode = int.Parse(responseJson["appCode"].ToString()); - } - tcs.SetException(new AVIMException(errorCode, appCode, reason, null)); - } - if (tcs.Task.Exception == null) - { - tcs.SetResult(result); - } - webSocketClient.OnMessage -= onMessage; - } - else - { - - } - } - }; - webSocketClient.OnMessage += onMessage; - return tcs.Task; - } - } -} diff --git a/RTM/Source/Internal/Command/AckCommand.cs b/RTM/Source/Internal/Command/AckCommand.cs deleted file mode 100644 index 938f078..0000000 --- a/RTM/Source/Internal/Command/AckCommand.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class AckCommand : AVIMCommand - { - public AckCommand() - : base(cmd: "ack") - { - - } - - public AckCommand(AVIMCommand source) - : base(source) - { - - } - - public AckCommand Message(IAVIMMessage message) - { - return new AckCommand() - .ConversationId(message.ConversationId) - .MessageId(message.Id); - } - - public AckCommand MessageId(string messageId) - { - if (string.IsNullOrEmpty(messageId)) - { - messageId = ""; - } - return new AckCommand(this.Argument("mid", messageId)); - } - - public AckCommand ConversationId(string conversationId) - { - if (string.IsNullOrEmpty(conversationId)) - { - conversationId = ""; - } - return new AckCommand(this.Argument("cid", conversationId)); - } - - public AckCommand FromTimeStamp(long startTimeStamp) - { - return new AckCommand(this.Argument("fromts", startTimeStamp)); - } - - public AckCommand ToTimeStamp(long endTimeStamp) - { - return new AckCommand(this.Argument("tots", endTimeStamp)); - } - - public AckCommand ReadAck() - { - return new AckCommand(this.Argument("read", true)); - } - } -} diff --git a/RTM/Source/Internal/Command/ConversationCommand.cs b/RTM/Source/Internal/Command/ConversationCommand.cs deleted file mode 100644 index ab4de2d..0000000 --- a/RTM/Source/Internal/Command/ConversationCommand.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class ConversationCommand : AVIMCommand - { - protected IList members; - public ConversationCommand() - : base(cmd: "conv") - { - - } - - public ConversationCommand(AVIMCommand source) - : base(source: source) - { - } - - public ConversationCommand Member(string clientId) - { - if (members == null) - { - members = new List(); - } - members.Add(clientId); - return Members(members); - } - - public ConversationCommand Members(IEnumerable members) - { - this.members = members.ToList(); - return new ConversationCommand(this.Argument("m", members)); - } - - public ConversationCommand Transient(bool isTransient) - { - return new ConversationCommand(this.Argument("transient", isTransient)); - } - - public ConversationCommand Unique(bool isUnique) - { - return new ConversationCommand(this.Argument("unique", isUnique)); - } - - public ConversationCommand Temporary(bool isTemporary) - { - return new ConversationCommand(this.Argument("tempConv", isTemporary)); - } - - public ConversationCommand TempConvTTL(double tempConvTTL) - { - return new ConversationCommand(this.Argument("tempConvTTL", tempConvTTL)); - } - - public ConversationCommand Attr(IDictionary attr) - { - return new ConversationCommand(this.Argument("attr", attr)); - } - - public ConversationCommand Set(string key, object value) - { - return new ConversationCommand(this.Argument(key, value)); - } - - public ConversationCommand ConversationId(string conversationId) - { - return new ConversationCommand(this.Argument("cid", conversationId)); - } - - public ConversationCommand Generate(AVIMConversation conversation) - { - var attr = conversation.EncodeAttributes(); - var cmd = new ConversationCommand() - .ConversationId(conversation.ConversationId) - .Attr(attr) - .Members(conversation.MemberIds) - .Transient(conversation.IsTransient) - .Temporary(conversation.IsTemporary); - - if (conversation.IsTemporary) - { - var ttl = (conversation.expiredAt.Value - DateTime.Now).TotalSeconds; - cmd = cmd.TempConvTTL(ttl); - } - - return cmd; - } - - public ConversationCommand Where(object encodedQueryString) - { - return new ConversationCommand(this.Argument("where", encodedQueryString)); - } - - public ConversationCommand Limit(int limit) - { - return new ConversationCommand(this.Argument("limit", limit)); - } - - public ConversationCommand Skip(int skip) - { - return new ConversationCommand(this.Argument("skip", skip)); - } - - public ConversationCommand Count() - { - return new ConversationCommand(this.Argument("count", 1)); - } - - public ConversationCommand Sort(string sort) - { - return new ConversationCommand(this.Argument("sort", sort)); - } - - public ConversationCommand TargetClientId(string targetClientId) - { - return new ConversationCommand(this.Argument("targetClientId", targetClientId)); - } - - public ConversationCommand QueryAllMembers(bool queryAllMembers) - { - return new ConversationCommand(this.Argument("queryAllMembers", queryAllMembers)); - } - - } -} diff --git a/RTM/Source/Internal/Command/IAVIMCommandRunner.cs b/RTM/Source/Internal/Command/IAVIMCommandRunner.cs deleted file mode 100644 index a904f97..0000000 --- a/RTM/Source/Internal/Command/IAVIMCommandRunner.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - public interface IAVIMCommandRunner - { - Task>> RunCommandAsync(AVIMCommand command, - CancellationToken cancellationToken = default(CancellationToken)); - - void RunCommand(AVIMCommand command); - } -} diff --git a/RTM/Source/Internal/Command/MessageCommand.cs b/RTM/Source/Internal/Command/MessageCommand.cs deleted file mode 100644 index ec76d94..0000000 --- a/RTM/Source/Internal/Command/MessageCommand.cs +++ /dev/null @@ -1,83 +0,0 @@ -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class MessageCommand : AVIMCommand - { - public MessageCommand() - : base(cmd: "direct") - { - - } - - public MessageCommand(AVIMCommand source) - : base(source: source) - { - - } - - public MessageCommand ConvId(string convId) - { - return new MessageCommand(this.Argument("cid", convId)); - } - - public MessageCommand Receipt(bool receipt) - { - return new MessageCommand(this.Argument("r", receipt)); - } - - public MessageCommand Transient(bool transient) - { - if (transient) return new MessageCommand(this.Argument("transient", transient)); - return new MessageCommand(this); - } - public MessageCommand Priority(int priority) - { - if (priority > 1) return new MessageCommand(this.Argument("level", priority)); - return new MessageCommand(this); - } - public MessageCommand Will(bool will) - { - if (will) return new MessageCommand(this.Argument("will", will)); - return new MessageCommand(this); - } - public MessageCommand Distinct(string token) - { - return new MessageCommand(this.Argument("dt", token)); - } - public MessageCommand Message(string msg) - { - return new MessageCommand(this.Argument("msg", msg)); - } - public MessageCommand BinaryEncode(bool binaryEncode) - { - return new MessageCommand(this.Argument("bin", binaryEncode)); - } - - public MessageCommand PushData(IDictionary pushData) - { - return new MessageCommand(this.Argument("pushData", Json.Encode(pushData))); - } - - public MessageCommand Mention(IEnumerable clientIds) - { - var mentionedMembers = clientIds.ToList(); - return new MessageCommand(this.Argument("mentionPids", mentionedMembers)); - } - - public MessageCommand MentionAll(bool mentionAll) - { - return new MessageCommand(this.Argument("mentionAll", mentionAll)); - } - - public MessageCommand Binary(byte[] data) - { - return new MessageCommand(this.Argument("binaryMsg", data)); - } - } -} diff --git a/RTM/Source/Internal/Command/PatchCommand.cs b/RTM/Source/Internal/Command/PatchCommand.cs deleted file mode 100644 index 113a0db..0000000 --- a/RTM/Source/Internal/Command/PatchCommand.cs +++ /dev/null @@ -1,98 +0,0 @@ -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class PatchCommand : AVIMCommand - { - - internal struct Patch - { - public string MessageId { get; set; } - public string ConvId { get; set; } - public string From { get; set; } - public long MetaTimestamp { get; set; } - public long PatchTimestamp { get; set; } - public string PatchData { get; set; } - public bool Recall { get; set; } - public byte[] BinaryData { get; set; } - public bool MentionAll { get; set; } - public IEnumerable MentionIds { get; set; } - - public IDictionary Encode() - { - return new Dictionary() - { - { "cid",this.ConvId}, - { "mid",this.MessageId}, - { "from",this.From}, - { "timestamp",this.MetaTimestamp}, - { "recall",this.Recall}, - { "data",this.PatchData}, - { "patchTimestamp",this.PatchTimestamp}, - { "binaryMsg",this.BinaryData}, - { "mentionAll",this.MentionAll}, - { "meintonPids",this.MentionIds} - } as IDictionary; - } - } - - public PatchCommand() - : base(cmd: "patch", op: "modify") - { - this.Patches = new List(); - } - - public PatchCommand(AVIMCommand source, ICollection sourcePatchs) - : base(source: source) - { - this.Patches = sourcePatchs; - } - - public ICollection Patches { get; set; } - - public IList> EncodePatches() - { - return this.Patches.Select(p => p.Encode().Trim()).ToList(); - } - - public PatchCommand Recall(IAVIMMessage message) - { - var patch = new Patch() - { - ConvId = message.ConversationId, - From = message.FromClientId, - MessageId = message.Id, - MetaTimestamp = message.ServerTimestamp, - Recall = true, - PatchTimestamp = DateTime.Now.ToUnixTimeStamp() - }; - - this.Patches.Add(patch); - this.Argument("patches", this.EncodePatches()); - return new PatchCommand(this, this.Patches); - } - - public PatchCommand Modify(IAVIMMessage oldMessage, IAVIMMessage newMessage) - { - var patch = new Patch() - { - ConvId = oldMessage.ConversationId, - From = oldMessage.FromClientId, - MessageId = oldMessage.Id, - MetaTimestamp = oldMessage.ServerTimestamp, - Recall = false, - PatchTimestamp = DateTime.Now.ToUnixTimeStamp(), - PatchData = newMessage.Serialize() - }; - - this.Patches.Add(patch); - this.Argument("patches", this.EncodePatches()); - return new PatchCommand(this, this.Patches); - } - } -} diff --git a/RTM/Source/Internal/Command/ReadCommand.cs b/RTM/Source/Internal/Command/ReadCommand.cs deleted file mode 100644 index a627d00..0000000 --- a/RTM/Source/Internal/Command/ReadCommand.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class ReadCommand : AVIMCommand - { - internal class ConvRead - { - internal string ConvId { get; set; } - internal string MessageId { get; set; } - internal long Timestamp { get; set; } - public override bool Equals(object obj) - { - ConvRead cr = obj as ConvRead; - return cr.ConvId == this.ConvId; - } - public override int GetHashCode() - { - return this.ConvId.GetHashCode() ^ this.MessageId.GetHashCode() ^ this.Timestamp.GetHashCode(); - } - } - - public ReadCommand() - : base(cmd: "read") - { - - } - - public ReadCommand(AVIMCommand source) - : base(source) - { - - } - - public ReadCommand ConvId(string convId) - { - return new ReadCommand(this.Argument("cid", convId)); - } - - public ReadCommand ConvIds(IEnumerable convIds) - { - if (convIds != null) - { - if (convIds.Count() > 0) - { - return new ReadCommand(this.Argument("cids", convIds.ToList())); - } - } - return this; - - } - - public ReadCommand Conv(ConvRead conv) - { - return Convs(new ConvRead[] { conv }); - } - - public ReadCommand Convs(IEnumerable convReads) - { - if (convReads != null) - { - if (convReads.Count() > 0) - { - IList> payload = new List>(); - - foreach (var convRead in convReads) - { - var convDic = new Dictionary(); - convDic.Add("cid", convRead.ConvId); - if (!string.IsNullOrEmpty(convRead.MessageId)) - { - convDic.Add("mid", convRead.MessageId); - } - if (convRead.Timestamp != 0) - { - convDic.Add("timestamp", convRead.Timestamp); - } - payload.Add(convDic); - } - - return new ReadCommand(this.Argument("convs", payload)); - } - } - return this; - } - } -} diff --git a/RTM/Source/Internal/Command/SessionCommand.cs b/RTM/Source/Internal/Command/SessionCommand.cs deleted file mode 100644 index f18b7b9..0000000 --- a/RTM/Source/Internal/Command/SessionCommand.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class SessionCommand : AVIMCommand - { - static readonly int MESSAGE_RECALL_AND_MODIFY = 0x1; - - public SessionCommand() - : base(cmd: "session") - { - arguments.Add("configBitmap", MESSAGE_RECALL_AND_MODIFY); - } - - public SessionCommand(AVIMCommand source) - :base(source: source) - { - - } - - public SessionCommand UA(string ua) - { - return new SessionCommand(this.Argument("ua", ua)); - } - - public SessionCommand Tag(string tag) - { - if (string.IsNullOrEmpty(tag)) return new SessionCommand(this); - return new SessionCommand(this.Argument("tag", tag)); - } - - public SessionCommand DeviceId(string deviceId) - { - if (string.IsNullOrEmpty(deviceId)) return new SessionCommand(this); - return new SessionCommand(this.Argument("deviceId", deviceId)); - } - - public SessionCommand R(int r) - { - return new SessionCommand(this.Argument("r", r)); - } - - public SessionCommand SessionToken(string st) - { - return new SessionCommand(this.Argument("st", st)); - } - - public SessionCommand SessionPeerIds(IEnumerable sessionPeerIds) - { - return new SessionCommand(this.Argument("sessionPeerIds", sessionPeerIds.ToList())); - } - } -} diff --git a/RTM/Source/Internal/DataEngine/Controller/DateTimeEngine.cs b/RTM/Source/Internal/DataEngine/Controller/DateTimeEngine.cs deleted file mode 100644 index 25c920a..0000000 --- a/RTM/Source/Internal/DataEngine/Controller/DateTimeEngine.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal enum UnixTimeStampUnit - { - Second = 1, - Milisecond = 1000, - } - internal static class DateTimeEngine - { - public static long ToUnixTimeStamp(this DateTime date, UnixTimeStampUnit unit = UnixTimeStampUnit.Milisecond) - { - long unixTimestamp = (long)(date.ToUniversalTime().Subtract(new DateTime(1970, 1, 1))).TotalSeconds; - return (unixTimestamp * (int)unit); - } - - public static DateTime ToDateTime(this long timestamp, UnixTimeStampUnit unit = UnixTimeStampUnit.Milisecond) - { - var timespan = timestamp * 1000 / (int)(unit); - DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); - dtDateTime = dtDateTime.AddMilliseconds(timespan).ToLocalTime(); - return dtDateTime; - } - } -} diff --git a/RTM/Source/Internal/DataEngine/Controller/DictionaryEngine.cs b/RTM/Source/Internal/DataEngine/Controller/DictionaryEngine.cs deleted file mode 100644 index a1da600..0000000 --- a/RTM/Source/Internal/DataEngine/Controller/DictionaryEngine.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal static class DictionaryEngine - { - internal static IDictionary Merge(this IDictionary dataLeft, IDictionary dataRight) - { - if (dataRight == null) - return dataLeft; - foreach (var kv in dataRight) - { - if (dataLeft.ContainsKey(kv.Key)) - { - dataLeft[kv.Key] = kv.Value; - } - else - { - dataLeft.Add(kv); - } - } - return dataLeft; - } - - internal static object Grab(this IDictionary data, string path) - { - var keys = path.Split('.').ToList(); - if (keys.Count == 1) return data[keys[0]]; - - var deep = data[keys[0]] as IDictionary; - - keys.RemoveAt(0); - string deepPath = string.Join(".", keys.ToArray()); - - return Grab(deep, deepPath); - } - - internal static IDictionary Trim(this IDictionary data) - { - return data.Where(kvp => kvp.Value != null).ToDictionary(k => k.Key, v => v.Value); - } - } -} diff --git a/RTM/Source/Internal/DataEngine/Controller/StringEngine.cs b/RTM/Source/Internal/DataEngine/Controller/StringEngine.cs deleted file mode 100644 index 62e902a..0000000 --- a/RTM/Source/Internal/DataEngine/Controller/StringEngine.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Text; - -namespace LeanCloud.Realtime.Internal -{ - internal static class StringEngine - { - internal static string Random(this string str, int length) - { - const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; - var random = new Random(); - return new string(Enumerable.Repeat(chars, length) - .Select(s => s[random.Next(s.Length)]).ToArray()); - } - - internal static string TempConvId(this IEnumerable objs) - { - var orderedBase64Strs = objs.Select(obj => Encoding.UTF8.ToBase64(obj.ToString())).OrderBy(a => a, StringComparer.Ordinal).ToArray(); - return "_tmp:" + string.Join("$", orderedBase64Strs); - } - - internal static string ToBase64(this System.Text.Encoding encoding, string text) - { - if (text == null) - { - return null; - } - - byte[] textAsBytes = encoding.GetBytes(text); - return Convert.ToBase64String(textAsBytes); - } - } -} diff --git a/RTM/Source/Internal/IAVIMPlatformHooks.cs b/RTM/Source/Internal/IAVIMPlatformHooks.cs deleted file mode 100644 index 53d737c..0000000 --- a/RTM/Source/Internal/IAVIMPlatformHooks.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - interface IAVIMPlatformHooks - { - IWebSocketClient WebSocketClient { get; } - - string ua { get; } - } -} diff --git a/RTM/Source/Internal/Message/Subclassing/FreeStyleMessageClassInfo.cs b/RTM/Source/Internal/Message/Subclassing/FreeStyleMessageClassInfo.cs deleted file mode 100644 index e1a1e56..0000000 --- a/RTM/Source/Internal/Message/Subclassing/FreeStyleMessageClassInfo.cs +++ /dev/null @@ -1,75 +0,0 @@ -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; - -namespace LeanCloud.Realtime.Internal -{ - internal class FreeStyleMessageClassInfo - { - public TypeInfo TypeInfo { get; private set; } - public IDictionary PropertyMappings { get; private set; } - private ConstructorInfo Constructor { get; set; } - //private MethodInfo ValidateMethod { get; set; } - - public int TypeInt { get; set; } - - public FreeStyleMessageClassInfo(Type type, ConstructorInfo constructor) - { - TypeInfo = type.GetTypeInfo(); - Constructor = constructor; - PropertyMappings = ReflectionHelpers.GetProperties(type) - .Select(prop => Tuple.Create(prop, prop.GetCustomAttribute(true))) - .Where(t => t.Item2 != null) - .Select(t => Tuple.Create(t.Item1, t.Item2.FieldName)) - .ToDictionary(t => t.Item1.Name, t => t.Item2); - } - public bool Validate(string msgStr) - { - var instance = Instantiate(msgStr); - if (instance is AVIMTypedMessage) - { - try - { - var msgDic = Json.Parse(msgStr) as IDictionary; - if (msgDic != null) - { - if (msgDic.ContainsKey(AVIMProtocol.LCTYPE)) - { - return msgDic[AVIMProtocol.LCTYPE].ToString() == TypeInt.ToString(); - } - } - } - catch (Exception ex) - { - if (ex is ArgumentException) - { - return instance.Validate(msgStr); - } - } - - } - return instance.Validate(msgStr); - } - - public IAVIMMessage Instantiate(string msgStr) - { - var rtn = (IAVIMMessage)Constructor.Invoke(null); - return rtn; - } - - public static string GetMessageClassName(TypeInfo type) - { - var attribute = type.GetCustomAttribute(); - return attribute != null ? attribute.ClassName : null; - } - - public static int GetTypedInteger(TypeInfo type) - { - var attribute = type.GetCustomAttribute(); - return attribute != null ? attribute.TypeInteger : 0; - } - } -} diff --git a/RTM/Source/Internal/Message/Subclassing/FreeStyleMessageClassingController.cs b/RTM/Source/Internal/Message/Subclassing/FreeStyleMessageClassingController.cs deleted file mode 100644 index 04bd105..0000000 --- a/RTM/Source/Internal/Message/Subclassing/FreeStyleMessageClassingController.cs +++ /dev/null @@ -1,210 +0,0 @@ -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading; - -namespace LeanCloud.Realtime.Internal -{ - internal class FreeStyleMessageClassingController : IFreeStyleMessageClassingController - { - private static readonly string messageClassName = "_AVIMMessage"; - private readonly IDictionary registeredInterfaces; - private readonly ReaderWriterLockSlim mutex; - - public FreeStyleMessageClassingController() - { - mutex = new ReaderWriterLockSlim(); - registeredInterfaces = new Dictionary(); - } - - public Type GetType(IDictionary msg) - { - throw new NotImplementedException(); - } - - public IAVIMMessage Instantiate(string msgStr, IDictionary buildInData) - { - FreeStyleMessageClassInfo info = null; - mutex.EnterReadLock(); - bool bin = false; - if (buildInData.ContainsKey("bin")) - { - bool.TryParse(buildInData["bin"].ToString(), out bin); - } - - if (bin) - { - var binMessage = new AVIMBinaryMessage(); - this.DecodeProperties(binMessage, buildInData); - return binMessage; - } - - var reverse = registeredInterfaces.Values.Reverse(); - foreach (var subInterface in reverse) - { - if (subInterface.Validate(msgStr)) - { - info = subInterface; - break; - } - } - - mutex.ExitReadLock(); - - var message = info != null ? info.Instantiate(msgStr) : new AVIMMessage(); - - this.DecodeProperties(message, buildInData); - - message.Deserialize(msgStr); - - return message; - } - - public IAVIMMessage DecodeProperties(IAVIMMessage message, IDictionary buildInData) - { - long timestamp; - if (buildInData.ContainsKey("timestamp")) - { - if (long.TryParse(buildInData["timestamp"].ToString(), out timestamp)) - { - message.ServerTimestamp = timestamp; - } - } - long ackAt; - if (buildInData.ContainsKey("ackAt")) - { - if (long.TryParse(buildInData["ackAt"].ToString(), out ackAt)) - { - message.RcpTimestamp = ackAt; - } - } - - if (buildInData.ContainsKey("from")) - { - message.FromClientId = buildInData["from"].ToString(); - } - if (buildInData.ContainsKey("msgId")) - { - message.Id = buildInData["msgId"].ToString(); - } - if (buildInData.ContainsKey("cid")) - { - message.ConversationId = buildInData["cid"].ToString(); - } - if (buildInData.ContainsKey("fromPeerId")) - { - message.FromClientId = buildInData["fromPeerId"].ToString(); - } - if (buildInData.ContainsKey("id")) - { - message.Id = buildInData["id"].ToString(); - } - if (buildInData.ContainsKey("mid")) - { - message.Id = buildInData["mid"].ToString(); - } - if (buildInData.ContainsKey("mentionPids")) - { - message.MentionList = AVDecoder.Instance.DecodeList(buildInData["mentionPids"]); - } - if (buildInData.TryGetValue("patchTimestamp", out object patchTimestampObj)) { - if (long.TryParse(patchTimestampObj.ToString(), out long patchTimestamp)) { - message.UpdatedAt = patchTimestamp; - } - } - - bool mentionAll; - if (buildInData.ContainsKey("mentionAll")) - { - if (bool.TryParse(buildInData["mentionAll"].ToString(), out mentionAll)) - { - message.MentionAll = mentionAll; - } - } - return message; - } - - public IDictionary EncodeProperties(IAVIMMessage subclass) - { - var type = subclass.GetType(); - var result = new Dictionary(); - var className = GetClassName(type); - var typeInt = GetTypeInt(type); - var propertMappings = GetPropertyMappings(className); - foreach (var propertyPair in propertMappings) - { - var propertyInfo = ReflectionHelpers.GetProperty(type, propertyPair.Key); - var operation = propertyInfo.GetValue(subclass, null); - if (operation != null) - result[propertyPair.Value] = PointerOrLocalIdEncoder.Instance.Encode(operation); - } - if (typeInt != 0) - { - result[AVIMProtocol.LCTYPE] = typeInt; - } - return result; - } - - public bool IsTypeValid(IDictionary msg, Type type) - { - return true; - } - - public void RegisterSubclass(Type type) - { - TypeInfo typeInfo = type.GetTypeInfo(); - - if (!typeof(IAVIMMessage).GetTypeInfo().IsAssignableFrom(typeInfo)) - { - throw new ArgumentException("Cannot register a type that is not a implementation of IAVIMMessage"); - } - var className = GetClassName(type); - var typeInt = GetTypeInt(type); - try - { - mutex.EnterWriteLock(); - ConstructorInfo constructor = type.FindConstructor(); - if (constructor == null) - { - throw new ArgumentException("Cannot register a type that does not implement the default constructor!"); - } - var classInfo = new FreeStyleMessageClassInfo(type, constructor); - if (typeInt != 0) - { - classInfo.TypeInt = typeInt; - } - registeredInterfaces[className] = classInfo; - } - finally - { - mutex.ExitWriteLock(); - } - } - public String GetClassName(Type type) - { - return type == typeof(IAVIMMessage) - ? messageClassName - : FreeStyleMessageClassInfo.GetMessageClassName(type.GetTypeInfo()); - } - public int GetTypeInt(Type type) - { - return type == typeof(AVIMTypedMessage) ? 0 : FreeStyleMessageClassInfo.GetTypedInteger(type.GetTypeInfo()); - } - public IDictionary GetPropertyMappings(String className) - { - FreeStyleMessageClassInfo info = null; - mutex.EnterReadLock(); - registeredInterfaces.TryGetValue(className, out info); - if (info == null) - { - registeredInterfaces.TryGetValue(messageClassName, out info); - } - mutex.ExitReadLock(); - - return info.PropertyMappings; - } - } -} diff --git a/RTM/Source/Internal/Message/Subclassing/IFreeStyleMessageClassingController.cs b/RTM/Source/Internal/Message/Subclassing/IFreeStyleMessageClassingController.cs deleted file mode 100644 index 0fc3912..0000000 --- a/RTM/Source/Internal/Message/Subclassing/IFreeStyleMessageClassingController.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace LeanCloud.Realtime.Internal -{ - interface IFreeStyleMessageClassingController - { - bool IsTypeValid(IDictionary msg, Type type); - void RegisterSubclass(Type t); - IAVIMMessage Instantiate(string msgStr,IDictionary buildInData); - IDictionary EncodeProperties(IAVIMMessage subclass); - Type GetType(IDictionary msg); - String GetClassName(Type type); - IDictionary GetPropertyMappings(String className); - } -} diff --git a/RTM/Source/Internal/Protocol/AVIMProtocol.cs b/RTM/Source/Internal/Protocol/AVIMProtocol.cs deleted file mode 100644 index 6c71044..0000000 --- a/RTM/Source/Internal/Protocol/AVIMProtocol.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class AVIMProtocol - { - #region msg format - static internal readonly string LCTYPE = "_lctype"; - static internal readonly string LCFILE = "_lcfile"; - static internal readonly string LCTEXT = "_lctext"; - static internal readonly string LCATTRS = "_lcattrs"; - static internal readonly string LCLOC = "_lcloc"; - #endregion - } -} diff --git a/RTM/Source/Internal/Router/AVRouterController.cs b/RTM/Source/Internal/Router/AVRouterController.cs deleted file mode 100644 index dc47848..0000000 --- a/RTM/Source/Internal/Router/AVRouterController.cs +++ /dev/null @@ -1,173 +0,0 @@ -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class AVRouterController : IAVRouterController - { - const string routerUrl = "http://router.g0.push.leancloud.cn/v1/route?appId={0}"; - const string routerKey = "LeanCloud_RouterState"; - public Task GetAsync(string pushRouter = null, bool secure = true, CancellationToken cancellationToken = default(CancellationToken)) - { - //return Task.FromResult(new PushRouterState() - //{ - // server = "wss://rtm57.leancloud.cn/" - //}); - return LoadAysnc(cancellationToken).OnSuccess(_ => - { - var cache = _.Result; - var task = Task.FromResult(cache); - - if (cache == null || cache.expire < DateTime.Now.ToUnixTimeStamp()) - { - task = QueryAsync(pushRouter, secure, cancellationToken); - } - - return task; - }).Unwrap(); - } - - /// - /// 清理地址缓存 - /// - /// The cache. - public Task ClearCache() { - var tcs = new TaskCompletionSource(); - AVPlugins.Instance.StorageController.LoadAsync().ContinueWith(t => { - if (t.IsFaulted) { - tcs.SetResult(true); - } else { - var storage = t.Result; - if (storage.ContainsKey(routerKey)) { - storage.RemoveAsync(routerKey).ContinueWith(_ => tcs.SetResult(true)); - } else { - tcs.SetResult(true); - } - } - }); - return tcs.Task; - } - - Task LoadAysnc(CancellationToken cancellationToken) - { - try - { - return AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(_ => - { - var currentCache = _.Result; - object routeCacheStr = null; - if (currentCache.TryGetValue(routerKey, out routeCacheStr)) - { - var routeCache = routeCacheStr as IDictionary; - var routerState = new PushRouterState() - { - groupId = routeCache["groupId"] as string, - server = routeCache["server"] as string, - secondary = routeCache["secondary"] as string, - ttl = long.Parse(routeCache["ttl"].ToString()), - expire = long.Parse(routeCache["expire"].ToString()), - source = "localCache" - }; - return routerState; - } - return null; - }); - } - catch - { - return Task.FromResult(null); - } - } - - Task QueryAsync(string pushRouter, bool secure, CancellationToken cancellationToken) - { - var routerHost = pushRouter; - if (routerHost == null) { - var appRouter = AVPlugins.Instance.AppRouterController.Get(); - routerHost = string.Format("https://{0}/v1/route?appId={1}", appRouter.RealtimeRouterServer, AVClient.CurrentConfiguration.ApplicationId) ?? appRouter.RealtimeRouterServer ?? string.Format(routerUrl, AVClient.CurrentConfiguration.ApplicationId); - } - AVRealtime.PrintLog($"router: {routerHost}"); - AVRealtime.PrintLog($"push: {pushRouter}"); - if (!string.IsNullOrEmpty(pushRouter)) - { - var rtmUri = new Uri(pushRouter); - if (!string.IsNullOrEmpty(rtmUri.Scheme)) - { - var url = new Uri(rtmUri, "v1/route").ToString(); - routerHost = string.Format("{0}?appId={1}", url, AVClient.CurrentConfiguration.ApplicationId); - } - else - { - routerHost = string.Format("https://{0}/v1/route?appId={1}", pushRouter, AVClient.CurrentConfiguration.ApplicationId); - } - } - if (secure) - { - routerHost += "&secure=1"; - } - - AVRealtime.PrintLog("use push router url:" + routerHost); - - return AVClient.RequestAsync(uri: new Uri(routerHost), - method: "GET", - headers: null, - data: null, - contentType: "application/json", - cancellationToken: CancellationToken.None).ContinueWith(t => - { - if (t.Exception != null) - { - var innnerException = t.Exception.InnerException; - AVRealtime.PrintLog(innnerException.Message); - throw innnerException; - } - var httpStatus = (int)t.Result.Item1; - if (httpStatus != 200) - { - return null; - } - try - { - var result = t.Result.Item2; - - var routerState = Json.Parse(result) as IDictionary; - if (routerState.Keys.Count == 0) - { - throw new KeyNotFoundException("Can not get websocket url from server,please check the appId."); - } - var ttl = long.Parse(routerState["ttl"].ToString()); - var expire = DateTime.Now.AddSeconds(ttl); - routerState["expire"] = expire.ToUnixTimeStamp(); - - //save to local cache async. - AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(storage => storage.Result.AddAsync(routerKey, routerState)); - var routerStateObj = new PushRouterState() - { - groupId = routerState["groupId"] as string, - server = routerState["server"] as string, - secondary = routerState["secondary"] as string, - ttl = long.Parse(routerState["ttl"].ToString()), - expire = expire.ToUnixTimeStamp(), - source = "online" - }; - - return routerStateObj; - } - catch (Exception e) - { - if (e is KeyNotFoundException) - { - throw e; - } - return null; - } - - }); - } - } -} diff --git a/RTM/Source/Internal/Router/IAVRouterController.cs b/RTM/Source/Internal/Router/IAVRouterController.cs deleted file mode 100644 index b7eebfb..0000000 --- a/RTM/Source/Internal/Router/IAVRouterController.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - interface IAVRouterController - { - Task GetAsync(string pushRouter, bool secure, CancellationToken cancellationToken = default(CancellationToken)); - Task ClearCache(); - } -} diff --git a/RTM/Source/Internal/Router/State/RouterState.cs b/RTM/Source/Internal/Router/State/RouterState.cs deleted file mode 100644 index 66eaea9..0000000 --- a/RTM/Source/Internal/Router/State/RouterState.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - internal class PushRouterState - { - public string groupId { get; internal set; } - public string server { get; internal set; } - public long ttl { get; internal set; } - public long expire { get; internal set; } - public string secondary { get; internal set; } - public string groupUrl { get; internal set; } - - public string source { get; internal set; } - } -} diff --git a/RTM/Source/Internal/Timer/IAVTimer.cs b/RTM/Source/Internal/Timer/IAVTimer.cs deleted file mode 100644 index 5573041..0000000 --- a/RTM/Source/Internal/Timer/IAVTimer.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -namespace LeanCloud.Realtime.Internal -{ - public interface IAVTimer - { - /// - /// Start this timer. - /// - void Start(); - - /// - /// Stop this timer. - /// - void Stop(); - - bool Enabled { get; set; } - - /// - /// The number of milliseconds between timer events. - /// - /// The interval. - double Interval { get; set; } - - /// - /// 已经执行了多少次 - /// - long Executed { get; } - - /// - /// Occurs when elapsed. - /// - event EventHandler Elapsed; - } - /// - /// Timer event arguments. - /// - public class TimerEventArgs : EventArgs - { - public TimerEventArgs(DateTime signalTime) - { - SignalTime = signalTime; - } - public DateTime SignalTime - { - get; - private set; - } - } -} diff --git a/RTM/Source/Internal/Timer/Portable/AVTimer.Portable.cs b/RTM/Source/Internal/Timer/Portable/AVTimer.Portable.cs deleted file mode 100644 index e981dbd..0000000 --- a/RTM/Source/Internal/Timer/Portable/AVTimer.Portable.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Threading; - -namespace LeanCloud.Realtime.Internal -{ - internal delegate void TimerCallback(); - - internal sealed class Timer : CancellationTokenSource, IDisposable - { - TimerCallback exe; - int Interval { get; set; } - - internal Timer(TimerCallback callback, int interval, bool enable) - { - exe = callback; - Interval = interval; - - Enabled = enable; - Execute(); - } - - Task Execute() - { - if (Enabled) - return Task.Delay(Interval).ContinueWith(t => - { - if (!Enabled) - return null; - exe(); - return this.Execute(); - }); - else - return Task.FromResult(0); - } - - volatile bool enabled; - public bool Enabled - { - get { - return enabled; - } set { - enabled = value; - } - } - } - - public class AVTimer : IAVTimer - { - public AVTimer() - { - - } - - Timer timer; - - public bool Enabled - { - get - { - return timer.Enabled; - } - set - { - timer.Enabled = value; - } - } - - public double Interval - { - get; set; - } - - long executed; - - public long Executed - { - get - { - return executed; - } - - internal set - { - executed = value; - } - } - - public void Start() - { - if (timer == null) - { - timer = new Timer(() => - { - Elapsed(this, new TimerEventArgs(DateTime.Now)); - }, (int)Interval, true); - } - } - - public void Stop() - { - if (timer != null) timer.Enabled = false; - } - - public event EventHandler Elapsed; - } -} diff --git a/RTM/Source/Internal/Timer/Unity/AVTimer.Unity.cs b/RTM/Source/Internal/Timer/Unity/AVTimer.Unity.cs deleted file mode 100644 index 8298433..0000000 --- a/RTM/Source/Internal/Timer/Unity/AVTimer.Unity.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Timers; - -namespace LeanCloud.Realtime.Internal -{ - public class AVTimer : IAVTimer - { - public AVTimer() - { - timer = new Timer(); - } - - Timer timer; - - public bool Enabled - { - get - { - return timer.Enabled; - } - set - { - timer.Enabled = value; - } - } - - public double Interval - { - get - { - return timer.Interval; - } - set - { - timer.Interval = value; - } - } - - long executed; - - public long Executed - { - get - { - return executed; - } - - internal set - { - executed = value; - } - } - - public void Start() - { - timer.Start(); - } - - public void Stop() - { - timer.Stop(); - } - - public event EventHandler Elapsed - { - add - { - timer.Elapsed += (object sender, ElapsedEventArgs e) => - { - value(this, new TimerEventArgs(e.SignalTime)); - }; - } - remove - { - timer.Elapsed -= (object sender, ElapsedEventArgs e) => - { - value(this, new TimerEventArgs(e.SignalTime)); - }; ; - } - } - } -} diff --git a/RTM/Source/Internal/WebSocket/IWebSocketClient.cs b/RTM/Source/Internal/WebSocket/IWebSocketClient.cs deleted file mode 100644 index 175ffa0..0000000 --- a/RTM/Source/Internal/WebSocket/IWebSocketClient.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - /// - /// LeanCloud WebSocket 客户端接口 - /// - public interface IWebSocketClient - { - /// - /// 客户端 WebSocket 长连接是否打开 - /// - bool IsOpen { get; } - - /// - /// WebSocket 长连接关闭时触发的事件回调 - /// - event Action OnClosed; - - /// - /// 云端发送数据包给客户端,WebSocket 接受到时触发的事件回调 - /// - event Action OnMessage; - - /// - /// 客户端 WebSocket 长连接成功打开时,触发的事件回调 - /// - event Action OnOpened; - - /// - /// 主动关闭连接 - /// - void Close(); - - void Disconnect(); - - /// - /// 打开连接 - /// - /// wss 地址 - /// 子协议 - void Open(string url, string protocol = null); - /// - /// 发送数据包的接口 - /// - /// - void Send(string message); - - Task Connect(string url, string protocol = null); - } -} diff --git a/RTM/Source/Internal/WebSocket/NetCore/DefaultWebSocketClient.NetCore.cs b/RTM/Source/Internal/WebSocket/NetCore/DefaultWebSocketClient.NetCore.cs deleted file mode 100644 index bf27232..0000000 --- a/RTM/Source/Internal/WebSocket/NetCore/DefaultWebSocketClient.NetCore.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - public class DefaultWebSocketClient : IWebSocketClient - { - private const int ReceiveChunkSize = 1024; - private const int SendChunkSize = 1024; - - private ClientWebSocket _ws; - private Uri _uri; - private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - private readonly CancellationToken _cancellationToken; - - /// - /// Occurs when on closed. - /// - public event Action OnClosed; - /// - /// Occurs when on error. - /// - public event Action OnError; - /// - /// Occurs when on log. - /// - public event Action OnLog; - /// - /// Occurs when on opened. - /// - public event Action OnOpened; - - public bool IsOpen => _ws.State == WebSocketState.Open; - - public DefaultWebSocketClient() - { - _ws = NewWebSocket(); - _cancellationToken = _cancellationTokenSource.Token; - } - - public event Action OnMessage; - - private async void StartListen() - { - var buffer = new byte[8192]; - - try - { - while (_ws.State == WebSocketState.Open) - { - var stringResult = new StringBuilder(); - - WebSocketReceiveResult result; - do - { - result = await _ws.ReceiveAsync(new ArraySegment(buffer), _cancellationToken); - - if (result.MessageType == WebSocketMessageType.Close) - { - await - _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); - CallOnDisconnected(); - } - else - { - var str = Encoding.UTF8.GetString(buffer, 0, result.Count); - stringResult.Append(str); - } - - } while (!result.EndOfMessage); - - CallOnMessage(stringResult); - - } - } - catch (Exception) - { - CallOnDisconnected(); - } - finally - { - _ws.Dispose(); - } - } - - private void CallOnMessage(StringBuilder stringResult) - { - if (OnMessage != null) - RunInTask(() => OnMessage(stringResult.ToString())); - } - - private void CallOnDisconnected() - { - AVRealtime.PrintLog("PCL websocket closed without parameters."); - if (OnClosed != null) - RunInTask(() => this.OnClosed(0, "", "")); - } - - private void CallOnConnected() - { - if (OnOpened != null) - RunInTask(() => this.OnOpened()); - } - - private static void RunInTask(Action action) - { - Task.Factory.StartNew(action); - } - - public async void Close() - { - if (_ws != null) - { - try - { - await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); - CallOnDisconnected(); - } - catch (Exception ex) - { - CallOnDisconnected(); - } - } - } - - public void Disconnect() { - _ws?.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); - } - - public async void Open(string url, string protocol = null) - { - _uri = new Uri(url); - if (_ws.State == WebSocketState.Open || _ws.State == WebSocketState.Connecting) - { - _ws = NewWebSocket(); - } - try - { - await _ws.ConnectAsync(_uri, _cancellationToken); - CallOnConnected(); - StartListen(); - } - catch (Exception ex) - { - if (ex is ObjectDisposedException) - { - OnError($"can NOT connect server with url: {url}"); - } - } - } - - public async void Send(string message) - { - if (_ws.State != WebSocketState.Open) - { - throw new Exception("Connection is not open."); - } - - var encoded = Encoding.UTF8.GetBytes(message); - var buffer = new ArraySegment(encoded, 0, encoded.Length); - await _ws.SendAsync(buffer, WebSocketMessageType.Text, true, _cancellationToken); - } - - ClientWebSocket NewWebSocket() - { - var result = new ClientWebSocket(); - result.Options.KeepAliveInterval = TimeSpan.FromSeconds(20); - return result; - } - } -} \ No newline at end of file diff --git a/RTM/Source/Internal/WebSocket/NetFx45/WebSocketClient.NetFx45.cs b/RTM/Source/Internal/WebSocket/NetFx45/WebSocketClient.NetFx45.cs deleted file mode 100644 index dfa5ac9..0000000 --- a/RTM/Source/Internal/WebSocket/NetFx45/WebSocketClient.NetFx45.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using Websockets; -using System.Net.WebSockets; -using LeanCloud.Realtime.Internal; - -namespace LeanCloud.Realtime -{ - public class WebSocketClient: IWebSocketClient - { - internal readonly IWebSocketConnection connection; - public WebSocketClient() - { - Websockets.Net.WebsocketConnection.Link(); - connection = WebSocketFactory.Create(); - } - - public event Action OnClosed; - public event Action OnError; - public event Action OnLog; - - public event Action OnOpened - { - add - { - connection.OnOpened += value; - } - remove - { - connection.OnOpened -= value; - } - } - - public event Action OnMessage - { - add - { - connection.OnMessage += value; - } - remove - { - connection.OnMessage -= value; - } - } - - public bool IsOpen - { - get - { - return connection.IsOpen; - } - } - - public void Close() - { - if (connection != null) - { - connection.Close(); - } - } - - public void Open(string url, string protocol = null) - { - if (connection != null) - { - connection.Open(url, protocol); - } - } - - public void Send(string message) - { - if (connection != null) - { - if (this.IsOpen) - { - connection.Send(message); - } - } - } - } -} diff --git a/RTM/Source/Internal/WebSocket/Portable/DefaultWebSocketClient.Portable.cs b/RTM/Source/Internal/WebSocket/Portable/DefaultWebSocketClient.Portable.cs deleted file mode 100644 index 85face2..0000000 --- a/RTM/Source/Internal/WebSocket/Portable/DefaultWebSocketClient.Portable.cs +++ /dev/null @@ -1,164 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Websockets; - -namespace LeanCloud.Realtime.Internal -{ - /// - /// LeanCloud Realtime SDK for .NET Portable 内置默认的 WebSocketClient - /// - public class DefaultWebSocketClient : IWebSocketClient - { - internal IWebSocketConnection connection; - /// - /// LeanCluod .NET Realtime SDK 内置默认的 WebSocketClient - /// 开发者可以在初始化的时候指定自定义的 WebSocketClient - /// - public DefaultWebSocketClient() - { - - } - - public event Action OnClosed; - public event Action OnOpened; - public event Action OnMessage; - - public bool IsOpen - { - get - { - return connection != null && connection.IsOpen; - } - } - - public void Close() - { - if (connection != null) - { - connection.OnOpened -= Connection_OnOpened; - connection.OnMessage -= Connection_OnMessage; - connection.OnClosed -= Connection_OnClosed; - connection.OnError -= Connection_OnError; - try { - connection.Close(); - } catch (Exception e) { - AVRealtime.PrintLog(string.Format("close websocket error: {0}", e.Message)); - } - } - } - - public void Disconnect() { - connection?.Close(); - } - - public void Open(string url, string protocol = null) - { - // 在每次打开时,重新创建 WebSocket 对象 - connection = WebSocketFactory.Create(); - connection.OnOpened += Connection_OnOpened; - connection.OnMessage += Connection_OnMessage; - connection.OnClosed += Connection_OnClosed; - connection.OnError += Connection_OnError; - if (!string.IsNullOrEmpty(protocol)) - { - url = string.Format("{0}?subprotocol={1}", url, protocol); - } - connection.Open(url, protocol); - } - - private void Connection_OnOpened() - { - OnOpened?.Invoke(); - } - - private void Connection_OnMessage(string obj) - { - AVRealtime.PrintLog("websocket<=" + obj); - OnMessage?.Invoke(obj); - } - - private void Connection_OnClosed() - { - AVRealtime.PrintLog("PCL websocket closed without parameters.."); - OnClosed?.Invoke(0, "", ""); - } - - private void Connection_OnError(string obj) - { - AVRealtime.PrintLog($"PCL websocket error: {obj}"); - connection?.Close(); - } - - public void Send(string message) - { - if (connection != null) - { - if (this.IsOpen) - { - connection.Send(message); - } - else - { - var log = "Connection is NOT open when send message"; - AVRealtime.PrintLog(log); - connection?.Close(); - } - } - else { - AVRealtime.PrintLog("Connection is NULL"); - } - } - - public Task Connect(string url, string protocol = null) { - var tcs = new TaskCompletionSource(); - Action onOpen = null; - Action onClose = null; - Action onError = null; - onOpen = () => { - AVRealtime.PrintLog("PCL websocket opened"); - connection.OnOpened -= onOpen; - connection.OnClosed -= onClose; - connection.OnError -= onError; - // 注册事件 - connection.OnMessage += Connection_OnMessage; - connection.OnClosed += Connection_OnClosed; - connection.OnError += Connection_OnError; - tcs.SetResult(true); - }; - onClose = () => { - connection.OnOpened -= onOpen; - connection.OnClosed -= onClose; - connection.OnError -= onError; - tcs.SetException(new Exception("连接关闭")); - }; - onError = (err) => { - AVRealtime.PrintLog(string.Format("连接错误:{0}", err)); - connection.OnOpened -= onOpen; - connection.OnClosed -= onClose; - connection.OnError -= onError; - try { - connection.Close(); - } catch (Exception e) { - AVRealtime.PrintLog(string.Format("关闭错误的 WebSocket 异常:{0}", e.Message)); - } finally { - tcs.SetException(new Exception(string.Format("连接错误:{0}", err))); - } - }; - - // 在每次打开时,重新创建 WebSocket 对象 - connection = WebSocketFactory.Create(); - connection.OnOpened += onOpen; - connection.OnClosed += onClose; - connection.OnError += onError; - // - if (!string.IsNullOrEmpty(protocol)) { - url = string.Format("{0}?subprotocol={1}", url, protocol); - } - connection.Open(url, protocol); - return tcs.Task; - } - } -} diff --git a/RTM/Source/Internal/WebSocket/Unity/DefaultWebSocketClient.Unity.cs b/RTM/Source/Internal/WebSocket/Unity/DefaultWebSocketClient.Unity.cs deleted file mode 100644 index c0769b4..0000000 --- a/RTM/Source/Internal/WebSocket/Unity/DefaultWebSocketClient.Unity.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using WebSocketSharp; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime.Internal -{ - - /// - /// LeanCluod Unity Realtime SDK 内置默认的 WebSocketClient - /// 开发者可以在初始化的时候指定自定义的 WebSocketClient - /// - public class DefaultWebSocketClient : IWebSocketClient - { - WebSocket ws; - public bool IsOpen - { - get - { - if (ws == null) { return false; } - return ws.IsAlive; - } - } - - public event Action OnClosed; - public event Action OnMessage - { - add - { - onMesssageCount++; - AVRealtime.PrintLog("DefaultWebSocketClient.OnMessage event add with " + onMesssageCount + " times"); - m_OnMessage += value; - - } - remove - { - onMesssageCount--; - AVRealtime.PrintLog("DefaultWebSocketClient.OnMessage event remove with " + onMesssageCount + " times"); - m_OnMessage -= value; - } - } - private Action m_OnMessage; - private int onMesssageCount = 0; - public event Action OnOpened; - - public void Close() - { - ws.CloseAsync(); - ws.OnOpen -= OnOpen; - ws.OnMessage -= OnWebSokectMessage; - ws.OnClose -= OnClose; - } - - public void Disconnect() { - ws.CloseAsync(); - } - - public void Open(string url, string protocol = null) - { - if (!string.IsNullOrEmpty(protocol)) - { - url = string.Format("{0}?subprotocol={1}", url, protocol); - } - ws = new WebSocket(url); - ws.OnOpen += OnOpen; - ws.OnMessage += OnWebSokectMessage; - ws.OnClose += OnClose; - ws.ConnectAsync(); - } - - private void OnWebSokectMessage(object sender, MessageEventArgs e) - { - AVRealtime.PrintLog("websocket<=" + e.Data); - m_OnMessage?.Invoke(e.Data); - } - - private void OnClose(object sender, CloseEventArgs e) { - AVRealtime.PrintLog(string.Format("Unity websocket closed with {0}, {1}", e.Code, e.Reason)); - OnClosed?.Invoke(e.Code, e.Reason, null); - } - - void OnWebSocketError(object sender, ErrorEventArgs e) { - AVRealtime.PrintLog($"PCL websocket error: {e.Message}"); - ws?.Close(); - } - - private void OnOpen(object sender, EventArgs e) { - OnOpened?.Invoke(); - } - - public void Send(string message) - { - ws.SendAsync(message, (b) => - { - - }); - } - - public Task Connect(string url, string protocol = null) { - var tcs = new TaskCompletionSource(); - EventHandler onOpen = null; - EventHandler onClose = null; - EventHandler onError = null; - onOpen = (sender, e) => { - AVRealtime.PrintLog("PCL websocket opened"); - ws.OnOpen -= onOpen; - ws.OnClose -= onClose; - ws.OnError -= onError; - // 注册事件 - ws.OnMessage += OnWebSokectMessage; - ws.OnClose += OnClose; - ws.OnError += OnWebSocketError; - tcs.SetResult(true); - }; - onClose = (sender, e) => { - ws.OnOpen -= onOpen; - ws.OnClose -= onClose; - ws.OnError -= onError; - tcs.SetException(new Exception("连接关闭")); - }; - onError = (sender, e) => { - AVRealtime.PrintLog(string.Format("连接错误:{0}", e.Message)); - ws.OnOpen -= onOpen; - ws.OnClose -= onClose; - ws.OnError -= onError; - try { - ws.Close(); - } catch (Exception ex) { - AVRealtime.PrintLog(string.Format("关闭错误的 WebSocket 异常:{0}", ex.Message)); - } finally { - tcs.SetException(new Exception(string.Format("连接错误:{0}", e.Message))); - } - }; - - // 在每次打开时,重新创建 WebSocket 对象 - if (!string.IsNullOrEmpty(protocol)) { - url = string.Format("{0}?subprotocol={1}", url, protocol); - } - ws = new WebSocket(url); - ws.OnOpen += onOpen; - ws.OnClose += onClose; - ws.OnError += onError; - ws.ConnectAsync(); - return tcs.Task; - } - } -} diff --git a/RTM/Source/Internal/WebSocket/Unity/websocket-sharp.dll b/RTM/Source/Internal/WebSocket/Unity/websocket-sharp.dll deleted file mode 100644 index 06740f7..0000000 Binary files a/RTM/Source/Internal/WebSocket/Unity/websocket-sharp.dll and /dev/null differ diff --git a/RTM/Source/Public/AVIMAudioMessage.cs b/RTM/Source/Public/AVIMAudioMessage.cs deleted file mode 100644 index 3c0907e..0000000 --- a/RTM/Source/Public/AVIMAudioMessage.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// Audio message. - /// - [AVIMMessageClassName("_AVIMAudioMessage")] - [AVIMTypedMessageTypeInt(-3)] - public class AVIMAudioMessage : AVIMFileMessage - { - - } - - /// - /// Video message. - /// - [AVIMMessageClassName("_AVIMVideoMessage")] - [AVIMTypedMessageTypeInt(-4)] - public class AVIMVideoMessage: AVIMFileMessage - { - - } -} diff --git a/RTM/Source/Public/AVIMBinaryMessage.cs b/RTM/Source/Public/AVIMBinaryMessage.cs deleted file mode 100644 index 103d4b3..0000000 --- a/RTM/Source/Public/AVIMBinaryMessage.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using LeanCloud.Realtime.Internal; - -namespace LeanCloud.Realtime -{ - /// - /// 基于二进制数据的消息类型,可以直接发送 Byte 数组 - /// - [AVIMMessageClassName("_AVIMBinaryMessage")] - public class AVIMBinaryMessage : AVIMMessage - { - - /// - /// Initializes a new instance of the class. - /// - public AVIMBinaryMessage() - { - - } - /// - /// create new instance of AVIMBinnaryMessage - /// - /// - public AVIMBinaryMessage(byte[] data) - { - this.BinaryData = data; - } - - /// - /// Gets or sets the binary data. - /// - /// The binary data. - public byte[] BinaryData { get; set; } - - internal override MessageCommand BeforeSend(MessageCommand cmd) - { - var result = base.BeforeSend(cmd); - result = result.Binary(this.BinaryData); - return result; - } - } -} diff --git a/RTM/Source/Public/AVIMClient.cs b/RTM/Source/Public/AVIMClient.cs deleted file mode 100644 index 4715c07..0000000 --- a/RTM/Source/Public/AVIMClient.cs +++ /dev/null @@ -1,1195 +0,0 @@ -using LeanCloud; -using LeanCloud.Storage.Internal; -using LeanCloud.Realtime.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// 代表一个实时通信的终端用户 - /// - public class AVIMClient - { - private readonly string clientId; - private readonly AVRealtime _realtime; - internal readonly object mutex = new object(); - internal readonly object patchMutex = new object(); - - /// - /// 一些可变的配置选项,便于应对各种需求场景 - /// - public struct Configuration - { - /// - /// Gets or sets a value indicating whether this - /// auto read. - /// - /// true if auto read; otherwise, false. - public bool AutoRead { get; set; } - } - - /// - /// Gets or sets the current configuration. - /// - /// The current configuration. - public Configuration CurrentConfiguration - { - get; set; - } - - internal AVRealtime LinkedRealtime - { - get { return _realtime; } - } - - /// - /// 单点登录所使用的 Tag - /// - public string Tag - { - get; - private set; - } - - /// - /// 客户端的标识,在一个 Application 内唯一。 - /// - public string ClientId - { - get { return clientId; } - } - - //private EventHandler m_OnNoticeReceived; - ///// - ///// 接收到服务器的命令时触发的事件 - ///// - //public event EventHandler OnNoticeReceived - //{ - // add - // { - // m_OnNoticeReceived += value; - // } - // remove - // { - // m_OnNoticeReceived -= value; - // } - //} - - private int onMessageReceivedCount = 0; - private EventHandler m_OnMessageReceived; - /// - /// 接收到聊天消息的事件通知 - /// - public event EventHandler OnMessageReceived - { - add - { - onMessageReceivedCount++; - AVRealtime.PrintLog("AVIMClient.OnMessageReceived event add with " + onMessageReceivedCount + " times"); - m_OnMessageReceived += value; - } - remove - { - onMessageReceivedCount--; - AVRealtime.PrintLog("AVIMClient.OnMessageReceived event remove with" + onMessageReceivedCount + " times"); - m_OnMessageReceived -= value; - } - } - - /// - /// Occurs when on members joined. - /// - public event EventHandler OnMembersJoined; - - /// - /// Occurs when on members left. - /// - public event EventHandler OnMembersLeft; - - /// - /// Occurs when on kicked. - /// - public event EventHandler OnKicked; - - /// - /// Occurs when on invited. - /// - public event EventHandler OnInvited; - - internal event EventHandler OnOfflineMessageReceived; - - private EventHandler m_OnSessionClosed; - /// - /// 当前打开的链接被迫关闭时触发的事件回调 - /// 可能的原因有单点登录冲突,或者被 REST API 强制踢下线 - /// - public event EventHandler OnSessionClosed - { - add - { - m_OnSessionClosed += value; - } - remove - { - m_OnSessionClosed -= value; - } - } - - /// - /// 创建 AVIMClient 对象 - /// - /// - /// - internal AVIMClient(string clientId, AVRealtime realtime) - : this(clientId, null, realtime) - { - - } - - /// - /// - /// - /// - /// - /// - internal AVIMClient(string clientId, string tag, AVRealtime realtime) - { - this.clientId = clientId; - Tag = tag ?? tag; - _realtime = realtime; - - #region sdk 强制在接收到消息之后一定要向服务端回发 ack - var ackListener = new AVIMMessageListener(); - ackListener.OnMessageReceived += AckListener_OnMessageReceieved; - //this.RegisterListener(ackListener); - #endregion - - #region 默认要为当前 client 绑定一个消息的监听器,用作消息的事件通知 - var messageListener = new AVIMMessageListener(); - messageListener.OnMessageReceived += MessageListener_OnMessageReceived; - this.RegisterListener(messageListener); - #endregion - - #region 默认要为当前 client 绑定一个 session close 的监听器,用来监测单点登录冲突的事件通知 - var sessionListener = new SessionListener(); - sessionListener.OnSessionClosed += SessionListener_OnSessionClosed; - this.RegisterListener(sessionListener); - #endregion - - #region 默认要为当前 client 监听 Ta 所出的对话中的人员变动的被动消息通知 - var membersJoinedListener = new AVIMMembersJoinListener(); - membersJoinedListener.OnMembersJoined += MembersJoinedListener_OnMembersJoined; - this.RegisterListener(membersJoinedListener); - - var membersLeftListener = new AVIMMembersLeftListener(); - membersLeftListener.OnMembersLeft += MembersLeftListener_OnMembersLeft; - this.RegisterListener(membersLeftListener); - - var invitedListener = new AVIMInvitedListener(); - invitedListener.OnInvited += InvitedListener_OnInvited; - this.RegisterListener(invitedListener); - - var kickedListener = new AVIMKickedListener(); - kickedListener.OnKicked += KickedListener_OnKicked; - this.RegisterListener(kickedListener); - #endregion - - #region 当前 client id 离线的时间内,TA 所在的对话产生的普通消息会以离线消息的方式送达到 TA 下一次登录的客户端 - var offlineMessageListener = new OfflineMessageListener(); - offlineMessageListener.OnOfflineMessageReceived += OfflineMessageListener_OnOfflineMessageReceived; - this.RegisterListener(offlineMessageListener); - #endregion - - #region 当前 client 离线期间内产生的未读消息可以通过之后调用 Conversation.SyncStateAsync 获取一下离线期间内的未读状态 - var unreadListener = new ConversationUnreadListener(); - this.RegisterListener(unreadListener); - #endregion - - #region 消息补丁(修改或者撤回) - var messagePatchListener = new MessagePatchListener(); - messagePatchListener.OnReceived = (messages) => - { - foreach (var message in messages) { - if (message is AVIMRecalledMessage) { - m_OnMessageRecalled?.Invoke(this, new AVIMMessagePatchEventArgs(message)); - } else { - m_OnMessageUpdated?.Invoke(this, new AVIMMessagePatchEventArgs(message)); - } - } - }; - this.RegisterListener(messagePatchListener); - #endregion - - #region configuration - CurrentConfiguration = new Configuration() - { - AutoRead = true, - }; - #endregion - - } - - private void OfflineMessageListener_OnOfflineMessageReceived(object sender, AVIMMessageEventArgs e) - { - if (OnOfflineMessageReceived != null) - { - OnOfflineMessageReceived(this, e); - } - this.AckListener_OnMessageReceieved(sender, e); - } - - private void KickedListener_OnKicked(object sender, AVIMOnKickedEventArgs e) - { - if (OnKicked != null) - OnKicked(this, e); - } - - private void InvitedListener_OnInvited(object sender, AVIMOnInvitedEventArgs e) - { - if (OnInvited != null) - OnInvited(this, e); - } - - private void MembersLeftListener_OnMembersLeft(object sender, AVIMOnMembersLeftEventArgs e) - { - if (OnMembersLeft != null) - OnMembersLeft(this, e); - } - - private void MembersJoinedListener_OnMembersJoined(object sender, AVIMOnMembersJoinedEventArgs e) - { - if (OnMembersJoined != null) - OnMembersJoined(this, e); - } - - private void SessionListener_OnSessionClosed(int arg1, string arg2, string arg3) - { - if (m_OnSessionClosed != null) - { - var args = new AVIMSessionClosedEventArgs() - { - Code = arg1, - Reason = arg2, - Detail = arg3 - }; - if (args.Code == 4115 || args.Code == 4111) - { - this._realtime.sessionConflict = true; - } - - m_OnSessionClosed(this, args); - } - AVRealtime.PrintLog("SessionListener_OnSessionClosed invoked."); - //this.LinkedRealtime.LogOut(); - } - - private void MessageListener_OnMessageReceived(object sender, AVIMMessageEventArgs e) - { - if (this.m_OnMessageReceived != null) - { - this.m_OnMessageReceived.Invoke(this, e); - } - this.AckListener_OnMessageReceieved(sender, e); - } - - private void AckListener_OnMessageReceieved(object sender, AVIMMessageEventArgs e) - { - lock (mutex) - { - var ackCommand = new AckCommand().MessageId(e.Message.Id) - .ConversationId(e.Message.ConversationId); - - // 在 v.2 协议下,只要在线收到消息,就默认是已读的,下次上线不会再把当前消息当做未读消息 - if (this.LinkedRealtime.CurrentConfiguration.OfflineMessageStrategy == AVRealtime.OfflineMessageStrategy.UnreadNotice) - { - ackCommand = ackCommand.ReadAck(); - } - - this.RunCommandAsync(ackCommand); - } - } - - private void UpdateUnreadNotice(object sender, AVIMMessageEventArgs e) - { - ConversationUnreadListener.UpdateNotice(e.Message); - } - - #region listener - - /// - /// 注册 IAVIMListener - /// - /// - /// - public void RegisterListener(IAVIMListener listener, Func runtimeHook = null) - { - _realtime.SubscribeNoticeReceived(listener, runtimeHook); - } - - #region get client instance - /// - /// Get the specified clientId. - /// - /// The get. - /// Client identifier. - public static AVIMClient Get(string clientId) - { - if (AVRealtime.clients == null || !AVRealtime.clients.ContainsKey(clientId)) throw new Exception(string.Format("no client found with a id in {0}", clientId)); - - return AVRealtime.clients[clientId]; - } - #endregion - - #endregion - /// - /// 创建对话 - /// - /// 对话 - /// 是否创建唯一对话,当 isUnique 为 true 时,如果当前已经有相同成员的对话存在则返回该对话,否则会创建新的对话。该值默认为 false。 - /// - internal Task CreateConversationAsync(AVIMConversation conversation, bool isUnique = true) - { - var cmd = new ConversationCommand() - .Generate(conversation) - .Unique(isUnique); - - var convCmd = cmd.Option("start") - .PeerId(clientId); - - return LinkedRealtime.AttachSignature(convCmd, LinkedRealtime.SignatureFactory.CreateStartConversationSignature(this.clientId, conversation.MemberIds)).OnSuccess(_ => - { - return this.RunCommandAsync(convCmd).OnSuccess(t => - { - var result = t.Result; - if (result.Item1 < 1) - { - var members = conversation.MemberIds.ToList(); - members.Add(ClientId); - conversation.MemberIds = members; - conversation.MergeFromPushServer(result.Item2); - } - - return conversation; - }); - }).Unwrap(); - } - - /// - /// 创建与目标成员的对话. - /// - /// 返回对话实例. - /// 目标成员. - /// 目标成员列表. - /// 对话名称. - /// 是否是系统对话. - /// 是否为暂态对话(聊天室). - /// 是否是唯一对话. - /// 自定义属性. - public Task CreateConversationAsync(string member = null, - IEnumerable members = null, - string name = "", - bool isSystem = false, - bool isTransient = false, - bool isUnique = true, - bool isTemporary = false, - int ttl = 86400, - IDictionary options = null) - { - if (member == null) member = ClientId; - var membersAsList = Concat(member, members, "创建对话时被操作的 member(s) 不可以为空。"); - var conversation = new AVIMConversation(members: membersAsList, - name: name, - isUnique: isUnique, - isSystem: isSystem, - isTransient: isTransient, - isTemporary: isTemporary, - ttl: ttl, - client: this); - if (options != null) - { - foreach (var key in options.Keys) - { - conversation[key] = options[key]; - } - } - return CreateConversationAsync(conversation, isUnique); - } - - /// - /// Creates the conversation async. - /// - /// The conversation async. - /// Builder. - public Task CreateConversationAsync(IAVIMConversatioBuilder builder) - { - var conversation = builder.Build(); - return CreateConversationAsync(conversation, conversation.IsUnique); - } - - /// - /// Gets the conversatio builder. - /// - /// The conversatio builder. - public AVIMConversationBuilder GetConversationBuilder() - { - var builder = AVIMConversationBuilder.CreateDefaultBuilder(); - builder.Client = this; - return builder; - } - - /// - /// 创建虚拟对话,对话 id 是由本地直接生成,云端根据规则消息发送给指定的 client id(s) - /// - /// - /// - /// 过期时间,默认是一天(86400 秒),单位是秒 - /// - public Task CreateTemporaryConversationAsync(string member = null, - IEnumerable members = null, int ttl = 86400) - { - if (member == null) member = ClientId; - var membersAsList = Concat(member, members, "创建对话时被操作的 member(s) 不可以为空。"); - return CreateConversationAsync(member, membersAsList, isTemporary: true, ttl: ttl); - } - - /// - /// 创建聊天室(即:暂态对话) - /// - /// 聊天室名称 - /// - public Task CreateChatRoomAsync(string chatroomName) - { - return CreateConversationAsync(name: chatroomName, isTransient: true); - } - - /// - /// 获取一个对话 - /// - /// 对话的 ID - /// 从服务器获取 - /// - public Task GetConversationAsync(string id, bool noCache = true) - { - if (!noCache) return Task.FromResult(new AVIMConversation(this) { ConversationId = id }); - else - { - return this.GetQuery().WhereEqualTo("objectId", id).FirstAsync(); - } - } - - #region send message - /// - /// 向目标对话发送消息 - /// - /// 目标对话 - /// 消息体 - /// - public Task SendMessageAsync( - AVIMConversation conversation, - IAVIMMessage message) - { - return this.SendMessageAsync(conversation, message, new AVIMSendOptions() - { - Receipt = true, - Transient = false, - Priority = 1, - Will = false, - PushData = null, - }); - } - - /// - /// 向目标对话发送消息 - /// - /// 目标对话 - /// 消息体 - /// 消息的发送选项,包含了一些特殊的标记 - /// - public Task SendMessageAsync( - AVIMConversation conversation, - IAVIMMessage message, - AVIMSendOptions options) - { - if (this.LinkedRealtime.State != AVRealtime.Status.Online) throw new Exception("未能连接到服务器,无法发送消息。"); - - var messageBody = message.Serialize(); - - message.ConversationId = conversation.ConversationId; - message.FromClientId = this.ClientId; - - var cmd = new MessageCommand() - .Message(messageBody) - .ConvId(conversation.ConversationId) - .Receipt(options.Receipt) - .Transient(options.Transient) - .Priority(options.Priority) - .Will(options.Will) - .MentionAll(message.MentionAll); - - if (message is AVIMMessage) - { - cmd = ((AVIMMessage)message).BeforeSend(cmd); - } - - if (options.PushData != null) - { - cmd = cmd.PushData(options.PushData); - } - - if (message.MentionList != null) - { - cmd = cmd.Mention(message.MentionList); - } - - var directCmd = cmd.PeerId(this.ClientId); - - return this.RunCommandAsync(directCmd).OnSuccess(t => - { - var response = t.Result.Item2; - - message.Id = response["uid"].ToString(); - message.ServerTimestamp = long.Parse(response["t"].ToString()); - - return message; - - }); - } - - - #endregion - - #region mute & unmute - /// - /// 当前用户对目标对话进行静音操作 - /// - /// - /// - public Task MuteConversationAsync(AVIMConversation conversation) - { - var convCmd = new ConversationCommand() - .ConversationId(conversation.ConversationId) - .Option("mute") - .PeerId(this.ClientId); - - return this.RunCommandAsync(convCmd); - } - /// - /// 当前用户对目标对话取消静音,恢复该对话的离线消息推送 - /// - /// - /// - public Task UnmuteConversationAsync(AVIMConversation conversation) - { - var convCmd = new ConversationCommand() - .ConversationId(conversation.ConversationId) - .Option("unmute") - .PeerId(this.ClientId); - - return this.RunCommandAsync(convCmd); - } - #endregion - - #region Conversation members operations - internal Task OperateMembersAsync(AVIMConversation conversation, string action, string member = null, IEnumerable members = null) - { - if (string.IsNullOrEmpty(conversation.ConversationId)) - { - throw new Exception("conversation id 不可以为空。"); - } - - var membersAsList = Concat(member, members, "加人或者踢人的时候,被操作的 member(s) 不可以为空。"); - - var cmd = new ConversationCommand().ConversationId(conversation.ConversationId) - .Members(membersAsList) - .Option(action) - .PeerId(clientId); - - return this.LinkedRealtime.AttachSignature(cmd, LinkedRealtime.SignatureFactory.CreateConversationSignature(conversation.ConversationId, ClientId, membersAsList, ConversationSignatureAction.Add)).OnSuccess(_ => - { - return this.RunCommandAsync(cmd).OnSuccess(t => - { - var result = t.Result; - if (!conversation.IsTransient) - { - if (conversation.MemberIds == null) conversation.MemberIds = new List(); - conversation.MemberIds = conversation.MemberIds.Concat(membersAsList); - } - return result; - }); - }).Unwrap(); - } - internal IEnumerable Concat(T single, IEnumerable collection, string exString = null) - { - List asList = null; - if (collection == null) - { - collection = new List(); - } - asList = collection.ToList(); - if (asList.Count == 0 && single == null) - { - exString = exString ?? "can not cancat a collection with a null value."; - throw new ArgumentNullException(exString); - } - asList.Add(single); - return asList; - } - - #region Join - /// - /// 当前用户加入到目标的对话中 - /// - /// 目标对话 - /// - public Task JoinAsync(AVIMConversation conversation) - { - return this.OperateMembersAsync(conversation, "add", this.ClientId); - } - #endregion - - #region Invite - /// - /// 直接将其他人加入到目标对话 - /// 被操作的人会在客户端会触发 OnInvited 事件,而已经存在于对话的用户会触发 OnMembersJoined 事件 - /// - /// 目标对话 - /// 单个的 Client Id - /// Client Id 集合 - /// - public Task InviteAsync(AVIMConversation conversation, string member = null, IEnumerable members = null) - { - return this.OperateMembersAsync(conversation, "add", member, members); - } - #endregion - - #region Left - /// - /// 当前 Client 离开目标对话 - /// 可以理解为是 QQ 群的退群操作 - /// - /// - /// 目标对话 - /// - [Obsolete("use LeaveAsync instead.")] - public Task LeftAsync(AVIMConversation conversation) - { - return this.OperateMembersAsync(conversation, "remove", this.ClientId); - } - - /// - /// Leaves the conversation async. - /// - /// The async. - /// Conversation. - public Task LeaveAsync(AVIMConversation conversation) - { - return this.OperateMembersAsync(conversation, "remove", this.ClientId); - } - #endregion - - #region Kick - /// - /// 从目标对话中剔除成员 - /// - /// 目标对话 - /// 被剔除的单个成员 - /// 被剔除的成员列表 - /// - public Task KickAsync(AVIMConversation conversation, string member = null, IEnumerable members = null) - { - return this.OperateMembersAsync(conversation, "remove", member, members); - } - #endregion - - #endregion - - #region Query && Message history && ack - - /// - /// Get conversation query. - /// - /// - public AVIMConversationQuery GetQuery() - { - return GetConversationQuery(); - } - - /// - /// Get conversation query. - /// - /// The conversation query. - public AVIMConversationQuery GetConversationQuery() - { - return new AVIMConversationQuery(this); - } - - #region load message history - - /// - /// 查询目标对话的历史消息 - /// 不支持聊天室(暂态对话) - /// - /// 目标对话 - /// 从 beforeMessageId 开始向前查询(和 beforeTimeStampPoint 共同使用,为防止某毫秒时刻有重复消息) - /// 截止到某个 afterMessageId (不包含) - /// 从 beforeTimeStampPoint 开始向前查询 - /// 拉取截止到 afterTimeStampPoint 时间戳(不包含) - /// 查询方向,默认是 1,如果是 1 表示从新消息往旧消息方向, 0 则相反,其他值无效 - /// 拉取消息条数,默认值 20 条,可设置为 1 - 1000 之间的任意整数 - /// - public Task> QueryMessageAsync(AVIMConversation conversation, - string beforeMessageId = null, - string afterMessageId = null, - DateTime? beforeTimeStampPoint = null, - DateTime? afterTimeStampPoint = null, - int direction = 1, - int limit = 20) - where T : IAVIMMessage - { - var maxLimit = 1000; - var actualLimit = limit > maxLimit ? maxLimit : limit; - var logsCmd = new AVIMCommand() - .Command("logs") - .Argument("cid", conversation.ConversationId) - .Argument("l", actualLimit); - - if (beforeMessageId != null) - { - logsCmd = logsCmd.Argument("mid", beforeMessageId); - } - - if (afterMessageId != null) - { - logsCmd = logsCmd.Argument("tmid", afterMessageId); - } - - if (beforeTimeStampPoint != null && beforeTimeStampPoint.Value != DateTime.MinValue) - { - logsCmd = logsCmd.Argument("t", beforeTimeStampPoint.Value.ToUnixTimeStamp()); - } - - if (afterTimeStampPoint != null && afterTimeStampPoint.Value != DateTime.MinValue) - { - logsCmd = logsCmd.Argument("tt", afterTimeStampPoint.Value.ToUnixTimeStamp()); - } - - if (direction == 0) - { - logsCmd = logsCmd.Argument("direction", "NEW"); - } - - var subMessageType = typeof(T); - var subTypeInteger = subMessageType == typeof(AVIMTypedMessage) ? 0 : FreeStyleMessageClassInfo.GetTypedInteger(subMessageType.GetTypeInfo()); - - if (subTypeInteger != 0) - { - logsCmd = logsCmd.Argument("lctype", subTypeInteger); - } - - return this.RunCommandAsync(logsCmd).OnSuccess(t => - { - var rtn = new List(); - var result = t.Result.Item2; - var logs = result["logs"] as List; - if (logs != null) - { - foreach (var log in logs) - { - var logMap = log as IDictionary; - if (logMap != null) - { - var msgStr = logMap["data"].ToString(); - var messageObj = AVRealtime.FreeStyleMessageClassingController.Instantiate(msgStr, logMap); - messageObj.ConversationId = conversation.ConversationId; - rtn.Add(messageObj); - } - } - } - - conversation.OnMessageLoad(rtn); - - return rtn.AsEnumerable().OfType(); - }); - } - #endregion - - - //public Task MarkAsReadAsync(string conversationId = null, string messageId = null, AVIMConversation conversation = null, AVIMMessage message = null) - //{ - // var msgId = messageId != null ? messageId : message.Id; - // var convId = conversationId != null ? conversationId : conversation.ConversationId; - // if (convId == null && msgId == null) throw new ArgumentNullException("发送已读回执的时候,必须指定 conversation id 或者 message id"); - // lock (mutex) - // { - // var ackCommand = new AckCommand() - // .ReadAck().MessageId(msgId) - // .ConversationId(convId) - // .PeerId(this.ClientId); - - // return this.RunCommandAsync(ackCommand); - // } - //} - #region 查询对话中对方的接收状态,也就是已读回执 - private Task> FetchAllReceiptTimestampsAsync(string targetClientId = null, string conversationId = null, AVIMConversation conversation = null, bool queryAllMembers = false) - { - var convId = conversationId != null ? conversationId : conversation.ConversationId; - if (convId == null) throw new ArgumentNullException("conversationId 和 conversation 不可以同时为 null"); - - var cmd = new ConversationCommand().ConversationId(convId) - .TargetClientId(targetClientId) - .QueryAllMembers(queryAllMembers) - .Option("max-read") - .PeerId(clientId); - - return this.RunCommandAsync(cmd).OnSuccess(t => - { - var result = t.Result; - long maxReadTimestamp = -1; - long maxAckTimestamp = -1; - - if (result.Item2.ContainsKey("maxReadTimestamp")) - { - long.TryParse(result.Item2["maxReadTimestamp"].ToString(), out maxReadTimestamp); - } - if (result.Item2.ContainsKey("maxAckTimestamp")) - { - long.TryParse(result.Item2["maxAckTimestamp"].ToString(), out maxAckTimestamp); - } - return new Tuple(maxAckTimestamp, maxReadTimestamp); - - }); - } - #endregion - - #region 查询对方是否在线 - /// - /// 查询对方 client Id 是否在线 - /// - /// 单个 client Id - /// 多个 client Id 集合 - /// - public Task>> PingAsync(string targetClientId = null, IEnumerable targetClientIds = null) - { - List queryIds = null; - if (targetClientIds != null) queryIds = targetClientIds.ToList(); - if (queryIds == null && string.IsNullOrEmpty(targetClientId)) throw new ArgumentNullException("必须查询至少一个 client id 的状态,targetClientId 和 targetClientIds 不可以同时为空"); - queryIds.Add(targetClientId); - - var cmd = new SessionCommand() - .SessionPeerIds(queryIds) - .Option("query"); - - return this.RunCommandAsync(cmd).OnSuccess(t => - { - var result = t.Result; - List> rtn = new List>(); - var onlineSessionPeerIds = AVDecoder.Instance.DecodeList(result.Item2["onlineSessionPeerIds"]); - foreach (var peerId in targetClientIds) - { - rtn.Add(new Tuple(peerId, onlineSessionPeerIds.Contains(peerId))); - } - return rtn.AsEnumerable(); - }); - } - #endregion - #region 获取暂态对话在线人数 - /// - /// 获取暂态对话(聊天室)在线人数,依赖缓存,并不一定 100% 与真实数据一致。 - /// - /// - /// - public Task CountOnlineClientsAsync(string chatroomId) - { - var command = new AVCommand(relativeUri: "rtm/transient_group/onlines?gid=" + chatroomId, method: "GET", - sessionToken: null, - headers: null, - data: null); - - return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => - { - var result = t.Result.Item2; - if (result.ContainsKey("result")) - { - return int.Parse(result["result"].ToString()); - } - return -1; - }); - } - #endregion - #endregion - - #region mark as read - - /// - /// - /// - /// - /// - /// - /// - public Task ReadAsync(AVIMConversation conversation, IAVIMMessage message = null, DateTime? readAt = null) - { - var convRead = new ReadCommand.ConvRead() - { - ConvId = conversation.ConversationId, - }; - - if (message != null) - { - convRead.MessageId = message.Id; - convRead.Timestamp = message.ServerTimestamp; - } - - if (readAt != null && readAt.Value != DateTime.MinValue) - { - convRead.Timestamp = readAt.Value.ToUnixTimeStamp(); - } - - var readCmd = new ReadCommand().Conv(convRead).PeerId(this.ClientId); - - this.RunCommandAsync(readCmd); - - return Task.FromResult(true); - } - - /// - /// mark the conversation as read with conversation id. - /// - /// conversation id - /// - public Task ReadAsync(string conversationId) - { - var conv = AVIMConversation.CreateWithoutData(conversationId, this); - return this.ReadAsync(conv); - } - - /// - /// mark all conversations as read. - /// - /// - public Task ReadAllAsync() - { - var cids = ConversationUnreadListener.FindAllConvIds(); - var readCmd = new ReadCommand().ConvIds(cids).PeerId(this.ClientId); - return this.RunCommandAsync(readCmd); - } - #endregion - - #region recall & modify - - /// - /// Recalls the async. - /// - /// The async. - /// Message. - public Task RecallAsync(IAVIMMessage message) - { - var tcs = new TaskCompletionSource(); - var patchCmd = new PatchCommand().Recall(message); - RunCommandAsync(patchCmd) - .OnSuccess(t => { - var recalledMsg = new AVIMRecalledMessage(); - AVIMMessage.CopyMetaData(message, recalledMsg); - tcs.SetResult(recalledMsg); - }); - return tcs.Task; - } - - /// - /// Modifies the aysnc. - /// - /// The aysnc. - /// 要修改的消息对象 - /// 新的消息对象 - public Task UpdateAsync(IAVIMMessage oldMessage, IAVIMMessage newMessage) - { - var tcs = new TaskCompletionSource(); - var patchCmd = new PatchCommand().Modify(oldMessage, newMessage); - this.RunCommandAsync(patchCmd) - .OnSuccess(t => { - // 从旧消息对象中拷贝数据 - AVIMMessage.CopyMetaData(oldMessage, newMessage); - // 获取更新时间戳 - var response = t.Result.Item2; - if (response.TryGetValue("lastPatchTime", out object updatedAtObj) && - long.TryParse(updatedAtObj.ToString(), out long updatedAt)) { - newMessage.UpdatedAt = updatedAt; - } - tcs.SetResult(newMessage); - }); - return tcs.Task; - } - - internal EventHandler m_OnMessageRecalled; - /// - /// Occurs when on message recalled. - /// - public event EventHandler OnMessageRecalled - { - add - { - this.m_OnMessageRecalled += value; - } - remove - { - this.m_OnMessageRecalled -= value; - } - } - internal EventHandler m_OnMessageUpdated; - /// - /// Occurs when on message modified. - /// - public event EventHandler OnMessageUpdated - { - add - { - this.m_OnMessageUpdated += value; - } - remove - { - this.m_OnMessageUpdated -= value; - } - } - - #endregion - - #region log out - /// - /// 退出登录或者切换账号 - /// - /// - public Task CloseAsync() - { - var cmd = new SessionCommand().Option("close"); - return this.RunCommandAsync(cmd).ContinueWith(t => - { - m_OnSessionClosed(this, null); - }); - } - #endregion - - /// - /// Run command async. - /// - /// The command async. - /// Command. - public Task>> RunCommandAsync(AVIMCommand command) - { - command.PeerId(this.ClientId); - return this.LinkedRealtime.RunCommandAsync(command); - } - - /// - /// Run command. - /// - /// Command. - public void RunCommand(AVIMCommand command) - { - command.PeerId(this.ClientId); - this.LinkedRealtime.RunCommand(command); - } - } - - /// - /// AVIMClient extensions. - /// - public static class AVIMClientExtensions - { - /// - /// Create conversation async. - /// - /// The conversation async. - /// Client. - /// Members. - public static Task CreateConversationAsync(this AVIMClient client, IEnumerable members) - { - return client.CreateConversationAsync(members: members); - } - - public static Task CreateConversationAsync(this AVIMClient client, IEnumerable members, string conversationName) - { - return client.CreateConversationAsync(members: members, name: conversationName); - } - - /// - /// Get conversation. - /// - /// The conversation. - /// Client. - /// Conversation identifier. - public static AVIMConversation GetConversation(this AVIMClient client, string conversationId) - { - return AVIMConversation.CreateWithoutData(conversationId, client); - } - - /// - /// Join conversation async. - /// - /// The async. - /// Client. - /// Conversation identifier. - public static Task JoinAsync(this AVIMClient client, string conversationId) - { - var conversation = client.GetConversation(conversationId); - return client.JoinAsync(conversation); - } - - /// - /// Leave conversation async. - /// - /// The async. - /// Client. - /// Conversation identifier. - public static Task LeaveAsync(this AVIMClient client, string conversationId) - { - var conversation = client.GetConversation(conversationId); - return client.LeaveAsync(conversation); - } - - /// - /// Query messages. - /// - /// The message async. - /// Client. - /// Conversation. - /// Before message identifier. - /// After message identifier. - /// Before time stamp point. - /// After time stamp point. - /// Direction. - /// Limit. - public static Task> QueryMessageAsync(this AVIMClient client, - AVIMConversation conversation, - string beforeMessageId = null, - string afterMessageId = null, - DateTime? beforeTimeStampPoint = null, - DateTime? afterTimeStampPoint = null, - int direction = 1, - int limit = 20) - { - return client.QueryMessageAsync(conversation, - beforeMessageId, - afterMessageId, - beforeTimeStampPoint, - afterTimeStampPoint, - direction, - limit); - } - - /// - /// Get the chat room query. - /// - /// The chat room query. - /// Client. - public static AVIMConversationQuery GetChatRoomQuery(this AVIMClient client) - { - return client.GetQuery().WhereEqualTo("tr", true); - } - } -} diff --git a/RTM/Source/Public/AVIMConversation.cs b/RTM/Source/Public/AVIMConversation.cs deleted file mode 100644 index 1bdf1cf..0000000 --- a/RTM/Source/Public/AVIMConversation.cs +++ /dev/null @@ -1,1545 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using LeanCloud.Realtime.Internal; -using LeanCloud; -using LeanCloud.Storage.Internal; -using System.Collections; -using System.IO; - -namespace LeanCloud.Realtime -{ - /// - /// 对话 - /// - public class AVIMConversation : IEnumerable>, IAVObject - { - private DateTime? updatedAt; - - private DateTime? createdAt; - - private DateTime? lastMessageAt; - - internal DateTime? expiredAt; - - private string name; - - private AVObject convState; - - internal readonly Object mutex = new Object(); - //private readonly IDictionary estimatedData = new Dictionary(); - - internal AVIMClient _currentClient; - - IEnumerator> IEnumerable>.GetEnumerator() - { - lock (mutex) - { - return ((IEnumerable>)convState).GetEnumerator(); - } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - lock (mutex) - { - return ((IEnumerable>)convState).GetEnumerator(); - } - } - - virtual public object this[string key] - { - get - { - return convState[key]; - } - set - { - convState[key] = value; - } - } - public ICollection Keys - { - get - { - lock (mutex) - { - return convState.Keys; - } - } - } - public T Get(string key) - { - return this.convState.Get(key); - } - public bool ContainsKey(string key) - { - return this.convState.ContainsKey(key); - } - - internal IDictionary EncodeAttributes() - { - var currentOperations = convState.StartSave(); - var jsonToSave = AVObject.ToJSONObjectForSaving(currentOperations); - return jsonToSave; - } - - internal void MergeFromPushServer(IDictionary json) - { - if (json.Keys.Contains("cdate")) - { - createdAt = DateTime.Parse(json["cdate"].ToString()); - updatedAt = DateTime.Parse(json["cdate"].ToString()); - json.Remove("cdate"); - } - if (json.Keys.Contains("lm")) - { - var ts = long.Parse(json["lm"].ToString()); - updatedAt = ts.ToDateTime(); - lastMessageAt = ts.ToDateTime(); - json.Remove("lm"); - } - if (json.Keys.Contains("c")) - { - Creator = json["c"].ToString(); - json.Remove("c"); - } - if (json.Keys.Contains("m")) - { - MemberIds = json["m"] as IList; - json.Remove("m"); - } - if (json.Keys.Contains("mu")) - { - MuteMemberIds = json["mu"] as IList; - json.Remove("mu"); - } - if (json.Keys.Contains("tr")) - { - IsTransient = bool.Parse(json["tr"].ToString()); - json.Remove("tr"); - } - if (json.Keys.Contains("sys")) - { - IsSystem = bool.Parse(json["sys"].ToString()); - json.Remove("sys"); - } - if (json.Keys.Contains("cid")) - { - ConversationId = json["cid"].ToString(); - json.Remove("cid"); - } - - if (json.Keys.Contains("name")) - { - Name = json["name"].ToString(); - json.Remove("name"); - } - } - - /// - /// 当前的AVIMClient,一个对话理论上只存在一个AVIMClient。 - /// - public AVIMClient CurrentClient - { - get - { - if (_currentClient == null) throw new NullReferenceException("当前对话没有关联有效的 AVIMClient。"); - return _currentClient; - } - //set - //{ - // _currentClient = value; - //} - } - /// - /// 对话的唯一ID - /// - public string ConversationId { get; internal set; } - - /// - /// 对话在全局的唯一的名字 - /// - public string Name - { - get - { - if (convState.ContainsKey("name")) - { - name = this.convState.Get("name"); - } - return name; - } - set - { - if (value == null) - this["name"] = ""; - else - { - this["name"] = value; - } - } - } - - /// - /// 对话中存在的 Client 的 ClientId 列表 - /// - public IEnumerable MemberIds { get; internal set; } - - /// - /// 对该对话静音的成员列表 - /// - /// 对该对话设置了静音的成员,将不会收到离线消息的推送。 - /// - /// - public IEnumerable MuteMemberIds { get; internal set; } - - /// - /// 对话的创建者 - /// - public string Creator { get; private set; } - - /// - /// 是否为聊天室 - /// - public bool IsTransient { get; internal set; } - - /// - /// 是否系统对话 - /// - public bool IsSystem { get; internal set; } - - /// - /// 是否是唯一对话 - /// - public bool IsUnique { get; internal set; } - - /// - /// 对话是否为虚拟对话 - /// - public bool IsTemporary { get; internal set; } - - /// - /// 对话创建的时间 - /// - public DateTime? CreatedAt - { - get - { - DateTime? nullable; - lock (this.mutex) - { - nullable = this.createdAt; - } - return nullable; - } - private set - { - lock (this.mutex) - { - this.createdAt = value; - } - } - } - - /// - /// 对话更新的时间 - /// - public DateTime? UpdatedAt - { - get - { - DateTime? nullable; - lock (this.mutex) - { - nullable = this.updatedAt; - } - return nullable; - } - private set - { - lock (this.mutex) - { - this.updatedAt = value; - } - } - } - - /// - /// 对话中最后一条消息的时间,可以用此判断对话的最后活跃时间 - /// - public DateTime? LastMessageAt - { - get - { - DateTime? nullable; - lock (this.mutex) - { - nullable = this.lastMessageAt; - } - return nullable; - } - private set - { - lock (this.mutex) - { - this.lastMessageAt = value; - } - } - } - - /// - /// 已知 id,在本地构建一个 AVIMConversation 对象 - /// - public AVIMConversation(string id) - : this(id, null) - { - - } - - /// - /// 已知 id 在本地构建一个对话 - /// - /// 对话 id - /// AVIMClient 实例,必须是登陆成功的 - public AVIMConversation(string id, AVIMClient client) : this(client) - { - this.ConversationId = id; - } - - internal AVIMConversation(AVIMClient client) - { - this._currentClient = client; - this.CurrentClient.OnMessageReceived += CurrentClient_OnMessageReceived; - } - - /// - /// AVIMConversation Build 驱动器 - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - internal AVIMConversation(AVIMConversation source = null, - string name = null, - string creator = null, - IEnumerable members = null, - IEnumerable muteMembers = null, - bool isTransient = false, - bool isSystem = false, - IEnumerable> attributes = null, - AVObject state = null, - bool isUnique = true, - bool isTemporary = false, - int ttl = 86400, - AVIMClient client = null) : - this(client) - { - convState = source != null ? source.convState : new AVObject("_Conversation"); - - - this.Name = source?.Name; - this.MemberIds = source?.MemberIds; - this.Creator = source?.Creator; - this.MuteMemberIds = source?.MuteMemberIds; - - if (!string.IsNullOrEmpty(name)) - { - this.Name = name; - } - if (!string.IsNullOrEmpty(creator)) - { - this.Creator = creator; - } - if (members != null) - { - this.MemberIds = members.ToList(); - } - if (muteMembers != null) - { - this.MuteMemberIds = muteMembers.ToList(); - } - - this.IsTransient = isTransient; - this.IsSystem = isSystem; - this.IsUnique = isUnique; - this.IsTemporary = isTemporary; - this.expiredAt = DateTime.Now + new TimeSpan(0, 0, ttl); - - if (state != null) - { - convState = state; - this.ConversationId = state.ObjectId; - this.CreatedAt = state.CreatedAt; - this.UpdatedAt = state.UpdatedAt; - this.MergeMagicFields(state.ToDictionary(x => x.Key, x => x.Value)); - } - - if (attributes != null) - { - this.MergeMagicFields(attributes.ToDictionary(x => x.Key, x => x.Value)); - } - } - - /// - /// 从本地构建一个对话 - /// - /// 对话的 objectId - /// - /// - public static AVIMConversation CreateWithoutData(string convId, AVIMClient client) - { - return new AVIMConversation(client) - { - ConversationId = convId, - }; - } - - /// - /// - /// - /// - /// - /// - public static AVIMConversation CreateWithData(IEnumerable> magicFields, AVIMClient client) - { - if (magicFields is AVObject) - { - return new AVIMConversation(state: (AVObject)magicFields, client: client); - } - return new AVIMConversation(attributes: magicFields, client: client); - } - - #region save to cloud - /// - /// 将修改保存到云端 - /// - /// - public Task SaveAsync() - { - var cmd = new ConversationCommand() - .Generate(this); - - var convCmd = cmd.Option("update") - .PeerId(this.CurrentClient.ClientId); - - return this.CurrentClient.RunCommandAsync(convCmd); - } - #endregion - - #region send message - /// - /// 向该对话发送消息。 - /// - /// 消息体 - /// 是否需要送达回执 - /// 是否是暂态消息,暂态消息不返回送达回执(ack),不保留离线消息,不触发离线推送 - /// 消息等级,默认是1,可选值还有 2 ,3 - /// 标记该消息是否为下线通知消息 - /// 如果消息的接收者已经下线了,这个字段的内容就会被离线推送到接收者 - /// 例如,一张图片消息的离线消息内容可以类似于:[您收到一条图片消息,点击查看] 这样的推送内容,参照微信的做法 - /// - /// - public Task SendMessageAsync(IAVIMMessage avMessage, - bool receipt = true, - bool transient = false, - int priority = 1, - bool will = false, - IDictionary pushData = null) - { - return this.SendMessageAsync(avMessage, new AVIMSendOptions() - { - Receipt = receipt, - Transient = transient, - Priority = priority, - Will = will, - PushData = pushData - }); - } - - /// - /// 发送消息 - /// - /// 消息体 - /// 消息的发送选项,包含了一些特殊的标记 - /// - public Task SendMessageAsync(IAVIMMessage avMessage, AVIMSendOptions options) - { - if (this.CurrentClient == null) throw new Exception("当前对话未指定有效 AVIMClient,无法发送消息。"); - return this.CurrentClient.SendMessageAsync(this, avMessage, options); - } - #endregion - - #region recall message - - #endregion - - #region message listener and event notify - - /// - /// Registers the listener. - /// - /// Listener. - public void RegisterListener(IAVIMListener listener) - { - this.CurrentClient.RegisterListener(listener, this.ConversationIdHook); - } - - internal bool ConversationIdHook(AVIMNotice notice) - { - if (!notice.RawData.ContainsKey("cid")) return false; - return notice.RawData["cid"].ToString() == this.ConversationId; - } - #endregion - - #region mute && unmute - /// - /// 当前用户针对对话做静音操作 - /// - /// - public Task MuteAsync() - { - return this.CurrentClient.MuteConversationAsync(this); - } - /// - /// 当前用户取消对话的静音,恢复该对话的离线消息推送 - /// - /// - public Task UnmuteAsync() - { - return this.CurrentClient.UnmuteConversationAsync(this); - } - #endregion - - #region 成员操作相关接口 - - /// - /// Joins the async. - /// - /// The async. - public Task JoinAsync() - { - return AddMembersAsync(CurrentClient.ClientId); - } - - - /// - /// Adds the members async. - /// - /// The members async. - /// Client identifier. - /// Client identifiers. - public Task AddMembersAsync(string clientId = null, IEnumerable clientIds = null) - { - return this.CurrentClient.InviteAsync(this, clientId, clientIds); - } - - /// - /// Removes the members async. - /// - /// The members async. - /// Client identifier. - /// Client identifiers. - public Task RemoveMembersAsync(string clientId = null, IEnumerable clientIds = null) - { - return this.CurrentClient.KickAsync(this, clientId, clientIds); - } - - /// - /// Quits the async. - /// - /// The async. - public Task QuitAsync() - { - return RemoveMembersAsync(CurrentClient.ClientId); - } - #endregion - - #region load message history - /// - /// 获取当前对话的历史消息 - /// 不支持聊天室(暂态对话) - /// - /// 从 beforeMessageId 开始向前查询(和 beforeTimeStampPoint 共同使用,为防止某毫秒时刻有重复消息) - /// 截止到某个 afterMessageId (不包含) - /// 从 beforeTimeStampPoint 开始向前查询 - /// 拉取截止到 afterTimeStampPoint 时间戳(不包含) - /// 查询方向,默认是 1,如果是 1 表示从新消息往旧消息方向, 0 则相反,其他值无效 - /// 获取的消息数量 - /// - public Task> QueryMessageAsync( - string beforeMessageId = null, - string afterMessageId = null, - DateTime? beforeTimeStampPoint = null, - DateTime? afterTimeStampPoint = null, - int direction = 1, - int limit = 20) - where T : IAVIMMessage - { - return this.CurrentClient.QueryMessageAsync(this, beforeMessageId, afterMessageId, beforeTimeStampPoint, afterTimeStampPoint, direction, limit) - .OnSuccess(t => - { - //OnMessageLoad(t.Result); - return t.Result; - }); - } - - /// - /// Gets the message query. - /// - /// The message query. - public AVIMMessageQuery GetMessageQuery() - { - return new AVIMMessageQuery(this); - } - - /// - /// Gets the message pager. - /// - /// The message pager. - public AVIMMessagePager GetMessagePager() - { - return new AVIMMessagePager(this); - } - - #endregion - - #region 字典与对象之间的转换 - internal virtual void MergeMagicFields(IDictionary data) - { - lock (this.mutex) - { - if (data.ContainsKey("objectId")) - { - this.ConversationId = (data["objectId"] as String); - data.Remove("objectId"); - } - if (data.ContainsKey("createdAt")) - { - this.CreatedAt = AVDecoder.ParseDate(data["createdAt"] as string); - data.Remove("createdAt"); - } - if (data.ContainsKey("updatedAt")) - { - this.updatedAt = AVDecoder.ParseDate(data["updatedAt"] as string); - data.Remove("updatedAt"); - } - if (data.ContainsKey("name")) - { - this.Name = (data["name"] as String); - data.Remove("name"); - } - if (data.ContainsKey("lm")) - { - this.LastMessageAt = AVDecoder.Instance.Decode(data["lm"]) as DateTime?; - data.Remove("lm"); - } - if (data.ContainsKey("m")) - { - this.MemberIds = AVDecoder.Instance.DecodeList(data["m"]); - data.Remove("m"); - } - if (data.ContainsKey("mu")) - { - this.MuteMemberIds = AVDecoder.Instance.DecodeList(data["mu"]); - data.Remove("mu"); - } - if (data.ContainsKey("c")) - { - this.Creator = data["c"].ToString(); - data.Remove("c"); - } - if (data.ContainsKey("unique")) - { - if (data["unique"] is bool) - { - this.IsUnique = (bool)data["unique"]; - } - data.Remove("unique"); - } - foreach (var kv in data) - { - this[kv.Key] = kv.Value; - } - } - } - #endregion - - #region SyncStateAsync & unread & mark as read - /// - /// sync state from server.suhc unread state .etc; - /// - /// - public Task SyncStateAsync() - { - lock (mutex) - { - var rtn = new AggregatedState(); - rtn.Unread = GetUnreadStateFromLocal(); - return Task.FromResult(rtn); - } - } - - private UnreadState _unread; - private UnreadState _lastUnreadWhenOpenSession; - public UnreadState Unread - { - get - { - _lastUnreadWhenOpenSession = GetUnreadStateFromLocal(); - - // v.2 协议,只给出上次离线之后的未读消息,本次在线的收到的消息均视为已读 - if (this.CurrentClient.LinkedRealtime.CurrentConfiguration.OfflineMessageStrategy == AVRealtime.OfflineMessageStrategy.UnreadNotice) - { - _unread = _lastUnreadWhenOpenSession; - } - else if (this.CurrentClient.LinkedRealtime.CurrentConfiguration.OfflineMessageStrategy == AVRealtime.OfflineMessageStrategy.UnreadAck) - { - if (_lastUnreadWhenOpenSession == null) _unread = new UnreadState().MergeReceived(this.Received); - else _unread = _lastUnreadWhenOpenSession.MergeReceived(this.Received); - } - - return _unread; - } - - internal set - { - _unread = value; - } - } - - private readonly object receivedMutex = new object(); - public ReceivedState Received - { - get; set; - } - public ReadState Read - { - get; set; - } - - UnreadState GetUnreadStateFromLocal() - { - lock (mutex) - { - var notice = ConversationUnreadListener.Get(this.ConversationId); - if (notice != null) - { - var unreadState = new UnreadState() - { - LastMessage = notice.LastUnreadMessage, - SyncdAt = ConversationUnreadListener.NotifTime, - Count = notice.UnreadCount - }; - return unreadState; - } - - return null; - } - } - - internal void OnMessageLoad(IEnumerable messages) - { - var lastestInCollection = messages.OrderByDescending(m => m.ServerTimestamp).FirstOrDefault(); - if (lastestInCollection != null) - { - if (CurrentClient.CurrentConfiguration.AutoRead) - { - this.ReadAsync(lastestInCollection); - } - } - } - - /// - /// mark this conversation as read - /// - /// - public Task ReadAsync(IAVIMMessage message = null, DateTime? readAt = null) - { - // 标记已读必须至少是从上一次离线产生的最后一条消息开始,否则无法计算 Count - if (_lastUnreadWhenOpenSession != null) - { - if (_lastUnreadWhenOpenSession.LastMessage != null) - { - message = _lastUnreadWhenOpenSession.LastMessage; - } - } - return this.CurrentClient.ReadAsync(this, message, readAt).OnSuccess(t => - { - Received = null; - _lastUnreadWhenOpenSession = null; - Read = new ReadState() - { - ReadAt = readAt != null ? readAt.Value.ToUnixTimeStamp() : 0, - LastMessage = message, - SyncdAt = DateTime.Now.ToUnixTimeStamp() - }; - - }); - } - - /// - /// aggregated state for the conversation - /// - public class AggregatedState - { - /// - /// Unread state - /// - public UnreadState Unread { get; internal set; } - } - - /// - /// UnreadState recoder for the conversation - /// - public class UnreadState - { - /// - /// unread count - /// - public int Count { get; internal set; } - /// - /// last unread message - /// - public IAVIMMessage LastMessage { get; internal set; } - - /// - /// last sync timestamp - /// - public long SyncdAt { get; internal set; } - - internal UnreadState MergeReceived(ReceivedState receivedState) - { - if (receivedState == null) return this; - var count = Count + receivedState.Count; - var lastMessage = this.LastMessage; - if (receivedState.LastMessage != null) - { - lastMessage = receivedState.LastMessage; - } - var syncdAt = this.SyncdAt > receivedState.SyncdAt ? this.SyncdAt : receivedState.SyncdAt; - return new UnreadState() - { - Count = count, - LastMessage = lastMessage, - SyncdAt = syncdAt - }; - } - } - - public class ReceivedState - { - public int Count { get; internal set; } - /// - /// last received message - /// - public IAVIMMessage LastMessage { get; internal set; } - - /// - /// last sync timestamp - /// - public long SyncdAt { get; internal set; } - } - - public class ReadState - { - public long ReadAt { get; set; } - public IAVIMMessage LastMessage { get; internal set; } - public long SyncdAt { get; internal set; } - } - - #endregion - - #region on client message received to update unread - private void CurrentClient_OnMessageReceived(object sender, AVIMMessageEventArgs e) - { - if (this.CurrentClient.CurrentConfiguration.AutoRead) - { - this.ReadAsync(e.Message); - return; - } - lock (receivedMutex) - { - if (this.Received == null) this.Received = new ReceivedState(); - this.Received.Count++; - this.Received.LastMessage = e.Message; - this.Received.SyncdAt = DateTime.Now.ToUnixTimeStamp(); - } - } - #endregion - } - - /// - /// AVIMConversation extensions. - /// - public static class AVIMConversationExtensions - { - - /// - /// Send message async. - /// - /// The async. - /// Conversation. - /// Message. - /// Options. - public static Task SendAsync(this AVIMConversation conversation, IAVIMMessage message, AVIMSendOptions options) - { - return conversation.SendMessageAsync(message, options); - } - - /// - /// Send message async. - /// - /// The async. - /// Conversation. - /// Message. - /// Options. - /// The 1st type parameter. - public static Task SendAsync(this AVIMConversation conversation, T message, AVIMSendOptions options) - where T : IAVIMMessage - { - return conversation.SendMessageAsync(message, options).OnSuccess(t => - { - return (T)t.Result; - }); - } - - /// - /// Send message async. - /// - /// The async. - /// Conversation. - /// Message. - /// The 1st type parameter. - public static Task SendAsync(this AVIMConversation conversation, T message) - where T : IAVIMMessage - { - return conversation.SendMessageAsync(message).OnSuccess(t => - { - return (T)t.Result; - }); - } - - /// - /// Send text message. - /// - /// The text async. - /// Conversation. - /// Text. - public static Task SendTextAsync(this AVIMConversation conversation, string text) - { - return conversation.SendAsync(new AVIMTextMessage(text)); - } - - #region Image messages - - /// - /// Send image message async. - /// - /// The image async. - /// Conversation. - /// URL. - /// Name. - /// Text title. - /// Custom attributes. - public static Task SendImageAsync(this AVIMConversation conversation, string url, string name = null, string textTitle = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(url, name, textTitle, customAttributes); - } - - /// - /// Send image message async. - /// - /// The image async. - /// Conversation. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - public static Task SendImageAsync(this AVIMConversation conversation, string fileName, Stream data, string mimeType = null, string textTitle = null, IDictionary metaData = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(fileName, data, mimeType, textTitle, metaData, customAttributes); - } - - /// - /// Send image message async. - /// - /// The image async. - /// Conversation. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - public static Task SendImageAsync(this AVIMConversation conversation, string fileName, byte[] data, string mimeType = null, string textTitle = null, IDictionary metaData = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(fileName, data, mimeType, textTitle, metaData, customAttributes); - } - #endregion - - #region audio message - - /// - /// Send audio message async. - /// - /// The audio async. - /// Conversation. - /// URL. - /// Name. - /// Text title. - /// Custom attributes. - public static Task SendAudioAsync(this AVIMConversation conversation, string url, string name = null, string textTitle = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(name, url, textTitle, customAttributes); - } - - /// - /// Send audio message async. - /// - /// The audio async. - /// Conversation. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - public static Task SendAudioAsync(this AVIMConversation conversation, string fileName, Stream data, string mimeType = null, string textTitle = null, IDictionary metaData = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(fileName, data, mimeType, textTitle, metaData, customAttributes); - } - - /// - /// Send audio message async. - /// - /// The audio async. - /// Conversation. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - public static Task SendAudioAsync(this AVIMConversation conversation, string fileName, byte[] data, string mimeType = null, string textTitle = null, IDictionary metaData = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(fileName, data, mimeType, textTitle, metaData, customAttributes); - } - #endregion - - #region video message - /// - /// Send video message async. - /// - /// The video async. - /// Conversation. - /// URL. - /// Name. - /// Text title. - /// Custom attributes. - public static Task SendVideoAsync(this AVIMConversation conversation, string url, string name = null, string textTitle = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(name, url, textTitle, customAttributes); - } - /// - /// Send video message async. - /// - /// The video async. - /// Conversation. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - public static Task SendVideoAsync(this AVIMConversation conversation, string fileName, Stream data, string mimeType = null, string textTitle = null, IDictionary metaData = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(fileName, data, mimeType, textTitle, metaData, customAttributes); - } - - /// - /// Send video message async. - /// - /// The video async. - /// Conversation. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - public static Task SendVideoAsync(this AVIMConversation conversation, string fileName, byte[] data, string mimeType = null, string textTitle = null, IDictionary metaData = null, IDictionary customAttributes = null) - { - return conversation.SendFileMessageAsync(fileName, data, mimeType, textTitle, metaData, customAttributes); - } - #endregion - - /// - /// Send file message async. - /// - /// The file message async. - /// Conversation. - /// URL. - /// Name. - /// Text title. - /// Custom attributes. - /// The 1st type parameter. - public static Task SendFileMessageAsync(this AVIMConversation conversation, string url, string name = null, string textTitle = null, IDictionary customAttributes = null) - where T : AVIMFileMessage, new() - { - var fileMessage = AVIMFileMessage.FromUrl(name, url, textTitle, customAttributes); - return conversation.SendAsync(fileMessage); - } - - /// - /// Send file message async. - /// - /// The file message async. - /// Conversation. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - /// The 1st type parameter. - public static Task SendFileMessageAsync(this AVIMConversation conversation, string fileName, Stream data, string mimeType = null, string textTitle = null, IDictionary metaData = null, IDictionary customAttributes = null) - where T : AVIMFileMessage, new() - { - var fileMessage = AVIMFileMessage.FromStream(fileName, data, mimeType, textTitle, metaData, customAttributes); - - return fileMessage.File.SaveAsync().OnSuccess(fileUploaded => - { - return conversation.SendAsync(fileMessage); - }).Unwrap(); - } - - /// - /// Send file message async. - /// - /// The file message async. - /// Conversation. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - /// The 1st type parameter. - public static Task SendFileMessageAsync(this AVIMConversation conversation, string fileName, byte[] data, string mimeType = null, string textTitle = null, IDictionary metaData = null, IDictionary customAttributes = null) - where T : AVIMFileMessage, new() - { - var fileMessage = AVIMFileMessage.FromStream(fileName, new MemoryStream(data), mimeType, textTitle, metaData, customAttributes); - - return conversation.SendFileMessageAsync(fileName, new MemoryStream(data), mimeType, textTitle, metaData, customAttributes); - } - - /// - /// Send location async. - /// - /// The location async. - /// Conversation. - /// Point. - public static Task SendLocationAsync(this AVIMConversation conversation, AVGeoPoint point) - { - var locationMessage = new AVIMLocationMessage(point); - return conversation.SendAsync(locationMessage); - } - - /// - /// Query the message async. - /// - /// The message async. - /// Conversation. - /// Before message identifier. - /// After message identifier. - /// Before time stamp. - /// After time stamp. - /// Direction. - /// Limit. - public static Task> QueryMessageAsync( - this AVIMConversation conversation, - string beforeMessageId = null, - string afterMessageId = null, - long? beforeTimeStamp = null, - long? afterTimeStamp = null, - int direction = 1, - int limit = 20) - { - - return conversation.QueryMessageAsync(beforeMessageId, - afterMessageId, - beforeTimeStamp, - afterTimeStamp, - direction, - limit); - } - - /// - /// Query message with speciafic subclassing type. - /// - /// The message async. - /// Conversation. - /// Before message identifier. - /// After message identifier. - /// Before time stamp. - /// After time stamp. - /// Direction. - /// Limit. - /// The 1st type parameter. - public static Task> QueryMessageAsync( - this AVIMConversation conversation, - string beforeMessageId = null, - string afterMessageId = null, - long? beforeTimeStamp = null, - long? afterTimeStamp = null, - int direction = 1, - int limit = 20) - where T : IAVIMMessage - { - - return conversation.QueryMessageAsync(beforeMessageId, - afterMessageId, - beforeTimeStampPoint: beforeTimeStamp.HasValue ? beforeTimeStamp.Value.ToDateTime() : DateTime.MinValue, - afterTimeStampPoint: afterTimeStamp.HasValue ? afterTimeStamp.Value.ToDateTime() : DateTime.MinValue, - direction: direction, - limit: limit); - } - - /// - /// Query message record before the given message async. - /// - /// The message before async. - /// Conversation. - /// Message. - /// Limit. - public static Task> QueryMessageBeforeAsync( - this AVIMConversation conversation, - IAVIMMessage message, - int limit = 20) - { - return conversation.QueryMessageAsync(beforeMessageId: message.Id, beforeTimeStamp: message.ServerTimestamp, limit: limit); - } - - /// - /// Query message record after the given message async. - /// - /// The message after async. - /// Conversation. - /// Message. - /// Limit. - public static Task> QueryMessageAfterAsync( - this AVIMConversation conversation, - IAVIMMessage message, - int limit = 20) - { - return conversation.QueryMessageAsync(afterMessageId: message.Id, afterTimeStamp: message.ServerTimestamp, limit: limit); - } - - /// - /// Query messages after conversation created. - /// - /// The message after async. - /// Conversation. - /// Limit. - public static Task> QueryMessageFromOldToNewAsync( - this AVIMConversation conversation, - int limit = 20) - { - return conversation.QueryMessageAsync(afterTimeStamp: conversation.CreatedAt.Value.ToUnixTimeStamp(), limit: limit); - } - - - /// - /// Query messages in interval async. - /// - /// The message interval async. - /// Conversation. - /// Start. - /// End. - /// Limit. - public static Task> QueryMessageInIntervalAsync( - this AVIMConversation conversation, - IAVIMMessage start, - IAVIMMessage end, - int limit = 20) - { - return conversation.QueryMessageAsync( - beforeMessageId: end.Id, - beforeTimeStamp: end.ServerTimestamp, - afterMessageId: start.Id, - afterTimeStamp: start.ServerTimestamp, - limit: limit); - } - - /// - /// Recall message async. - /// - /// The async. - /// Conversation. - /// Message. - public static Task RecallAsync(this AVIMConversation conversation, IAVIMMessage message) - { - return conversation.CurrentClient.RecallAsync(message); - } - - /// - /// Modifiy message async. - /// - /// The async. - /// Conversation. - /// 要修改的消息对象 - /// 新的消息对象 - public static Task UpdateAsync(this AVIMConversation conversation, IAVIMMessage oldMessage, IAVIMMessage newMessage) - { - return conversation.CurrentClient.UpdateAsync(oldMessage, newMessage); - } - } - - /// - /// AVIMConversatio builder. - /// - public interface IAVIMConversatioBuilder - { - /// - /// Build this instance. - /// - /// The build. - AVIMConversation Build(); - } - - /// - /// AVIMConversation builder. - /// - public class AVIMConversationBuilder : IAVIMConversatioBuilder - { - /// - /// Gets or sets the client. - /// - /// The client. - public AVIMClient Client { get; internal set; } - private bool isUnique; - private Dictionary properties; - - private string name; - private bool isTransient; - private bool isSystem; - private List members; - - - internal static AVIMConversationBuilder CreateDefaultBuilder() - { - return new AVIMConversationBuilder(); - } - - /// - /// Build this instance. - /// - /// The build. - public AVIMConversation Build() - { - var result = new AVIMConversation( - members: members, - name: name, - isUnique: isUnique, - isSystem: isSystem, - isTransient: isTransient, - client: Client); - - if (properties != null) - { - foreach (var key in properties.Keys) - { - result[key] = properties[key]; - } - } - - return result; - } - - /// - /// Sets the unique. - /// - /// The unique. - /// If set to true toggle. - public AVIMConversationBuilder SetUnique(bool toggle = true) - { - this.isUnique = toggle; - return this; - } - - /// - /// Sets the system. - /// - /// The system. - /// If set to true toggle. - public AVIMConversationBuilder SetSystem(bool toggle = true) - { - this.isSystem = toggle; - return this; - } - - /// - /// Sets the transient. - /// - /// The transient. - /// If set to true toggle. - public AVIMConversationBuilder SetTransient(bool toggle = true) - { - this.isTransient = toggle; - return this; - } - - /// - /// Sets the name. - /// - /// The name. - /// Name. - public AVIMConversationBuilder SetName(string name) - { - this.name = name; - return this; - } - - /// - /// Sets the members. - /// - /// The members. - /// Member client identifiers. - public AVIMConversationBuilder SetMembers(IEnumerable memberClientIds) - { - this.members = memberClientIds.ToList(); - return this; - } - - /// - /// Adds the member. - /// - /// The member. - /// Member client identifier. - public AVIMConversationBuilder AddMember(string memberClientId) - { - return AddMembers(new string[] { memberClientId }); - } - - /// - /// Adds the members. - /// - /// The members. - /// Member client identifiers. - public AVIMConversationBuilder AddMembers(IEnumerable memberClientIds) - { - if (this.members == null) this.members = new List(); - this.members.AddRange(memberClientIds); - return this; - } - - /// - /// Sets the property. - /// - /// The property. - /// Key. - /// Value. - public AVIMConversationBuilder SetProperty(string key, object value) - { - if (this.properties == null) this.properties = new Dictionary(); - this.properties[key] = value; - return this; - } - } - - /// - /// AVIMM essage emitter builder. - /// - public class AVIMMessageEmitterBuilder - { - private AVIMConversation _conversation; - /// - /// Sets the conversation. - /// - /// The conversation. - /// Conversation. - public AVIMMessageEmitterBuilder SetConversation(AVIMConversation conversation) - { - _conversation = conversation; - return this; - } - /// - /// Gets the conversation. - /// - /// The conversation. - public AVIMConversation Conversation - { - get - { - return _conversation; - } - } - - private AVIMSendOptions _sendOptions; - /// - /// Gets the send options. - /// - /// The send options. - public AVIMSendOptions SendOptions - { - get - { - return _sendOptions; - } - } - /// - /// Sets the send options. - /// - /// The send options. - /// Send options. - public AVIMMessageEmitterBuilder SetSendOptions(AVIMSendOptions sendOptions) - { - _sendOptions = sendOptions; - return this; - } - - private IAVIMMessage _message; - /// - /// Gets the message. - /// - /// The message. - public IAVIMMessage Message - { - get - { - return _message; - } - } - /// - /// Sets the message. - /// - /// The message. - /// Message. - public AVIMMessageEmitterBuilder SetMessage(IAVIMMessage message) - { - _message = message; - return this; - } - - /// - /// Send async. - /// - /// The async. - public Task SendAsync() - { - return this.Conversation.SendAsync(this.Message, this.SendOptions); - } - } -} diff --git a/RTM/Source/Public/AVIMConversationQuery.cs b/RTM/Source/Public/AVIMConversationQuery.cs deleted file mode 100644 index cbb0f5f..0000000 --- a/RTM/Source/Public/AVIMConversationQuery.cs +++ /dev/null @@ -1,181 +0,0 @@ -using LeanCloud.Realtime.Internal; -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// 对话查询类 - /// - public class AVIMConversationQuery : AVQueryPair, IAVQuery - { - internal AVIMClient CurrentClient { get; set; } - internal AVIMConversationQuery(AVIMClient _currentClient) - : base() - { - CurrentClient = _currentClient; - } - - bool compact; - bool withLastMessageRefreshed; - - private AVIMConversationQuery(AVIMConversationQuery source, - IDictionary where = null, - IEnumerable replacementOrderBy = null, - IEnumerable thenBy = null, - int? skip = null, - int? limit = null, - IEnumerable includes = null, - IEnumerable selectedKeys = null, - String redirectClassNameForKey = null) - : base(source, where, replacementOrderBy, thenBy, skip, limit, includes, selectedKeys, redirectClassNameForKey) - { - - } - - /// - /// Creates the instance. - /// - /// The instance. - /// Where. - /// Replacement order by. - /// Then by. - /// Skip. - /// Limit. - /// Includes. - /// Selected keys. - /// Redirect class name for key. - public override AVIMConversationQuery CreateInstance( - IDictionary where = null, - IEnumerable replacementOrderBy = null, - IEnumerable thenBy = null, - int? skip = null, - int? limit = null, - IEnumerable includes = null, - IEnumerable selectedKeys = null, - String redirectClassNameForKey = null) - { - var rtn = new AVIMConversationQuery(this, where, replacementOrderBy, thenBy, skip, limit, includes); - rtn.CurrentClient = this.CurrentClient; - rtn.compact = this.compact; - rtn.withLastMessageRefreshed = this.withLastMessageRefreshed; - return rtn; - } - - /// - /// Withs the last message refreshed. - /// - /// The last message refreshed. - /// If set to true enabled. - public AVIMConversationQuery WithLastMessageRefreshed(bool enabled) - { - this.withLastMessageRefreshed = enabled; - return this; - } - - public AVIMConversationQuery Compact(bool enabled) - { - this.compact = enabled; - return this; - } - - - internal ConversationCommand GenerateQueryCommand() - { - var cmd = new ConversationCommand(); - - var queryParameters = this.BuildParameters(false); - if (queryParameters != null) - { - if (queryParameters.Keys.Contains("where")) - cmd.Where(queryParameters["where"]); - - if (queryParameters.Keys.Contains("skip")) - cmd.Skip(int.Parse(queryParameters["skip"].ToString())); - - if (queryParameters.Keys.Contains("limit")) - cmd.Limit(int.Parse(queryParameters["limit"].ToString())); - - if (queryParameters.Keys.Contains("sort")) - cmd.Sort(queryParameters["order"].ToString()); - } - - return cmd; - } - - public override Task CountAsync(CancellationToken cancellationToken) - { - var convCmd = this.GenerateQueryCommand(); - convCmd.Count(); - convCmd.Limit(0); - var cmd = convCmd.Option("query"); - return CurrentClient.RunCommandAsync(convCmd).OnSuccess(t => - { - var result = t.Result.Item2; - - if (result.ContainsKey("count")) - { - return int.Parse(result["count"].ToString()); - } - return 0; - }); - } - - - /// - /// 查找符合条件的对话 - /// - /// - /// - public override Task> FindAsync(CancellationToken cancellationToken) - { - var convCmd = this.GenerateQueryCommand().Option("query"); - return CurrentClient.RunCommandAsync(convCmd).OnSuccess(t => - { - var result = t.Result.Item2; - - IList rtn = new List(); - var conList = result["results"] as IList; - if (conList != null) - { - foreach (var c in conList) - { - var cData = c as IDictionary; - if (cData != null) - { - var con = AVIMConversation.CreateWithData(cData, CurrentClient); - rtn.Add(con); - } - } - } - return rtn.AsEnumerable(); - }); - } - - public override Task FirstAsync(CancellationToken cancellationToken) - { - return this.FirstOrDefaultAsync(); - } - - public override Task FirstOrDefaultAsync(CancellationToken cancellationToken) - { - var firstQuery = this.Limit(1); - return firstQuery.FindAsync().OnSuccess(t => - { - return t.Result.FirstOrDefault(); - }); - } - - public override Task GetAsync(string objectId, CancellationToken cancellationToken) - { - var idQuery = this.WhereEqualTo("objectId", objectId); - return idQuery.FirstAsync(); - } - } - -} diff --git a/RTM/Source/Public/AVIMEnumerator.cs b/RTM/Source/Public/AVIMEnumerator.cs deleted file mode 100644 index d9368bc..0000000 --- a/RTM/Source/Public/AVIMEnumerator.cs +++ /dev/null @@ -1,248 +0,0 @@ -using LeanCloud.Storage.Internal; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using LeanCloud.Realtime.Internal; - -namespace LeanCloud.Realtime -{ - - /// - /// AVIMM essage pager. - /// - public class AVIMMessagePager - { - /// - /// Gets the query. - /// - /// The query. - public AVIMMessageQuery Query { get; private set; } - - /// - /// Gets the size of the page. - /// - /// The size of the page. - public int PageSize - { - get - { - return Query.Limit; - } - - private set - { - Query.Limit = value; - } - } - - /// - /// Gets the current message identifier flag. - /// - /// The current message identifier flag. - public string CurrentMessageIdFlag - { - get - { - return Query.StartMessageId; - } - private set - { - Query.StartMessageId = value; - } - } - - /// - /// Gets the current date time flag. - /// - /// The current date time flag. - public DateTime CurrentDateTimeFlag - { - get - { - return Query.From; - } - private set - { - Query.From = value; - } - } - - internal AVIMMessagePager() - { - - } - - /// - /// Initializes a new instance of the class. - /// - /// Conversation. - public AVIMMessagePager(AVIMConversation conversation) - : this() - { - Query = conversation.GetMessageQuery(); - PageSize = 20; - CurrentDateTimeFlag = DateTime.Now; - } - - /// - /// Sets the size of the page. - /// - /// The page size. - /// Page size. - public AVIMMessagePager SetPageSize(int pageSize) - { - PageSize = pageSize; - return this; - } - - /// - /// Previouses the async. - /// - /// The async. - public Task> PreviousAsync() - { - return Query.FindAsync().OnSuccess(t => - { - var headerMessage = t.Result.FirstOrDefault(); - if (headerMessage != null) - { - CurrentMessageIdFlag = headerMessage.Id; - CurrentDateTimeFlag = headerMessage.ServerTimestamp.ToDateTime(); - } - return t.Result; - }); - } - - /// - /// from previous to lastest. - /// - /// - public Task> NextAsync() - { - return Query.ReverseFindAsync().OnSuccess(t => - { - var tailMessage = t.Result.LastOrDefault(); - if (tailMessage != null) - { - CurrentMessageIdFlag = tailMessage.Id; - CurrentDateTimeFlag = tailMessage.ServerTimestamp.ToDateTime(); - } - return t.Result; - }); - } - } - - /// - /// history message interator. - /// - public class AVIMMessageQuery - { - /// - /// Gets or sets the convsersation. - /// - /// The convsersation. - public AVIMConversation Convsersation { get; set; } - /// - /// Gets or sets the limit. - /// - /// The limit. - public int Limit { get; set; } - /// - /// Gets or sets from. - /// - /// From. - public DateTime From { get; set; } - /// - /// Gets or sets to. - /// - /// To. - public DateTime To { get; set; } - /// - /// Gets or sets the end message identifier. - /// - /// The end message identifier. - public string EndMessageId { get; set; } - /// - /// Gets or sets the start message identifier. - /// - /// The start message identifier. - public string StartMessageId { get; set; } - - - internal AVIMMessageQuery() - { - Limit = 20; - From = DateTime.Now; - } - - /// - /// Initializes a new instance of the class. - /// - /// Conversation. - public AVIMMessageQuery(AVIMConversation conversation) - : this() - { - Convsersation = conversation; - } - - /// - /// Sets the limit. - /// - /// The limit. - /// Limit. - public AVIMMessageQuery SetLimit(int limit) - { - Limit = limit; - return this; - } - - /// - /// from lastest to previous. - /// - /// - public Task> FindAsync() - { - return FindAsync(); - } - - /// - /// from lastest to previous. - /// - /// - public Task> ReverseFindAsync() - { - return ReverseFindAsync(); - } - - /// - /// Finds the async. - /// - /// The async. - /// set direction to reverse,it means query direct is from old to new. - /// The 1st type parameter. - public Task> FindAsync(bool reverse = false) - where T : IAVIMMessage - { - return Convsersation.QueryMessageAsync( - beforeTimeStampPoint: From, - afterTimeStampPoint: To, - limit: Limit, - afterMessageId: EndMessageId, - beforeMessageId: StartMessageId, - direction: reverse ? 0 : 1); - } - - /// - /// from previous to lastest. - /// - /// - public Task> ReverseFindAsync() - where T : IAVIMMessage - { - return FindAsync(true); - } - } -} diff --git a/RTM/Source/Public/AVIMEventArgs.cs b/RTM/Source/Public/AVIMEventArgs.cs deleted file mode 100644 index 2b91b23..0000000 --- a/RTM/Source/Public/AVIMEventArgs.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace LeanCloud.Realtime -{ - /// - /// - /// - public class AVIMEventArgs : EventArgs - { - public AVIMEventArgs() - { - - } - public AVIMException.ErrorCode ErrorCode { get; internal set; } - /// - /// LeanCloud 服务端发往客户端消息通知 - /// - public string Message { get; set; } - } - - public class AVIMDisconnectEventArgs : EventArgs - { - public int Code { get; private set; } - - public string Reason { get; private set; } - - public string Detail { get; private set; } - - public AVIMDisconnectEventArgs() - { - - } - public AVIMDisconnectEventArgs(int _code, string _reason, string _detail) - { - this.Code = _code; - this.Reason = _reason; - this.Detail = _detail; - } - } - - /// - /// 开始重连之后触发正在重连的事件通知,提供给监听者的事件参数 - /// - public class AVIMReconnectingEventArgs : EventArgs - { - /// - /// 是否由 SDK 内部机制启动的自动重连 - /// - public bool IsAuto { get; set; } - - /// - /// 重连的 client Id - /// - public string ClientId { get; set; } - - /// - /// 重连时使用的 SessionToken - /// - public string SessionToken { get; set; } - } - - /// - /// 重连成功之后的事件回调 - /// - public class AVIMReconnectedEventArgs : EventArgs - { - /// - /// 是否由 SDK 内部机制启动的自动重连 - /// - public bool IsAuto { get; set; } - - /// - /// 重连的 client Id - /// - public string ClientId { get; set; } - - /// - /// 重连时使用的 SessionToken - /// - public string SessionToken { get; set; } - } - - /// - /// 重连失败之后的事件回调参数 - /// - public class AVIMReconnectFailedArgs : EventArgs - { - /// - /// 是否由 SDK 内部机制启动的自动重连 - /// - public bool IsAuto { get; set; } - - /// - /// 重连的 client Id - /// - public string ClientId { get; set; } - - /// - /// 重连时使用的 SessionToken - /// - public string SessionToken { get; set; } - - /// - /// 失败的原因 - /// 0. 客户端网络断开 - /// 1. sessionToken 错误或者失效,需要重新创建 client - /// - public int FailedCode { get; set; } - } - - /// - /// AVIMM essage event arguments. - /// - public class AVIMMessageEventArgs : EventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// I message. - public AVIMMessageEventArgs(IAVIMMessage iMessage) - { - Message = iMessage; - } - /// - /// Gets or sets the message. - /// - /// The message. - public IAVIMMessage Message { get; internal set; } - } - - /// - /// AVIMMessage event arguments. - /// - public class AVIMMessagePatchEventArgs : EventArgs - { - public AVIMMessagePatchEventArgs(IAVIMMessage message) - { - Message = message; - } - - /// - /// Gets or sets the message. - /// - /// The message. - public IAVIMMessage Message { get; internal set; } - } - - /// - /// AVIMT ext message event arguments. - /// - public class AVIMTextMessageEventArgs : EventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// Raw. - public AVIMTextMessageEventArgs(AVIMTextMessage raw) - { - TextMessage = raw; - } - /// - /// Gets or sets the text message. - /// - /// The text message. - public AVIMTextMessage TextMessage { get; internal set; } - } - - /// - /// 当对话中有人加入时,触发 时所携带的事件参数 - /// - public class AVIMOnMembersJoinedEventArgs : EventArgs - { - /// - /// 加入到对话的 Client Id(s) - /// - public IEnumerable JoinedMembers { get; internal set; } - - /// - /// 邀请的操作人 - /// - public string InvitedBy { get; internal set; } - - /// - /// 此次操作针对的对话 Id - /// - public string ConversationId { get; internal set; } - } - - /// - /// 当对话中有人加入时,触发 AVIMMembersJoinListener 时所携带的事件参数 - /// - public class AVIMOnMembersLeftEventArgs : EventArgs - { - /// - /// 离开对话的 Client Id(s) - /// - public IEnumerable LeftMembers { get; internal set; } - - /// - /// 踢出的操作人 - /// - public string KickedBy { get; internal set; } - - /// - /// 此次操作针对的对话 Id - /// - public string ConversationId { get; internal set; } - } - /// - /// 当前用户被邀请加入到对话 - /// - public class AVIMOnInvitedEventArgs : EventArgs - { - /// - /// 邀请的操作人 - /// - public string InvitedBy { get; internal set; } - - /// - /// 此次操作针对的对话 Id - /// - public string ConversationId { get; internal set; } - } - - /// - /// 当前用户被他人从对话中踢出 - /// - public class AVIMOnKickedEventArgs : EventArgs - { - /// - /// 踢出的操作人 - /// - public string KickedBy { get; internal set; } - - /// - /// 此次操作针对的对话 Id - /// - public string ConversationId { get; internal set; } - } - - public class AVIMSessionClosedEventArgs : EventArgs - { - public int Code { get; internal set; } - - public string Reason { get; internal set; } - - public string Detail { get; internal set; } - } -} diff --git a/RTM/Source/Public/AVIMException.cs b/RTM/Source/Public/AVIMException.cs deleted file mode 100644 index f473746..0000000 --- a/RTM/Source/Public/AVIMException.cs +++ /dev/null @@ -1,235 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// 实时通信的异常 - /// - public class AVIMException : Exception - { - /// - /// 错误代码 - /// - public enum ErrorCode - { - /// - /// Error code indicating that an unknown error or an error unrelated to LeanCloud - /// occurred. - /// - OtherCause = -1, - - /// - /// 服务端错误 - /// - FromServer = 4000, - - - /// - /// websocket 连接非正常关闭,通常见于路由器配置对长连接限制的情况。SDK 会自动重连,无需人工干预。 - /// - UnknownError = 1006, - - /// - /// 应用不存在或应用禁用了实时通信服务 - /// - APP_NOT_AVAILABLE = 4100, - - - /// - /// 登录签名验证失败 - /// - SIGNATURE_FAILED = 4102, - - /// - /// Client ClientId 格式错误,超过 64 个字符。 - /// - INVALID_LOGIN = 4103, - - /// - /// Session 没有打开就发送消息,或执行其他操作。常见的错误场景是调用 open session 后直接发送消息,正确的用法是在 Session 打开的回调里执行。 - /// - SESSION_REQUIRED = 4105, - - /// - /// 读超时,服务器端长时间没有收到客户端的数据,切断连接。SDK 包装了心跳包的机制,出现此错误通常是网络问题。SDK 会自动重连,无需人工干预。 - /// - READ_TIMEOUT = 4107, - - /// - /// 登录超时,连接后长时间没有完成 session open。通常是登录被拒绝等原因,出现此问题可能是使用方式有误,可以 创建工单,由我们技术顾问来给出建议。 - /// - LOGIN_TIMEOUT = 4108, - - /// - /// 包过长。消息大小超过 5 KB,请缩短消息或者拆分消息。 - /// - FRAME_TOO_LONG = 4109, - - /// - /// 设置安全域名后,当前登录的域名与安全域名不符合。 - /// - INVALID_ORIGIN = 4110, - - - /// - /// 设置单设备登录后,客户端被其他设备挤下线。 - /// - SESSION_CONFLICT = 4111, - - /// - /// 应用容量超限,当天登录用户数已经超过应用设定的最大值。 - /// - APP_QUOTA_EXCEEDED = 4113, - - /// - /// 客户端发送的序列化数据服务器端无法解析。 - /// - UNPARSEABLE_RAW_MESSAGE = 4114, - - /// - /// 客户端被 REST API 管理接口强制下线。 - /// - KICKED_BY_APP = 4115, - - /// - /// 应用单位时间内发送消息量超过限制,消息被拒绝。 - /// - MESSAGE_SENT_QUOTA_EXCEEDED = 4116, - - /// - /// 服务器内部错误,如果反复出现请收集相关线索并 创建工单,我们会尽快解决。 - /// - INTERNAL_ERROR = 4200, - - /// - /// 通过 API 发送消息超时 - /// - SEND_MESSAGE_TIMEOUT = 4201, - - /// - /// 上游 API 调用异常,请查看报错信息了解错误详情 - /// - CONVERSATION_API_FAILED = 4301, - - /// - /// 对话相关操作签名错误 - /// - CONVERSATION_SIGNATURE_FAILED = 4302, - - /// - /// 发送消息,或邀请等操作对应的对话不存在。 - /// - CONVERSATION_NOT_FOUND = 4303, - - /// - /// 对话成员已满,不能再添加。 - /// - CONVERSATION_FULL = 4304, - - /// - /// 对话操作被应用的云引擎 Hook 拒绝 - /// - CONVERSATION_REJECTED_BY_APP = 4305, - - /// - /// 更新对话操作失败 - /// - CONVERSATION_UPDATE_FAILED = 4306, - - /// - /// 该对话为只读,不能更新或增删成员。 - /// - CONVERSATION_READ_ONLY = 4307, - - /// - /// 该对话禁止当前用户发送消息 - /// - CONVERSATION_NOT_ALLOWED = 4308, - - /// - /// 更新对话的请求被拒绝,当前用户不在对话中 - /// - CONVERSATION_UPDATE_REJECT = 4309, - - /// - /// 查询对话失败,常见于慢查询导致的超时或受其他慢查询导致的数据库响应慢 - /// - CONVERSATION_QUERY_FAILED = 4310, - - /// - /// 拉取对话消息记录失败,常见与超时的情况 - /// - CONVERSATION_LOG_FAILED = 4311, - - /// - /// 拉去对话消息记录被拒绝,当前用户不再对话中 - /// - CONVERSATION_LOG_REJECT = 4312, - - /// - /// 该功能仅对系统对话有效 - /// - SYSTEM_CONVERSATION_REQUIRED = 4313, - - - /// - /// 该功能仅对普通对话有效。 - /// - NORMAL_CONVERSATION_REQUIRED = 4314, - - - /// - /// 当前用户被加入此对话的黑名单,无法发送消息。 - /// - CONVERSATION_BLACKLISTED = 4315, - - - /// - /// 该功能仅对暂态对话有效。 - /// - TRANSIENT_CONVERSATION_REQUIRED = 4316, - - /// - /// 发送消息的对话不存在,或当前用户不在对话中 - /// - INVALID_MESSAGING_TARGET = 4401, - - /// - /// 发送的消息被应用的云引擎 Hook 拒绝 - /// - MESSAGE_REJECTED_BY_APP = 4402, - - /// - /// 客户端无法通过 WebSocket 发送数据包 - /// - CAN_NOT_EXCUTE_COMMAND = 1002, - - } - /// - /// 用户云代码返回的错误码 - /// - public int AppCode { get; private set; } - - - internal AVIMException(ErrorCode code, string message, Exception cause = null) - : base(message, cause) - { - this.Code = code; - } - - internal AVIMException(int code, int appCode, string message, Exception cause = null) - : this((ErrorCode)code, message, cause) - { - this.AppCode = appCode; - } - - /// - /// The LeanCloud error code associated with the exception. - /// - public ErrorCode Code { get; private set; } - } -} diff --git a/RTM/Source/Public/AVIMImageMessage.cs b/RTM/Source/Public/AVIMImageMessage.cs deleted file mode 100644 index 9e00b67..0000000 --- a/RTM/Source/Public/AVIMImageMessage.cs +++ /dev/null @@ -1,246 +0,0 @@ -using LeanCloud; -using LeanCloud.Storage.Internal; -using LeanCloud.Realtime.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.IO; - -namespace LeanCloud.Realtime -{ - /// - /// 图像消息 - /// - [AVIMMessageClassName("_AVIMImageMessage")] - [AVIMTypedMessageTypeInt(-2)] - public class AVIMImageMessage : AVIMFileMessage - { - - } - - /// - /// File message. - /// - [AVIMMessageClassName("_AVIMFileMessage")] - [AVIMTypedMessageTypeInt(-6)] - public class AVIMFileMessage : AVIMMessageDecorator - { - /// - /// Initializes a new instance of the class. - /// - public AVIMFileMessage() - : base(new AVIMTypedMessage()) - { - - } - - /// - /// Initializes a new instance of the class. - /// - /// Message. - public AVIMFileMessage(AVIMTypedMessage message) - : base(message) - { - - } - - /// - /// Gets or sets the file. - /// - /// The file. - public AVFile File { get; set; } - - /// - /// Froms the URL. - /// - /// The URL. - /// URL. - /// The 1st type parameter. - public static T FromUrl(string url) where T : AVIMFileMessage, new() - { - return FromUrl(string.Empty.Random(8), url, null); - } - - /// - /// From the URL. - /// - /// The URL. - /// File name. - /// External URL. - /// Text title. - /// Custom attributes. - /// The 1st type parameter. - public static T FromUrl(string fileName, string externalUrl, string textTitle, IDictionary customAttributes = null) where T : AVIMFileMessage, new() - { - T message = new T(); - message.File = new AVFile(fileName, externalUrl); - message.TextContent = textTitle; - message.MergeCustomAttributes(customAttributes); - return message; - } - - /// - /// From the stream. - /// - /// The stream. - /// File name. - /// Data. - /// MIME type. - /// Text title. - /// Meta data. - /// Custom attributes. - /// The 1st type parameter. - public static T FromStream(string fileName, Stream data, string mimeType, string textTitle, IDictionary metaData, IDictionary customAttributes = null) where T : AVIMFileMessage, new() - { - T message = new T(); - message.File = new AVFile(fileName, data, mimeType, metaData); - message.TextContent = textTitle; - message.MergeCustomAttributes(customAttributes); - return message; - } - - /// - /// Encodes the decorator. - /// - /// The decorator. - public override IDictionary EncodeDecorator() - { - if (File.Url == null) throw new InvalidOperationException("File.Url can not be null before it can be sent."); - File.MetaData["name"] = File.Name; - File.MetaData["format"] = File.MimeType; - var fileData = new Dictionary - { - { "url", File.Url.ToString()}, - { "objId", File.ObjectId }, - { "metaData", File.MetaData } - }; - - return new Dictionary - { - { AVIMProtocol.LCFILE, fileData } - }; - } - - /// - /// Deserialize the specified msgStr. - /// - /// The deserialize. - /// Message string. - public override IAVIMMessage Deserialize(string msgStr) - { - var msg = Json.Parse(msgStr) as IDictionary; - var fileData = msg[AVIMProtocol.LCFILE] as IDictionary; - string mimeType = null; - string url = null; - string name = null; - string objId = null; - IDictionary metaData = null; - if (fileData != null) - { - object metaDataObj = null; - - if (fileData.TryGetValue("metaData", out metaDataObj)) - { - metaData = metaDataObj as IDictionary; - object fileNameObj = null; - if (metaData != null) - { - if (metaData.TryGetValue("name", out fileNameObj)) - { - name = fileNameObj.ToString(); - } - } - object mimeTypeObj = null; - if (metaData != null) - { - if (metaData.TryGetValue("format", out mimeTypeObj)) - { - if (mimeTypeObj != null) - mimeType = mimeTypeObj.ToString(); - } - } - } - - object objIdObj = null; - if (fileData.TryGetValue("objId", out objIdObj)) - { - if (objIdObj != null) - objId = objIdObj.ToString(); - } - - object urlObj = null; - if (fileData.TryGetValue("url", out urlObj)) - { - url = urlObj.ToString(); - } - File = AVFile.CreateWithData(objId, name, url, metaData); - } - - return base.Deserialize(msgStr); - } - } - - /// - /// Location message. - /// - [AVIMMessageClassName("_AVIMMessageClassName")] - [AVIMTypedMessageTypeInt(-5)] - public class AVIMLocationMessage : AVIMMessageDecorator - { - /// - /// Initializes a new instance of the class. - /// - public AVIMLocationMessage() - : base(new AVIMTypedMessage()) - { - - } - - /// - /// Gets or sets the location. - /// - /// The location. - public AVGeoPoint Location { get; set; } - - public AVIMLocationMessage(AVGeoPoint location) - : this() - { - Location = location; - } - - /// - /// Encodes the decorator. - /// - /// The decorator. - public override IDictionary EncodeDecorator() - { - var locationData = new Dictionary - { - { "longitude", Location.Longitude}, - { "latitude", Location.Latitude } - }; - return new Dictionary - { - { AVIMProtocol.LCLOC, locationData } - }; - } - - /// - /// Deserialize the specified msgStr. - /// - /// The deserialize. - /// Message string. - public override IAVIMMessage Deserialize(string msgStr) - { - var msg = Json.Parse(msgStr) as IDictionary; - var locationData = msg[AVIMProtocol.LCLOC] as IDictionary; - if (locationData != null) - { - Location = new AVGeoPoint(double.Parse(locationData["latitude"].ToString()), double.Parse(locationData["longitude"].ToString())); - } - return base.Deserialize(msgStr); - } - } -} diff --git a/RTM/Source/Public/AVIMMessage.cs b/RTM/Source/Public/AVIMMessage.cs deleted file mode 100644 index 21fb38d..0000000 --- a/RTM/Source/Public/AVIMMessage.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using LeanCloud; -using System.Reflection; -using LeanCloud.Storage.Internal; -using System.Threading; -using System.Collections; -using LeanCloud.Realtime.Internal; - -namespace LeanCloud.Realtime -{ - /// - /// 实时消息的核心基类,它是 Json schema 消息的父类 - /// - [AVIMMessageClassName("_AVIMMessage")] - public class AVIMMessage : IAVIMMessage - { - /// - /// 默认的构造函数 - /// - public AVIMMessage() - { - - } - internal readonly object mutex = new object(); - - /// - /// 对话的Id - /// - public string ConversationId { get; set; } - - /// - /// 发送消息的 ClientId - /// - public string FromClientId { get; set; } - - /// - /// 消息在全局的唯一标识Id - /// - public string Id { get; set; } - - /// - /// 服务器端的时间戳 - /// - public long ServerTimestamp { get; set; } - - /// - /// Gets or sets the content. - /// - /// The content. - public string Content { get; set; } - - /// - /// 对方收到消息的时间戳,如果是多人聊天,那以最早收到消息的人回发的 ACK 为准 - /// - public long RcpTimestamp { get; set; } - - public long UpdatedAt { get; set; } - - internal string cmdId { get; set; } - - #region - /// - /// Gets or sets a value indicating whether this mention all. - /// - /// true if mention all; otherwise, false. - public bool MentionAll { get; set; } - - /// - /// Gets or sets the mention list. - /// - /// The mention list. - public IEnumerable MentionList { get; set; } - - #endregion - - #region register convertor for custom typed message - - /// - /// Serialize this message. - /// - /// The serialize. - public virtual string Serialize() - { - return Content; - } - - /// - /// Validate the specified msgStr. - /// - /// The validate. - /// Message string. - public virtual bool Validate(string msgStr) - { - return true; - } - - /// - /// Deserialize the specified msgStr to message subclass instance - /// - /// The deserialize. - /// Message string. - public virtual IAVIMMessage Deserialize(string msgStr) - { - Content = msgStr; - return this; - } - - internal virtual MessageCommand BeforeSend(MessageCommand cmd) - { - return cmd; - } - - internal static IAVIMMessage CopyMetaData(IAVIMMessage srcMsg, IAVIMMessage desMsg) { - if (srcMsg == null) - return desMsg; - - desMsg.ConversationId = srcMsg.ConversationId; - desMsg.FromClientId = srcMsg.FromClientId; - desMsg.Id = srcMsg.Id; - desMsg.ServerTimestamp = srcMsg.ServerTimestamp; - desMsg.RcpTimestamp = srcMsg.RcpTimestamp; - desMsg.UpdatedAt = srcMsg.UpdatedAt; - return desMsg; - } - - #endregion - } - - - /// - /// 消息的发送选项 - /// - public struct AVIMSendOptions - { - /// - /// 是否需要送达回执 - /// - public bool Receipt; - /// - /// 是否是暂态消息,暂态消息不返回送达回执(ack),不保留离线消息,不触发离线推送 - /// - public bool Transient; - /// - /// 消息的优先级,默认是1,可选值还有 2|3 - /// - public int Priority; - /// - /// 是否为 Will 类型的消息,这条消息会被缓存在服务端,一旦当前客户端下线,这条消息会被发送到对话内的其他成员 - /// - public bool Will; - - /// - /// 如果消息的接收者已经下线了,这个字段的内容就会被离线推送到接收者 - ///例如,一张图片消息的离线消息内容可以类似于:[您收到一条图片消息,点击查看] 这样的推送内容,参照微信的做法 - /// - public IDictionary PushData; - } -} diff --git a/RTM/Source/Public/AVIMMessageClassNameAttribute.cs b/RTM/Source/Public/AVIMMessageClassNameAttribute.cs deleted file mode 100644 index e4d7228..0000000 --- a/RTM/Source/Public/AVIMMessageClassNameAttribute.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] - public sealed class AVIMMessageClassNameAttribute: Attribute - { - public AVIMMessageClassNameAttribute(string className) - { - this.ClassName = className; - } - public string ClassName { get; private set; } - - } -} diff --git a/RTM/Source/Public/AVIMMessageFieldNameAttribute.cs b/RTM/Source/Public/AVIMMessageFieldNameAttribute.cs deleted file mode 100644 index 0e155b5..0000000 --- a/RTM/Source/Public/AVIMMessageFieldNameAttribute.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace LeanCloud.Realtime -{ - [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] - public sealed class AVIMMessageFieldNameAttribute: Attribute - { - public AVIMMessageFieldNameAttribute(string fieldName) - { - FieldName = fieldName; - } - - public string FieldName { get; private set; } - } -} diff --git a/RTM/Source/Public/AVIMMessageListener.cs b/RTM/Source/Public/AVIMMessageListener.cs deleted file mode 100644 index d0d91cf..0000000 --- a/RTM/Source/Public/AVIMMessageListener.cs +++ /dev/null @@ -1,143 +0,0 @@ -using LeanCloud.Realtime.Internal; -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// 默认的消息监听器,它主要承担的指责是回执的发送与用户自定义的监听器不冲突 - /// - public class AVIMMessageListener : IAVIMListener - { - /// - /// 默认的 AVIMMessageListener 只会监听 direct 协议,但是并不会触发针对消息类型的判断的监听器 - /// - public AVIMMessageListener() - { - - } - - /// - /// Protocols the hook. - /// - /// true, if hook was protocoled, false otherwise. - /// Notice. - public virtual bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "direct") return false; - if (notice.RawData.ContainsKey("offline")) return false; - return true; - } - - private EventHandler m_OnMessageReceived; - /// - /// 接收到聊天消息的事件通知 - /// - public event EventHandler OnMessageReceived - { - add - { - m_OnMessageReceived += value; - } - remove - { - m_OnMessageReceived -= value; - } - } - internal virtual void OnMessage(AVIMNotice notice) - { - if (m_OnMessageReceived != null) - { - var msgStr = notice.RawData["msg"].ToString(); - var iMessage = AVRealtime.FreeStyleMessageClassingController.Instantiate(msgStr, notice.RawData); - //var messageNotice = new AVIMMessageNotice(notice.RawData); - //var messaegObj = AVIMMessage.Create(messageNotice); - var args = new AVIMMessageEventArgs(iMessage); - m_OnMessageReceived.Invoke(this, args); - } - } - - /// - /// Ons the notice received. - /// - /// Notice. - public virtual void OnNoticeReceived(AVIMNotice notice) - { - this.OnMessage(notice); - } - - } - - /// - /// 文本消息监听器 - /// - public class AVIMTextMessageListener : IAVIMListener - { - /// - /// 构建默认的文本消息监听器 - /// - public AVIMTextMessageListener() - { - - } - - /// - /// 构建文本消息监听者 - /// - /// - public AVIMTextMessageListener(Action textMessageReceived) - { - OnTextMessageReceived += (sender, textMessage) => - { - textMessageReceived(textMessage.TextMessage); - }; - } - - private EventHandler m_OnTextMessageReceived; - public event EventHandler OnTextMessageReceived - { - add - { - m_OnTextMessageReceived += value; - } - remove - { - m_OnTextMessageReceived -= value; - } - } - - public virtual bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "direct") return false; - try - { - var msg = Json.Parse(notice.RawData["msg"].ToString()) as IDictionary; - if (!msg.Keys.Contains(AVIMProtocol.LCTYPE)) return false; - var typInt = 0; - int.TryParse(msg[AVIMProtocol.LCTYPE].ToString(), out typInt); - if (typInt != -1) return false; - return true; - } - catch(ArgumentException) - { - - } - return false; - - } - - public virtual void OnNoticeReceived(AVIMNotice notice) - { - if (m_OnTextMessageReceived != null) - { - var textMessage = new AVIMTextMessage(); - textMessage.Deserialize(notice.RawData["msg"].ToString()); - m_OnTextMessageReceived(this, new AVIMTextMessageEventArgs(textMessage)); - } - } - } -} diff --git a/RTM/Source/Public/AVIMNotice.cs b/RTM/Source/Public/AVIMNotice.cs deleted file mode 100644 index 65f4053..0000000 --- a/RTM/Source/Public/AVIMNotice.cs +++ /dev/null @@ -1,57 +0,0 @@ -using LeanCloud; -using LeanCloud.Realtime.Internal; -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// - /// - public interface IAVIMNotice - { - /// - /// - /// - /// - /// - AVIMNotice Restore(IDictionary estimatedData); - } - /// - /// 从服务端接受到的通知 - /// 通知泛指消息,对话信息变更(例如加人和被踢等),服务器的 ACK,消息回执等 - /// - public class AVIMNotice : EventArgs - { - /// - /// Initializes a new instance of the class. - /// - public AVIMNotice() - { - - } - - /// - /// The name of the command. - /// - public readonly string CommandName; - public readonly IDictionary RawData; - public AVIMNotice(IDictionary estimatedData) - { - this.RawData = estimatedData; - this.CommandName = estimatedData["cmd"].ToString(); - } - - public static bool IsValidLeanCloudProtocol(IDictionary estimatedData) - { - if (estimatedData == null) return false; - if (estimatedData.Count == 0) return false; - return true; - } - } -} diff --git a/RTM/Source/Public/AVIMRecalledMessage.cs b/RTM/Source/Public/AVIMRecalledMessage.cs deleted file mode 100644 index 1e863fd..0000000 --- a/RTM/Source/Public/AVIMRecalledMessage.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace LeanCloud.Realtime { - /// - /// 撤回消息 - /// - [AVIMMessageClassName("_AVIMRecalledMessagee")] - [AVIMTypedMessageTypeInt(-127)] - public class AVIMRecalledMessage : AVIMTypedMessage { - - } -} diff --git a/RTM/Source/Public/AVIMSignature.cs b/RTM/Source/Public/AVIMSignature.cs deleted file mode 100644 index c5bd0d3..0000000 --- a/RTM/Source/Public/AVIMSignature.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// 签名 - /// - public class AVIMSignature - { - /// - /// 经过 SHA1 以及相关操作参数计算出来的加密字符串 - /// - public string SignatureContent { get; set; } - - /// - /// 服务端时间戳 - /// - public long Timestamp { get; set; } - - /// - /// 随机字符串 - /// - public string Nonce { get; set; } - - /// - /// 构造一个签名 - /// - /// - /// - /// - public AVIMSignature(string s,long t,string n) - { - this.Nonce = n; - this.SignatureContent = s; - this.Timestamp = t; - } - } -} diff --git a/RTM/Source/Public/AVIMTemporaryConversation.cs b/RTM/Source/Public/AVIMTemporaryConversation.cs deleted file mode 100644 index 1e06769..0000000 --- a/RTM/Source/Public/AVIMTemporaryConversation.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// Temporary conversation. - /// - public class AVIMTemporaryConversation : AVIMConversation - { - public DateTime ExpiredAt - { - get - { - if (expiredAt == null) - return DateTime.Now.AddDays(1); - return expiredAt.Value; - } - - set - { - expiredAt = value; - } - } - - internal AVIMTemporaryConversation(long ttl) - : base(isTemporary: true) - { - this.expiredAt = DateTime.Now.AddDays(1); - } - } - - -} diff --git a/RTM/Source/Public/AVIMTextMessage.cs b/RTM/Source/Public/AVIMTextMessage.cs deleted file mode 100644 index 7bc1d34..0000000 --- a/RTM/Source/Public/AVIMTextMessage.cs +++ /dev/null @@ -1,47 +0,0 @@ -using LeanCloud.Realtime.Internal; -using LeanCloud.Storage.Internal; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// 纯文本信息 - /// - [AVIMMessageClassName("_AVIMTextMessage")] - [AVIMTypedMessageTypeInt(-1)] - public class AVIMTextMessage : AVIMTypedMessage - { - /// - /// 构建一个文本信息 class. - /// - public AVIMTextMessage() - { - - } - - /// - /// 文本类型标记 - /// - [Obsolete("LCType is deprecated, please use AVIMTypedMessageTypeInt instead.")] - [AVIMMessageFieldName("_lctype")] - public int LCType - { - get; set; - } - - /// - /// 构造一个纯文本信息 - /// - /// - public AVIMTextMessage(string textContent) - : this() - { - TextContent = textContent; - } - } -} diff --git a/RTM/Source/Public/AVIMTypedMessage.cs b/RTM/Source/Public/AVIMTypedMessage.cs deleted file mode 100644 index c756e1f..0000000 --- a/RTM/Source/Public/AVIMTypedMessage.cs +++ /dev/null @@ -1,205 +0,0 @@ -using LeanCloud.Storage.Internal; -using LeanCloud.Realtime.Internal; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace LeanCloud.Realtime -{ - /// - /// - /// - [AVIMMessageClassName("_AVIMTypedMessage")] - [AVIMTypedMessageTypeInt(0)] - public class AVIMTypedMessage : AVIMMessage, IEnumerable> - { - /// - /// Initializes a new instance of the class. - /// - public AVIMTypedMessage() - { - - } - - /// - /// 文本内容 - /// - [AVIMMessageFieldName("_lctext")] - public string TextContent - { - get; set; - } - - private IDictionary estimatedData = new Dictionary(); - /// - /// Serialize this instance. - /// - /// The serialize. - public override string Serialize() - { - var result = Encode(); - var resultStr = Json.Encode(result); - this.Content = resultStr; - return resultStr; - } - - /// - /// Encode this instance. - /// - /// The encode. - public virtual IDictionary Encode() - { - var result = AVRealtime.FreeStyleMessageClassingController.EncodeProperties(this); - var encodedAttrs = PointerOrLocalIdEncoder.Instance.Encode(estimatedData); - result[AVIMProtocol.LCATTRS] = estimatedData; - return result; - } - - /// - /// Validate the specified msgStr. - /// - /// The validate. - /// Message string. - public override bool Validate(string msgStr) - { - try - { - var msg = Json.Parse(msgStr) as IDictionary; - return msg.ContainsKey(AVIMProtocol.LCTYPE); - } - catch - { - - } - return false; - } - - /// - /// Deserialize the specified msgStr. - /// - /// The deserialize. - /// Message string. - public override IAVIMMessage Deserialize(string msgStr) - { - var msg = Json.Parse(msgStr) as IDictionary; - var className = AVRealtime.FreeStyleMessageClassingController.GetClassName(this.GetType()); - var PropertyMappings = AVRealtime.FreeStyleMessageClassingController.GetPropertyMappings(className); - var messageFieldProperties = PropertyMappings.Where(prop => msg.ContainsKey(prop.Value)) - .Select(prop => Tuple.Create(ReflectionHelpers.GetProperty(this.GetType(), prop.Key), msg[prop.Value])); - - foreach (var property in messageFieldProperties) - { - property.Item1.SetValue(this, property.Item2, null); - } - - if (msg.ContainsKey(AVIMProtocol.LCATTRS)) - { - object attrs = msg[AVIMProtocol.LCATTRS]; - this.estimatedData = AVDecoder.Instance.Decode(attrs) as Dictionary; - } - - return base.Deserialize(msgStr); - } - - /// - /// Gets or sets the with the specified key. - /// - /// Key. - public virtual object this[string key] - { - get - { - if (estimatedData.TryGetValue(key, out object value)) { - return value; - } - return null; - } - set - { - estimatedData[key] = value; - } - } - - /// - /// Merges the custom attributes. - /// - /// Custom attributes. - public void MergeCustomAttributes(IDictionary customAttributes) - { - this.estimatedData = this.estimatedData.Merge(customAttributes); - } - - /// - /// Gets the enumerator. - /// - /// The enumerator. - public IEnumerator> GetEnumerator() - { - return estimatedData.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable>)this).GetEnumerator(); - } - } - - /// - /// AVIMMessage decorator. - /// - public abstract class AVIMMessageDecorator : AVIMTypedMessage - { - /// - /// Gets or sets the message. - /// - /// The message. - public AVIMTypedMessage Message { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// Message. - protected AVIMMessageDecorator(AVIMTypedMessage message) - { - this.Message = message; - } - - /// - /// Gets or sets the content of the message. - /// - /// The content of the message. - public virtual IDictionary MessageContent { get; set; } - - /// - /// Encodes the decorated. - /// - /// The decorated. - public virtual IDictionary EncodeDecorated() - { - return Message.Encode(); - } - - /// - /// Encode this instance. - /// - /// The encode. - public override IDictionary Encode() - { - var decoratedMessageEncoded = EncodeDecorated(); - var selfEncoded = base.Encode(); - var decoratoEncoded = this.EncodeDecorator(); - var resultEncoed = decoratedMessageEncoded.Merge(selfEncoded).Merge(decoratoEncoded); - return resultEncoed; - } - - /// - /// Encodes the decorator. - /// - /// The decorator. - public abstract IDictionary EncodeDecorator(); - } - - -} diff --git a/RTM/Source/Public/AVIMTypedMessageTypeIntAttribute.cs b/RTM/Source/Public/AVIMTypedMessageTypeIntAttribute.cs deleted file mode 100644 index 49c4b76..0000000 --- a/RTM/Source/Public/AVIMTypedMessageTypeIntAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -namespace LeanCloud.Realtime -{ - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] - public sealed class AVIMTypedMessageTypeIntAttribute : Attribute - { - public AVIMTypedMessageTypeIntAttribute(int typeInt) - { - this.TypeInteger = typeInt; - } - - public int TypeInteger { get; private set; } - } -} diff --git a/RTM/Source/Public/AVRealtime.cs b/RTM/Source/Public/AVRealtime.cs deleted file mode 100644 index 49bd9ec..0000000 --- a/RTM/Source/Public/AVRealtime.cs +++ /dev/null @@ -1,1282 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; -using LeanCloud; -using System.Reflection; -using LeanCloud.Realtime.Internal; -using LeanCloud.Storage.Internal; -using System.Threading; - -#if UNITY -using UnityEngine; -#endif -namespace LeanCloud.Realtime -{ - - /// - /// 实时消息的框架类 - /// 包含了 WebSocket 连接以及事件通知的管理 - /// - public class AVRealtime - { - internal static IDictionary clients = null; - - private static readonly object mutex = new object(); - private string _wss; - private string _secondaryWss; - private string _sesstionToken; - private long _sesstionTokenExpire; - private string _clientId; - private string _deviceId; - private bool _secure; - private string _tag; - private string subprotocolPrefix = "lc.json."; - - static readonly int RECONNECT_DELAY = 5 * 1000; - static readonly int RECONNECT_USE_SECONDARY_TIMES = 6; - static readonly int RECONNECT_FROM_APP_ROUTER = 12; - - int reconnectTimes; - - public bool IsSesstionTokenExpired - { - get - { - return DateTime.Now.ToUnixTimeStamp() > _sesstionTokenExpire; - } - } - - - - private IAVIMCommandRunner avIMCommandRunner; - - - /// - /// - /// - public IAVIMCommandRunner AVIMCommandRunner - { - get - { - lock (mutex) - { - avIMCommandRunner = avIMCommandRunner ?? new AVIMCommandRunner(this.AVWebSocketClient); - return avIMCommandRunner; - } - } - } - - private IWebSocketClient webSocketController; - internal IWebSocketClient AVWebSocketClient - { - get - { - lock (mutex) - { - webSocketController = webSocketController ?? new DefaultWebSocketClient(); - return webSocketController; - } - } - set - { - lock (mutex) - { - webSocketController = value; - } - } - } - - internal static IAVRouterController RouterController - { - get - { - return AVIMCorePlugins.Instance.RouterController; - } - } - - internal static IFreeStyleMessageClassingController FreeStyleMessageClassingController - { - get - { - return AVIMCorePlugins.Instance.FreeStyleClassingController; - } - } - - /// - /// - /// - public event EventHandler OnOfflineMessageReceived; - - /// - /// 与云端通讯的状态 - /// - public enum Status - { - /// - /// 未初始化 - /// - None = -1, - - /// - /// 正在连接 - /// - Connecting = 0, - - /// - /// 已连接 - /// - Online = 1, - - /// - /// 连接已断开 - /// - Offline = 2, - - /// - /// 正在重连 - /// - Reconnecting = 3, - - /// - /// websocket 连接已被打开 - /// - Opened = 98, - - /// - /// 已主动关闭 - /// - Closed = 99, - } - - private AVRealtime.Status state = Status.None; - public AVRealtime.Status State - { - get - { - return state; - } - private set - { - state = value; - } - } - - private struct NetworkStateOptions - { - public bool Available { get; set; } - } - - private NetworkStateOptions NetworkState { get; set; } - - private struct WebSocketStateOptions - { - public int ClosedCode { get; set; } - } - - private WebSocketStateOptions WebSocketState { get; set; } - - /// - /// - /// - public struct AVIMReconnectOptions - { - /// - /// 重连的时间间隔,单位是秒 - /// - public long Interval { get; set; } - - /// - /// 重连的次数 - /// - public int Retry { get; set; } - } - - internal string Subprotocol - { - get - { - return subprotocolPrefix + (int)CurrentConfiguration.OfflineMessageStrategy; - } - } - - /// - /// 重连选项 - /// - public AVIMReconnectOptions ReconnectOptions { get; set; } - - private ISignatureFactory _signatureFactory; - - /// - /// 签名接口 - /// - public ISignatureFactory SignatureFactory - { - get - { - _signatureFactory = _signatureFactory ?? new DefaulSiganatureFactory(); - return _signatureFactory; - } - set - { - _signatureFactory = value; - } - } - - private bool useLeanEngineSignaturFactory; - /// - /// 启用 LeanEngine 云函数签名 - /// - public void UseLeanEngineSignatureFactory() - { - useLeanEngineSignaturFactory = true; - this.SignatureFactory = new LeanEngineSignatureFactory(); - } - - private EventHandler m_OnDisconnected; - /// - /// 连接断开触发的事件 - /// 如果其他客户端使用了相同的 Tag 登录,就会导致当前用户被服务端断开 - /// - public event EventHandler OnDisconnected - { - add - { - m_OnDisconnected += value; - } - remove - { - m_OnDisconnected -= value; - } - } - - private EventHandler m_OnReconnecting; - /// - /// 正在重连时触发的事件 - /// - public event EventHandler OnReconnecting - { - add - { - m_OnReconnecting += value; - } - remove - { - m_OnReconnecting -= value; - } - } - - private EventHandler m_OnReconnected; - /// - /// 重连之后触发的事件 - /// - public event EventHandler OnReconnected - { - add - { - m_OnReconnected += value; - } - remove - { - m_OnReconnected -= value; - } - } - - private EventHandler m_OnReconnectFailed; - - /// - /// 重连失败之后触发的事件 - /// - public event EventHandler OnReconnectFailed - { - add - { - m_OnReconnectFailed += value; - } - remove - { - m_OnReconnectFailed -= value; - } - } - - /// - /// Invokes the state of the network. - /// - /// If set to true broken. - internal void InvokeNetworkState(bool available = false) - { - if (this.NetworkState.Available == available) return; - SetNetworkState(available); - PrintLog(string.Format("network connectivity is {0} now", available)); - // 如果断线产生的原因是客户端掉线而不是服务端踢下线,则应该开始自动重连 - var reasonShouldReconnect = new int[] { 0, 1006, 4107 }; - if (this.NetworkState.Available && reasonShouldReconnect.Contains(this.WebSocketState.ClosedCode)) - { - StartAutoReconnect(); - } - } - - internal void SetNetworkState(bool available = true) - { - this.NetworkState = new NetworkStateOptions() - { - Available = available - }; - } - - private EventHandler m_NoticeReceived; - public event EventHandler NoticeReceived - { - add - { - m_NoticeReceived += value; - } - remove - { - m_NoticeReceived -= value; - } - } - - private void WebSocketClient_OnMessage(string obj) - { - try - { - var estimatedData = Json.Parse(obj) as IDictionary; - var validator = AVIMNotice.IsValidLeanCloudProtocol(estimatedData); - if (validator) - { - var notice = new AVIMNotice(estimatedData); - m_NoticeReceived?.Invoke(this, notice); - } - } - catch (Exception ex) - { - if (ex.InnerException != null) - { - PrintLog(ex.InnerException.Source); - } - if (ex.Source != null) - { - PrintLog(ex.Source); - } - - PrintLog(ex.Message); - } - } - - /// - /// 设定监听者 - /// - /// - /// - public void SubscribeNoticeReceived(IAVIMListener listener, Func runtimeHook = null) - { - this.NoticeReceived += new EventHandler((sender, notice) => - { - var approved = runtimeHook == null ? listener.ProtocolHook(notice) : runtimeHook(notice) && listener.ProtocolHook(notice); - if (approved) - { - listener.OnNoticeReceived(notice); - } - }); - } - - /// - /// 初始化配置项 - /// - public struct Configuration - { - /// - /// 签名工厂 - /// - public ISignatureFactory SignatureFactory { get; set; } - /// - /// 自定义 WebSocket 客户端 - /// - public IWebSocketClient WebSocketClient { get; set; } - /// - /// LeanCloud App Id - /// - public string ApplicationId { get; set; } - /// - /// LeanCloud App Key - /// - public string ApplicationKey { get; set; } - - /// - /// 登录的时候告知服务器,本次登录所使用的离线消息策略 - /// - public OfflineMessageStrategy OfflineMessageStrategy { get; set; } - } - - /// - ///登录时的离线消息下发策略 - /// - public enum OfflineMessageStrategy - { - /// - /// 服务器将所有离线消息一次性在登录之后马上下发下来 - /// - Default = 1, - - /// - /// 不再下发未读消息,而是下发对话的未读通知,告知客户端有哪些对话处于未读状态 - /// - [Obsolete("该策略已被废弃,请使用 UnreadAck")] - UnreadNotice = 2, - - /// - /// ack 和 read 分离, ack 不会清理未读消息 - /// - UnreadAck = 3 - } - - /// - /// 当前配置 - /// - public Configuration CurrentConfiguration { get; internal set; } - /// - /// 初始化实时消息客户端 - /// - /// - public AVRealtime(Configuration config) - { - lock (mutex) - { - if ((int)config.OfflineMessageStrategy == 0) - { - config.OfflineMessageStrategy = OfflineMessageStrategy.UnreadAck; - } - - CurrentConfiguration = config; - if (CurrentConfiguration.WebSocketClient != null) - { - webSocketController = CurrentConfiguration.WebSocketClient; - } - if (CurrentConfiguration.SignatureFactory != null) - { - this.SignatureFactory = CurrentConfiguration.SignatureFactory; - } - ReconnectOptions = new AVIMReconnectOptions() - { - Interval = 5, - Retry = 120 - }; - - - RegisterMessageType(); - RegisterMessageType(); - RegisterMessageType(); - RegisterMessageType(); - RegisterMessageType(); - RegisterMessageType(); - RegisterMessageType(); - RegisterMessageType(); - RegisterMessageType(); - - // 注册服务端 goaway 指令 - var goAwayListener = new GoAwayListener(); - goAwayListener.OnGoAway += () => { - RouterController.ClearCache().ContinueWith(_ => { - reborn = true; - // 关闭 WebSocket - AVWebSocketClient.Disconnect(); - }); - }; - SubscribeNoticeReceived(goAwayListener); - - reconnectTimes = 0; - } - } - - /// - /// 初始化实时消息客户端 - /// - /// - /// - public AVRealtime(string applicationId, string applicationKey) - : this(new Configuration() - { - ApplicationId = applicationId, - ApplicationKey = applicationKey, - OfflineMessageStrategy = OfflineMessageStrategy.UnreadAck - }) - { - - } - - #region websocket log - internal static Action LogTracker { get; private set; } - /// - /// 打开 WebSocket 日志 - /// - /// - public static void WebSocketLog(Action trace) - { - LogTracker = trace; - } - public static void PrintLog(string log) - { - if (AVRealtime.LogTracker != null) - { - AVRealtime.LogTracker(log); - } - } - #endregion - - /// - /// 创建 Client - /// - /// - /// - /// 设备唯一的 Id。如果是 iOS 设备,需要将 iOS 推送使用的 DeviceToken 作为 deviceId 传入 - /// 是否强制加密 wss 链接 - /// - /// - public Task CreateClientAsync(string clientId, - string tag = null, - string deviceId = null, - bool secure = true, - CancellationToken cancellationToken = default(CancellationToken)) - { - lock (mutex) - { - var client = PreLogIn(clientId, tag, deviceId); - - AVRealtime.PrintLog("begin OpenAsync."); - return OpenAsync(secure, Subprotocol, true, cancellationToken).OnSuccess(t => - { - if (!t.Result) - { - return Task.FromResult(null); - } - AVRealtime.PrintLog("websocket server connected, begin to open sesstion."); - SetNetworkState(); - var cmd = new SessionCommand() - .UA(VersionString) - .Tag(tag) - .DeviceId(deviceId) - .Option("open") - .PeerId(clientId); - - ToggleNotification(true); - return AttachSignature(cmd, this.SignatureFactory.CreateConnectSignature(clientId)); - - }).Unwrap().OnSuccess(x => - { - var cmd = x.Result; - if (cmd == null) - { - return Task.FromResult>>(null); - } - return this.RunCommandAsync(cmd); - }).Unwrap().OnSuccess(s => - { - if (s.Result == null) - { - return null; - } - AVRealtime.PrintLog("sesstion opened."); - state = Status.Online; - ToggleHeartBeating(true); - var response = s.Result.Item2; - if (response.ContainsKey("st")) - { - _sesstionToken = response["st"] as string; - } - if (response.ContainsKey("stTtl")) - { - var stTtl = long.Parse(response["stTtl"].ToString()); - _sesstionTokenExpire = DateTime.Now.ToUnixTimeStamp() + stTtl * 1000; - } - AfterLogIn(client); - return client; - }); - } - } - - - - /// - /// Creates the client async. - /// - /// The client async. - /// User. - /// Tag. - /// Device identifier. - /// If set to true secure. - public Task CreateClientAsync(AVUser user = null, - string tag = null, - string deviceId = null, - bool secure = true, - CancellationToken cancellationToken = default(CancellationToken)) - { - AVIMClient client = null; - AVRealtime.PrintLog("begin OpenAsync."); - return OpenAsync(secure, Subprotocol, true, cancellationToken).OnSuccess(openTask => - { - AVRealtime.PrintLog("OpenAsync OnSuccess. begin send open sesstion cmd."); - var userTask = Task.FromResult(user); - if (user == null) - userTask = AVUser.GetCurrentUserAsync(); - - return userTask; - }).Unwrap().OnSuccess(u => - { - var theUser = u.Result; - return AVCloud.RequestRealtimeSignatureAsync(theUser); - }).Unwrap().OnSuccess(signTask => - { - var signResult = signTask.Result; - var clientId = signResult.ClientId; - var nonce = signResult.Nonce; - var singnature = signResult.Signature; - var ts = signResult.Timestamp; - - client = PreLogIn(clientId, tag, deviceId); - ToggleNotification(true); - return this.OpenSessionAsync(clientId, tag, deviceId, nonce, ts, singnature, secure); - }).Unwrap().OnSuccess(s => - { - ToggleHeartBeating(true); - AfterLogIn(client); - return client; - }); - } - - #region pre-login - internal AVIMClient PreLogIn(string clientId, - string tag = null, - string deviceId = null) - { - var client = new AVIMClient(clientId, tag, this); - if (this.OnOfflineMessageReceived != null) - { - client.OnOfflineMessageReceived += this.OnOfflineMessageReceived; - } - _clientId = clientId; - _tag = tag; - _deviceId = deviceId; - if (_tag != null) - { - if (deviceId == null) - throw new ArgumentNullException(deviceId, "当 tag 不为空时,必须传入当前设备不变的唯一 id(deviceId)"); - } - - if (string.IsNullOrEmpty(clientId)) throw new Exception("当前 ClientId 为空,无法登录服务器。"); - - return client; - } - - internal void AfterLogIn(AVIMClient client) - { - if (clients == null) clients = new Dictionary(); - client.OnSessionClosed += (sender, e) => { - string clientId = (sender as AVIMClient).ClientId; - clients.Remove(clientId); - if (clients.Count == 0) { - LogOut(); - } - }; - clients[client.ClientId] = client; - } - - #endregion - - #region after-login - - - #endregion - - /// - /// 创建 Client - /// - /// - /// - /// 设备唯一的 Id。如果是 iOS 设备,需要将 iOS 推送使用的 DeviceToken 作为 deviceId 传入 - /// 是否强制加密 wss 链接 - /// - /// - [Obsolete("CreateClient is deprecated, please use CreateClientAsync instead.")] - public Task CreateClient( - string clientId, - string tag = null, - string deviceId = null, - bool secure = true, - CancellationToken cancellationToken = default(CancellationToken)) - { - return this.CreateClientAsync(clientId, tag, deviceId, secure, cancellationToken); - } - - private bool _listening = false; - /// - /// websocket 事件的监听的开关 - /// - /// 是否打开 - public void ToggleNotification(bool toggle) - { - AVRealtime.PrintLog("ToggleNotification| toggle:" + toggle + "|listening: " + _listening); - if (toggle && !_listening) - { - AVWebSocketClient.OnClosed += WebsocketClient_OnClosed; - AVWebSocketClient.OnMessage += WebSocketClient_OnMessage; - _listening = true; - } - else if (!toggle && _listening) - { - AVWebSocketClient.OnClosed -= WebsocketClient_OnClosed; - AVWebSocketClient.OnMessage -= WebSocketClient_OnMessage; - _listening = false; - } - } - - //public void ToggleOfflineNotification(bool toggle) - //{ - // if (toggle) - // { - // PCLWebsocketClient.OnMessage += WebSocketClient_OnMessage_On_Session_Opening; - // } - // else - // { - // PCLWebsocketClient.OnMessage -= WebSocketClient_OnMessage_On_Session_Opening; - // } - //} - - //private void WebSocketClient_OnMessage_On_Session_Opening(string obj) - //{ - // AVRealtime.PrintLog("offline<=" + obj); - //} - - - string _beatPacket = "{}"; - bool _heartBeatingToggle = true; - IAVTimer _heartBeatingTimer; - /// - /// 主动发送心跳包 - /// - /// 是否开启 - /// 时间间隔 - /// 心跳包的内容,默认是个空的 {} - public void ToggleHeartBeating(bool toggle = true, double interval = 60000, string beatPacket = "{}") - { - this._heartBeatingToggle = toggle; - if (!string.Equals(_beatPacket, beatPacket)) _beatPacket = beatPacket; - - if (_heartBeatingTimer == null && this._heartBeatingToggle) - { - _heartBeatingTimer = new AVTimer(); - _heartBeatingTimer.Elapsed += SendHeartBeatingPacket; - _heartBeatingTimer.Interval = interval; - _heartBeatingTimer.Start(); - PrintLog("auto heart beating started."); - } - if (!this._heartBeatingToggle && _heartBeatingTimer != null) - { - _heartBeatingTimer.Stop(); - _heartBeatingTimer = null; - } - } - - void SendHeartBeatingPacket(object sender, TimerEventArgs e) - { - PrintLog("auto heart beating ticked by timer."); -#if MONO || UNITY - Dispatcher.Instance.Post(() => - { - KeepAlive(); - }); -#else - KeepAlive(); -#endif - } - - /// - /// Keeps the alive. - /// - public void KeepAlive() - { - try - { - var cmd = new AVIMCommand(); - RunCommandAsync(cmd).ContinueWith(t => - { - if (t.IsCanceled || t.IsFaulted || t.Exception != null) - { - InvokeNetworkState(); - } - }); - } - catch (Exception) - { - InvokeNetworkState(); - } - } - - internal bool sessionConflict = false; - internal bool loggedOut = false; - - internal bool CanReconnect - { - get - { - return !sessionConflict && !loggedOut && state == Status.Offline; - } - } - - /// - /// 开始自动重连 - /// - public void StartAutoReconnect() - { - - } - internal bool useSecondary = false; - internal bool reborn = false; - - internal Task LogInAsync(string clientId, - string tag = null, - string deviceId = null, - bool secure = true, - CancellationToken cancellationToken = default(CancellationToken)) - { - lock (mutex) - { - var cmd = new SessionCommand() - .UA(VersionString) - .Tag(tag) - .DeviceId(deviceId) - .Option("open") - .PeerId(clientId); - - var result = AttachSignature(cmd, this.SignatureFactory.CreateConnectSignature(clientId)).OnSuccess(_ => - { - return RunCommandAsync(cmd); - }).Unwrap().OnSuccess(t => - { - AVRealtime.PrintLog("sesstion opened."); - if (t.Exception != null) - { - var imException = t.Exception.InnerException as AVIMException; - throw imException; - } - state = Status.Online; - var response = t.Result.Item2; - if (response.ContainsKey("st")) - { - _sesstionToken = response["st"] as string; - } - if (response.ContainsKey("stTtl")) - { - var stTtl = long.Parse(response["stTtl"].ToString()); - _sesstionTokenExpire = DateTime.Now.ToUnixTimeStamp() + stTtl * 1000; - } - return t.Result; - }); - - return result; - } - - } - - internal Task OpenSessionAsync(string clientId, - string tag = null, - string deviceId = null, - string nonce = null, - long timestamp = 0, - string signature = null, - bool secure = true) - { - var cmd = new SessionCommand() - .UA(VersionString) - .Tag(tag) - .DeviceId(deviceId) - .Option("open") - .PeerId(clientId) - .Argument("n", nonce) - .Argument("t", timestamp) - .Argument("s", signature); - - return RunCommandAsync(cmd).OnSuccess(t => - { - AVRealtime.PrintLog("sesstion opened."); - if (t.Exception != null) - { - var imException = t.Exception.InnerException as AVIMException; - throw imException; - } - state = Status.Online; - var response = t.Result.Item2; - if (response.ContainsKey("st")) - { - _sesstionToken = response["st"] as string; - } - if (response.ContainsKey("stTtl")) - { - var stTtl = long.Parse(response["stTtl"].ToString()); - _sesstionTokenExpire = DateTime.Now.ToUnixTimeStamp() + stTtl * 1000; - } - return t.Result; - }); - - } - - /// - /// 自动重连 - /// - /// - Task AutoReconnect() - { - AVRealtime.PrintLog("AutoReconnect started."); - var reconnectingArgs = new AVIMReconnectingEventArgs() - { - ClientId = _clientId, - IsAuto = true, - SessionToken = _sesstionToken - }; - m_OnReconnecting?.Invoke(this, reconnectingArgs); - - var tcs = new TaskCompletionSource(); - Task task; - if (reborn) - { - AVRealtime.PrintLog("both preferred and secondary websockets are expired, so try to request RTM router to get a new pair"); - task = OpenAsync(this._secure, Subprotocol, true); - } else { - var websocketServer = _wss; - if (useSecondary) { - AVRealtime.PrintLog(string.Format("preferred websocket server ({0}) network broken, take secondary server({1}) :", _wss, _secondaryWss)); - websocketServer = _secondaryWss; - } - task = OpenAsync(websocketServer, Subprotocol, true); - } - - task.ContinueWith(t => - { - if (t.IsFaulted || t.IsCanceled) { - state = Status.Reconnecting; - var reconnectFailedArgs = new AVIMReconnectFailedArgs() { - ClientId = _clientId, - IsAuto = true, - SessionToken = _sesstionToken, - FailedCode = 0// network broken. - }; - m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); - state = Status.Offline; - tcs.SetException(t.Exception); - throw t.Exception; - } else { - state = Status.Opened; - SetNetworkState(); - - void onClose(int code, string reason, string detail) { - AVRealtime.PrintLog("disconnect when open session"); - var ex = new Exception("connection is closed"); - tcs.SetException(ex); - AVWebSocketClient.OnClosed -= onClose; - throw ex; - }; - AVWebSocketClient.OnClosed += onClose; - - if (this.IsSesstionTokenExpired) { - AVRealtime.PrintLog("session is expired, auto relogin with clientId :" + _clientId); - return this.LogInAsync(_clientId, this._tag, this._deviceId, this._secure).ContinueWith(o => { - AVWebSocketClient.OnClosed -= onClose; - return !o.IsFaulted; - }); - } else { - var sessionCMD = new SessionCommand().UA(VersionString).R(1); - - if (string.IsNullOrEmpty(_tag)) { - sessionCMD = sessionCMD.Tag(_tag).SessionToken(this._sesstionToken); - } - - var cmd = sessionCMD.Option("open") - .PeerId(_clientId); - - AVRealtime.PrintLog("reopen session with session token :" + _sesstionToken); - return RunCommandAsync(cmd).ContinueWith(o => { - AVWebSocketClient.OnClosed -= onClose; - return !o.IsFaulted; - }); - } - } - }).Unwrap().ContinueWith(s => - { - if (s.IsFaulted || s.Exception != null) - { - var reconnectFailedArgs = new AVIMReconnectFailedArgs() - { - ClientId = _clientId, - IsAuto = true, - SessionToken = _sesstionToken, - FailedCode = 1 - }; - m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); - state = Status.Offline; - tcs.SetException(s.Exception); - } - else - { - var reconnectedArgs = new AVIMReconnectedEventArgs() { - ClientId = _clientId, - IsAuto = true, - SessionToken = _sesstionToken, - }; - state = Status.Online; - m_OnReconnected?.Invoke(this, reconnectedArgs); - ToggleNotification(true); - ToggleHeartBeating(true); - tcs.SetResult(true); - } - }); - - return tcs.Task; - } - - - - #region register IAVIMMessage - /// - /// Registers the subtype of the message. - /// - /// The 1st type parameter. - public void RegisterMessageType() where T : IAVIMMessage - { - AVIMCorePlugins.Instance.FreeStyleClassingController.RegisterSubclass(typeof(T)); - } - #endregion - - /// - /// open websocket with default configurations. - /// - /// - public Task OpenAsync(bool secure = true) - { - return this.OpenAsync(secure, null); - } - - /// - /// Open websocket connection. - /// - /// The async. - /// If set to true secure. - /// Subprotocol. - /// If set to true enforce. - /// Cancellation token. - public Task OpenAsync(bool secure, string subprotocol = null, bool enforce = false, CancellationToken cancellationToken = default(CancellationToken)) - { - _secure = secure; - if (state == Status.Online && !enforce) - { - AVRealtime.PrintLog("state is Status.Online."); - return Task.FromResult(true); - } - - if (AVClient.CurrentConfiguration.RealtimeServer != null) - { - _wss = AVClient.CurrentConfiguration.RealtimeServer; - AVRealtime.PrintLog("use configuration realtime server with url: " + _wss); - return OpenAsync(_wss, subprotocol, enforce); - } - var routerUrl = AVClient.CurrentConfiguration.RTMServer; - return RouterController.GetAsync(routerUrl, secure, cancellationToken).OnSuccess(r => - { - var routerState = r.Result; - if (routerState == null) - { - return Task.FromResult(false); - } - _wss = routerState.server; - _secondaryWss = routerState.secondary; - state = Status.Connecting; - AVRealtime.PrintLog("push router give a url :" + _wss); - return OpenAsync(routerState.server, subprotocol, enforce); - }).Unwrap(); - } - - /// - /// open webcoket connection with cloud. - /// - /// wss address - /// subprotocol for websocket - /// - /// - public Task OpenAsync(string url, string subprotocol = null, bool enforce = false, CancellationToken cancellationToken = default(CancellationToken)) - { - if (AVWebSocketClient.IsOpen && !enforce) - { - AVRealtime.PrintLog(url + "is already connectd."); - return Task.FromResult(true); - } - - AVRealtime.PrintLog("websocket try to connect url :" + url + " with subprotocol: " + subprotocol); - AVRealtime.PrintLog(url + " \tconnecting..."); - - return AVWebSocketClient.Connect(url, subprotocol); - } - - /// - /// send websocket command to Realtime server. - /// - /// - /// - public Task>> RunCommandAsync(AVIMCommand command) - { - command.AppId(AVClient.CurrentConfiguration.ApplicationId); - return this.AVIMCommandRunner.RunCommandAsync(command); - } - - /// - /// - /// - /// - public void RunCommand(AVIMCommand command) - { - command.AppId(AVClient.CurrentConfiguration.ApplicationId); - this.AVIMCommandRunner.RunCommand(command); - } - - internal Task AttachSignature(AVIMCommand command, Task SignatureTask) - { - AVRealtime.PrintLog("begin to attach singature."); - var tcs = new TaskCompletionSource(); - if (SignatureTask == null) - { - tcs.SetResult(command); - return tcs.Task; - } - return SignatureTask.OnSuccess(_ => - { - if (_.Result != null) - { - var signature = _.Result; - command.Argument("t", signature.Timestamp); - command.Argument("n", signature.Nonce); - command.Argument("s", signature.SignatureContent); - AVRealtime.PrintLog("AttachSignature ended.t:" + signature.Timestamp + ";n:" + signature.Nonce + ";s:" + signature.SignatureContent); - } - return command; - }); - } - - #region log out and clean event subscribtion - private void WebsocketClient_OnClosed(int errorCode, string reason, string detail) - { - PrintLog(string.Format("websocket closed with code is {0},reason is {1} and detail is {2}", errorCode, reason, detail)); - state = Status.Offline; - - ToggleNotification(false); - ToggleHeartBeating(false); - - var disconnectEventArgs = new AVIMDisconnectEventArgs(errorCode, reason, detail); - m_OnDisconnected?.Invoke(this, disconnectEventArgs); - - this.WebSocketState = new WebSocketStateOptions() - { - ClosedCode = errorCode - }; - PrepareReconnect(); - } - - private void WebsocketClient_OnError(string obj) - { - PrintLog("error:" + obj); - // 如果遇到 WebSocket 错误之后,先关闭,再按断线处理 - AVWebSocketClient.Close(); - WebsocketClient_OnClosed(0, obj, string.Empty); - } - - void PrepareReconnect() { - AVRealtime.PrintLog("Prepare Reconnect"); - Task.Delay(RECONNECT_DELAY).ContinueWith(_ => { - // 开启重连 - AutoReconnect().ContinueWith(t => { - if (t.IsFaulted) { - // 重连失败,延迟再次重连 - reconnectTimes++; - AVRealtime.PrintLog(String.Format("reconnect {0} times", reconnectTimes)); - if (reconnectTimes >= RECONNECT_FROM_APP_ROUTER) { - // 如果大于当前服务地址的最大重连次数,则清空 Router 后重新重连 - RouterController.ClearCache().ContinueWith(__ => { - reborn = true; - PrepareReconnect(); - }); - - } else if (reconnectTimes >= RECONNECT_USE_SECONDARY_TIMES) { - // 如果大于单台 IM 服务器的重连次数,则启用备用服务器 - useSecondary = true; - PrepareReconnect(); - } else { - PrepareReconnect(); - } - } else { - // 重连成功 - reconnectTimes = 0; - reborn = false; - useSecondary = false; - } - }); - }); - } - - internal void LogOut() - { - State = Status.Closed; - loggedOut = true; - Dispose(); - AVWebSocketClient.Close(); - } - - internal void Dispose() - { - var toggle = false; - ToggleNotification(toggle); - ToggleHeartBeating(toggle); - - if (m_NoticeReceived != null) - { - foreach (Delegate d in m_NoticeReceived.GetInvocationList()) - { - m_NoticeReceived -= (EventHandler)d; - } - } - if (m_OnDisconnected != null) - { - foreach (Delegate d in m_OnDisconnected.GetInvocationList()) - { - m_OnDisconnected -= (EventHandler)d; - } - } - } - #endregion - - static AVRealtime() - { -#if MONO || UNITY - versionString = "net-unity/" + Version; -#else - versionString = "net-universal/" + Version; -#endif - } - - private static readonly string versionString; - internal static string VersionString - { - get - { - return versionString; - } - } - - internal static System.Version Version - { - get - { - AssemblyName assemblyName = new AssemblyName(typeof(AVRealtime).GetTypeInfo().Assembly.FullName); - return assemblyName.Version; - } - } - } -} diff --git a/RTM/Source/Public/IAVIMListener.cs b/RTM/Source/Public/IAVIMListener.cs deleted file mode 100644 index 366f4a2..0000000 --- a/RTM/Source/Public/IAVIMListener.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// WebSocket 监听服务端事件通知的接口 - /// 所有基于协议层的事件监听都需要实现这个接口,然后自定义监听协议。 - /// - public interface IAVIMListener - { - /// - /// 监听的协议 Hook - /// 例如,消息的协议是 direct 命令,因此消息监听需要判断 == "direct" 才可以调用 - /// - /// - /// - bool ProtocolHook(AVIMNotice notice); - - ///// - ///// 如果 返回 true,则会启动 NoticeAction 里面的回调逻辑 - ///// - //Action NoticeAction { get; set; } - - /// - /// 如果 返回 true,则会启动 NoticeAction 里面的回调逻辑 - /// - void OnNoticeReceived(AVIMNotice notice); - } -} diff --git a/RTM/Source/Public/IAVIMMessage.cs b/RTM/Source/Public/IAVIMMessage.cs deleted file mode 100644 index f797485..0000000 --- a/RTM/Source/Public/IAVIMMessage.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// 消息接口 - /// 所有消息必须实现这个接口 - /// - public interface IAVIMMessage - { - /// - /// Serialize this instance. - /// - /// The serialize. - string Serialize(); - - /// - /// Validate the specified msgStr. - /// - /// The validate. - /// Message string. - bool Validate(string msgStr); - - /// - /// Deserialize the specified msgStr. - /// - /// The deserialize. - /// Message string. - IAVIMMessage Deserialize(string msgStr); - - /// - /// Gets or sets the conversation identifier. - /// - /// The conversation identifier. - string ConversationId { get; set; } - - /// - /// Gets or sets from client identifier. - /// - /// From client identifier. - string FromClientId { get; set; } - - /// - /// Gets or sets the identifier. - /// - /// The identifier. - string Id { get; set; } - - /// - /// Gets or sets the server timestamp. - /// - /// The server timestamp. - long ServerTimestamp { get; set; } - - /// - /// Gets or sets the rcp timestamp. - /// - /// The rcp timestamp. - long RcpTimestamp { get; set; } - - long UpdatedAt { get; set; } - - - #region mention features. - /// - /// Gets or sets a value indicating whether this mention all. - /// - /// true if mention all; otherwise, false. - bool MentionAll { get; set; } - - /// - /// Gets or sets the mention list. - /// - /// The mention list. - IEnumerable MentionList { get; set; } - #endregion - - } -} diff --git a/RTM/Source/Public/ICacheEngine.cs b/RTM/Source/Public/ICacheEngine.cs deleted file mode 100644 index 1c20ec7..0000000 --- a/RTM/Source/Public/ICacheEngine.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - public interface ISQLStorage - { - - } -} diff --git a/RTM/Source/Public/ISignatureFactory.cs b/RTM/Source/Public/ISignatureFactory.cs deleted file mode 100644 index ffda11a..0000000 --- a/RTM/Source/Public/ISignatureFactory.cs +++ /dev/null @@ -1,131 +0,0 @@ -using LeanCloud; -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - - -namespace LeanCloud.Realtime -{ - /// - /// 对话操作的签名类型,比如讲一个 client id 加入到对话中 - /// - /// - public enum ConversationSignatureAction - { - /// - /// add 加入对话和邀请对方加入对话 - /// - Add, - /// - /// remove 当前 client Id 离开对话和将其他人踢出对话 - /// - Remove - } - - /// - /// - /// - public interface ISignatureFactory - { - - /// - /// 构建登录签名 - /// - /// 需要登录到云端服务器的 client Id - /// - Task CreateConnectSignature(string clientId); - - /// - /// - /// - /// - /// - /// - Task CreateStartConversationSignature(string clientId, IEnumerable targetIds); - - /// - /// - /// - /// - /// - /// - /// 需要签名的操作 - /// - Task CreateConversationSignature(string conversationId, string clientId, IEnumerable targetIds, ConversationSignatureAction action); - } - - internal class DefaulSiganatureFactory : ISignatureFactory - { - Task ISignatureFactory.CreateConnectSignature(string clientId) - { - return Task.FromResult(null); - } - - Task ISignatureFactory.CreateConversationSignature(string conversationId, string clientId, IEnumerable targetIds, ConversationSignatureAction action) - { - return Task.FromResult(null); - } - - Task ISignatureFactory.CreateStartConversationSignature(string clientId, IEnumerable targetIds) - { - return Task.FromResult(null); - } - } - - public class LeanEngineSignatureFactory : ISignatureFactory - { - public Task CreateConnectSignature(string clientId) - { - var data = new Dictionary(); - data.Add("client_id", clientId); - return AVCloud.CallFunctionAsync>("connect", data).OnSuccess(_ => - { - var jsonData = _.Result; - var s = jsonData["signature"].ToString(); - var n = jsonData["nonce"].ToString(); - var t = long.Parse(jsonData["timestamp"].ToString()); - var signature = new AVIMSignature(s, t, n); - return signature; - }); - } - - public Task CreateStartConversationSignature(string clientId, IEnumerable targetIds) - { - var data = new Dictionary(); - data.Add("client_id", clientId); - data.Add("members", targetIds.ToList()); - return AVCloud.CallFunctionAsync>("startConversation", data).OnSuccess(_ => - { - var jsonData = _.Result; - var s = jsonData["signature"].ToString(); - var n = jsonData["nonce"].ToString(); - var t = long.Parse(jsonData["timestamp"].ToString()); - var signature = new AVIMSignature(s, t, n); - return signature; - }); - } - - public Task CreateConversationSignature(string conversationId, string clientId, IEnumerable targetIds, ConversationSignatureAction action) - { - var actionList = new string[] { "invite", "kick" }; - var data = new Dictionary(); - data.Add("client_id", clientId); - data.Add("conv_id", conversationId); - data.Add("members", targetIds.ToList()); - data.Add("action", actionList[(int)action]); - return AVCloud.CallFunctionAsync>("oprateConversation", data).OnSuccess(_ => - { - var jsonData = _.Result; - var s = jsonData["signature"].ToString(); - var n = jsonData["nonce"].ToString(); - var t = long.Parse(jsonData["timestamp"].ToString()); - var signature = new AVIMSignature(s, t, n); - return signature; - }); - } - - } -} diff --git a/RTM/Source/Public/Listener/AVIMConversationListener.cs b/RTM/Source/Public/Listener/AVIMConversationListener.cs deleted file mode 100644 index 77f931a..0000000 --- a/RTM/Source/Public/Listener/AVIMConversationListener.cs +++ /dev/null @@ -1,256 +0,0 @@ -using LeanCloud.Storage.Internal; -using LeanCloud.Realtime.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - /// - /// 对话中成员变动的事件参数,它提供被操作的对话(Conversation),操作类型(AffectedType) - /// 受影响的成员列表(AffectedMembers) - /// - public class AVIMOnMembersChangedEventArgs : EventArgs - { - /// - /// 本次成员变动中被操作的具体对话(AVIMConversation)的对象 - /// - public AVIMConversation Conversation { get; set; } - - /// - /// 变动的类型 - /// - public AVIMConversationEventType AffectedType { get; internal set; } - - /// - /// 受影响的成员的 Client Ids - /// - public IList AffectedMembers { get; set; } - - /// - /// 操作人的 Client ClientId - /// - public string Oprator { get; set; } - - /// - /// 操作的时间,已转化为本地时间 - /// - public DateTime OpratedTime { get; set; } - } - - /// - /// 变动的类型,目前支持如下: - /// 1、Joined:当前 Client 主动加入,案例:当 A 主动加入到对话,A 将收到 Joined 事件响应,其余的成员收到 MembersJoined 事件响应 - /// 2、Left:当前 Client 主动退出,案例:当 A 从对话中退出,A 将收到 Left 事件响应,其余的成员收到 MembersLeft 事件响应 - /// 3、MembersJoined:某个成员加入(区别于Joined和Kicked),案例:当 A 把 B 加入到对话中,C 将收到 MembersJoined 事件响应 - /// 4、MembersLeft:某个成员加入(区别于Joined和Kicked),案例:当 A 把 B 从对话中剔除,C 将收到 MembersLeft 事件响应 - /// 5、Invited:当前 Client 被邀请加入,案例:当 A 被 B 邀请加入到对话中,A 将收到 Invited 事件响应,B 将收到 Joined ,其余的成员收到 MembersJoined 事件响应 - /// 6、Kicked:当前 Client 被剔除,案例:当 A 被 B 从对话中剔除,A 将收到 Kicked 事件响应,B 将收到 Left,其余的成员收到 MembersLeft 事件响应 - /// - public enum AVIMConversationEventType - { - /// - /// 自身主动加入 - /// - Joined = 1, - /// - /// 自身主动离开 - /// - Left, - /// - /// 他人加入 - /// - MembersJoined, - /// - /// 他人离开 - /// - MembersLeft, - /// - /// 自身被邀请加入 - /// - Invited, - /// - /// 自身被他人剔除 - /// - Kicked - } - - #region AVIMMembersJoinListener - //when Members joined or invited by member,this listener will invoke AVIMOnMembersJoinedEventArgs event. - /// - /// 对话中有成员加入的时候,在改对话中的其他成员都会触发 事件 - /// - public class AVIMMembersJoinListener : IAVIMListener - { - - private EventHandler m_OnMembersJoined; - /// - /// 有成员加入到对话时,触发的事件 - /// - public event EventHandler OnMembersJoined - { - add - { - m_OnMembersJoined += value; - } - remove - { - m_OnMembersJoined -= value; - } - } - - public virtual void OnNoticeReceived(AVIMNotice notice) - { - if (m_OnMembersJoined != null) - { - var joinedMembers = AVDecoder.Instance.DecodeList(notice.RawData["m"]); - var ivitedBy = notice.RawData["initBy"].ToString(); - var conersationId = notice.RawData["cid"].ToString(); - var args = new AVIMOnMembersJoinedEventArgs() - { - ConversationId = conersationId, - InvitedBy = ivitedBy, - JoinedMembers = joinedMembers - }; - m_OnMembersJoined.Invoke(this, args); - } - } - - public virtual bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "conv") return false; - if (!notice.RawData.ContainsKey("op")) return false; - var op = notice.RawData["op"].ToString(); - if (!op.Equals("members-joined")) return false; - return true; - } - } - #endregion - - #region AVIMMembersLeftListener - // when Members left or kicked by member,this listener will invoke AVIMOnMembersJoinedEventArgs event. - /// - /// 对话中有成员加入的时候,在改对话中的其他成员都会触发 OnMembersJoined 事件 - /// - public class AVIMMembersLeftListener : IAVIMListener - { - private EventHandler m_OnMembersLeft; - /// - /// 有成员加入到对话时,触发的事件 - /// - public event EventHandler OnMembersLeft - { - add - { - m_OnMembersLeft += value; - } - remove - { - m_OnMembersLeft -= value; - } - } - public virtual void OnNoticeReceived(AVIMNotice notice) - { - if (m_OnMembersLeft != null) - { - var leftMembers = AVDecoder.Instance.DecodeList(notice.RawData["m"]); - var kickedBy = notice.RawData["initBy"].ToString(); - var conersationId = notice.RawData["cid"].ToString(); - var args = new AVIMOnMembersLeftEventArgs() - { - ConversationId = conersationId, - KickedBy = kickedBy, - LeftMembers = leftMembers - }; - m_OnMembersLeft.Invoke(this, args); - } - } - - public virtual bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "conv") return false; - if (!notice.RawData.ContainsKey("op")) return false; - var op = notice.RawData["op"].ToString(); - if (!op.Equals("members-left")) return false; - return true; - } - } - #endregion - - #region AVIMInvitedListener - public class AVIMInvitedListener : IAVIMListener - { - private EventHandler m_OnInvited; - public event EventHandler OnInvited { - add { - m_OnInvited += value; - } remove { - m_OnInvited -= value; - } - } - public void OnNoticeReceived(AVIMNotice notice) - { - if (m_OnInvited != null) - { - var ivitedBy = notice.RawData["initBy"].ToString(); - var conersationId = notice.RawData["cid"].ToString(); - var args = new AVIMOnInvitedEventArgs() - { - ConversationId = conersationId, - InvitedBy = ivitedBy, - }; - m_OnInvited.Invoke(this, args); - } - } - - public bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "conv") return false; - if (!notice.RawData.ContainsKey("op")) return false; - var op = notice.RawData["op"].ToString(); - if (!op.Equals("joined")) return false; - return true; - } - } - #endregion - - #region AVIMKickedListener - public class AVIMKickedListener : IAVIMListener - { - private EventHandler m_OnKicked; - public event EventHandler OnKicked { - add { - m_OnKicked += value; - } remove { - m_OnKicked -= value; - } - } - public void OnNoticeReceived(AVIMNotice notice) - { - if (m_OnKicked != null) - { - var kickcdBy = notice.RawData["initBy"].ToString(); - var conersationId = notice.RawData["cid"].ToString(); - var args = new AVIMOnKickedEventArgs() - { - ConversationId = conersationId, - KickedBy = kickcdBy, - }; - m_OnKicked.Invoke(this, args); - } - } - - public bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "conv") return false; - if (!notice.RawData.ContainsKey("op")) return false; - var op = notice.RawData["op"].ToString(); - if (!op.Equals("left")) return false; - return true; - } - } - #endregion - -} diff --git a/RTM/Source/Public/Listener/ConversationUnreadListener.cs b/RTM/Source/Public/Listener/ConversationUnreadListener.cs deleted file mode 100644 index bd48b89..0000000 --- a/RTM/Source/Public/Listener/ConversationUnreadListener.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using LeanCloud.Realtime.Internal; - -namespace LeanCloud.Realtime -{ - internal class ConversationUnreadListener : IAVIMListener - { - internal class UnreadConversationNotice : IEqualityComparer - { - internal readonly object mutex = new object(); - internal IAVIMMessage LastUnreadMessage { get; set; } - internal string ConvId { get; set; } - internal int UnreadCount { get; set; } - - public bool Equals(UnreadConversationNotice x, UnreadConversationNotice y) - { - return x.ConvId == y.ConvId; - } - - public int GetHashCode(UnreadConversationNotice obj) - { - return obj.ConvId.GetHashCode(); - } - - internal void AutomicIncrement() - { - lock (mutex) - { - UnreadCount++; - } - } - } - internal static readonly object sMutex = new object(); - internal static long NotifTime; - internal static HashSet UnreadConversations; - static ConversationUnreadListener() - { - UnreadConversations = new HashSet(new UnreadConversationNotice()); - NotifTime = DateTime.Now.ToUnixTimeStamp(); - } - - internal static void UpdateNotice(IAVIMMessage message) - { - lock (sMutex) - { - var convValidators = UnreadConversations.Where(c => c.ConvId == message.ConversationId); - if (convValidators != null) - { - if (convValidators.Count() > 0) - { - var currentNotice = convValidators.FirstOrDefault(); - currentNotice.AutomicIncrement(); - currentNotice.LastUnreadMessage = message; - } - else - { - var currentThread = new UnreadConversationNotice(); - currentThread.ConvId = message.ConversationId; - currentThread.LastUnreadMessage = message; - currentThread.AutomicIncrement(); - UnreadConversations.Add(currentThread); - } - } - } - } - internal static void ClearUnread(string convId) - { - UnreadConversations.Remove(Get(convId)); - } - internal static IEnumerable FindAllConvIds() - { - lock (sMutex) - { - return ConversationUnreadListener.UnreadConversations.Select(c => c.ConvId); - } - } - - internal static UnreadConversationNotice Get(string convId) - { - lock (sMutex) - { - var unreadValidator = ConversationUnreadListener.UnreadConversations.Where(c => c.ConvId == convId); - if (unreadValidator != null) - { - if (unreadValidator.Count() > 0) - { - var notice = unreadValidator.FirstOrDefault(); - return notice; - } - } - return null; - } - } - - public void OnNoticeReceived(AVIMNotice notice) - { - lock (sMutex) - { - if (notice.RawData.ContainsKey("convs")) - { - var unreadRawData = notice.RawData["convs"] as List; - if (notice.RawData.ContainsKey("notifTime")) - { - long.TryParse(notice.RawData["notifTime"].ToString(), out NotifTime); - } - foreach (var data in unreadRawData) - { - var dataMap = data as IDictionary; - if (dataMap != null) - { - var convId = dataMap["cid"].ToString(); - var ucn = Get(convId); - if (ucn == null) ucn = new UnreadConversationNotice(); - - ucn.ConvId = convId; - var unreadCount = 0; - Int32.TryParse(dataMap["unread"].ToString(), out unreadCount); - ucn.UnreadCount = unreadCount; - - #region restore last message for the conversation - if (dataMap.ContainsKey("data")) - { - var msgStr = dataMap["data"].ToString(); - var messageObj = AVRealtime.FreeStyleMessageClassingController.Instantiate(msgStr, dataMap); - ucn.LastUnreadMessage = messageObj; - } - - UnreadConversations.Add(ucn); - #endregion - } - } - } - } - } - - public bool ProtocolHook(AVIMNotice notice) - { - return notice.CommandName == "unread"; - } - } -} diff --git a/RTM/Source/Public/Listener/GoAwayListener.cs b/RTM/Source/Public/Listener/GoAwayListener.cs deleted file mode 100644 index 57ecb62..0000000 --- a/RTM/Source/Public/Listener/GoAwayListener.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; - -namespace LeanCloud.Realtime { - /// - /// 强制被踢下线处理 - /// - internal class GoAwayListener : IAVIMListener { - Action onGoAway; - - public event Action OnGoAway { - add { - onGoAway += value; - } - remove { - onGoAway -= value; - } - } - - public void OnNoticeReceived(AVIMNotice notice) { - // TODO 退出并清理路由缓存 - onGoAway?.Invoke(); - } - - public bool ProtocolHook(AVIMNotice notice) { - return notice.CommandName == "goaway"; - } - } -} diff --git a/RTM/Source/Public/Listener/MessagePatchListener.cs b/RTM/Source/Public/Listener/MessagePatchListener.cs deleted file mode 100644 index b588190..0000000 --- a/RTM/Source/Public/Listener/MessagePatchListener.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LeanCloud.Realtime -{ - internal delegate void OnMessagePatch(IEnumerable messages); - internal class MessagePatchListener : IAVIMListener - { - public OnMessagePatch OnReceived { get; set; } - - public void OnNoticeReceived(AVIMNotice notice) - { - ICollection patchedMessages = new List(); - var msgObjs = notice.RawData["patches"] as IList; - if (msgObjs != null) - { - foreach (var msgObj in msgObjs) - { - var msgData = msgObj as IDictionary; - if (msgData != null) - { - var msgStr = msgData["data"] as string; - var message = AVRealtime.FreeStyleMessageClassingController.Instantiate(msgStr, msgData); - patchedMessages.Add(message); - } - } - } - if (OnReceived != null) - { - if (patchedMessages.Count > 0) - { - this.OnReceived(patchedMessages); - } - } - } - - public bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "patch") return false; - if (!notice.RawData.ContainsKey("op")) return false; - if (notice.RawData["op"].ToString() != "modify") return false; - return true; - } - } -} diff --git a/RTM/Source/Public/Listener/OfflineMessageListener.cs b/RTM/Source/Public/Listener/OfflineMessageListener.cs deleted file mode 100644 index 983ad8a..0000000 --- a/RTM/Source/Public/Listener/OfflineMessageListener.cs +++ /dev/null @@ -1,42 +0,0 @@ -using LeanCloud.Storage.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace LeanCloud.Realtime -{ - internal class OfflineMessageListener : IAVIMListener - { - private EventHandler m_OnOfflineMessageReceived; - public event EventHandler OnOfflineMessageReceived - { - add - { - m_OnOfflineMessageReceived += value; - } - remove - { - m_OnOfflineMessageReceived -= value; - } - } - public void OnNoticeReceived(AVIMNotice notice) - { - if (m_OnOfflineMessageReceived != null) - { - var msgStr = notice.RawData["msg"].ToString(); - var iMessage = AVRealtime.FreeStyleMessageClassingController.Instantiate(msgStr, notice.RawData); - var args = new AVIMMessageEventArgs(iMessage); - m_OnOfflineMessageReceived.Invoke(this, args); - } - - } - - public bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "direct") return false; - if (!notice.RawData.ContainsKey("offline")) return false; - return true; - } - } -} diff --git a/RTM/Source/Public/Listener/SessionListener.cs b/RTM/Source/Public/Listener/SessionListener.cs deleted file mode 100644 index aad4c54..0000000 --- a/RTM/Source/Public/Listener/SessionListener.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace LeanCloud.Realtime -{ - internal class SessionListener : IAVIMListener - { - private Action _onSessionClosed; - public event Action OnSessionClosed - { - add - { - _onSessionClosed += value; - } - remove - { - _onSessionClosed -= value; - } - } - public void OnNoticeReceived(AVIMNotice notice) - { - var code = 0; - if (notice.RawData.ContainsKey("code")) - { - int.TryParse(notice.RawData["code"].ToString(), out code); - } - - var reason = ""; - if (notice.RawData.ContainsKey("reason")) - { - reason = notice.RawData["reason"].ToString(); - } - - var detail = ""; - if (notice.RawData.ContainsKey("detail")) - { - detail = notice.RawData["detail"].ToString(); - } - - if (_onSessionClosed != null) - { - _onSessionClosed(code, reason, detail); - } - } - - public bool ProtocolHook(AVIMNotice notice) - { - if (notice.CommandName != "session") return false; - if (!notice.RawData.ContainsKey("op")) return false; - if (notice.RawData.ContainsKey("i")) return false; - if (notice.RawData["op"].ToString() != "closed") return false; - - return true; - } - } -} diff --git a/RTM/Source/Public/Unity/AVRealtimeBehavior.cs b/RTM/Source/Public/Unity/AVRealtimeBehavior.cs deleted file mode 100644 index fe84b52..0000000 --- a/RTM/Source/Public/Unity/AVRealtimeBehavior.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using LeanCloud.Realtime.Internal; -using LeanCloud.Storage.Internal; -using UnityEngine; -using UnityEngine.Networking; - -namespace LeanCloud.Realtime -{ - /// - /// AVRealtime initialize behavior. - /// - public class AVRealtimeBehavior : AVInitializeBehaviour - { - public string RTMRouter = null; - - //void OnApplicationQuit() - //{ - // if (AVRealtime.clients != null) - // { - // foreach (var item in AVRealtime.clients) - // { - // item.Value.LinkedRealtime.LogOut(); - // } - // } - //} - - //private void Update() - //{ - // var available = Application.internetReachability != NetworkReachability.NotReachable; - // if (AVRealtime.clients != null) - // foreach (var item in AVRealtime.clients) - // { - // if (item.Value != null) - // if (item.Value.LinkedRealtime != null) - // item.Value.LinkedRealtime.InvokeNetworkState(available); - // } - //} - - //public override void Awake() - //{ - // base.Awake(); - // StartCoroutine(InitializeRealtime()); - // gameObject.name = "AVRealtimeInitializeBehavior"; - //} - - //public IEnumerator InitializeRealtime() - //{ - // if (isRealtimeInitialized) - // { - // yield break; - // } - // isRealtimeInitialized = true; - // yield return FetchRouter(); - //} - - - //[SerializeField] - //public bool secure; - //private static bool isRealtimeInitialized = false; - //public string Server; - //private IDictionary routerState; - - //public IEnumerator FetchRouter() - //{ - // var router = RTMRouter; - // if (string.IsNullOrEmpty(router)) { - // var state = AVPlugins.Instance.AppRouterController.Get(); - // router = state.RealtimeRouterServer; - // } - // var url = string.Format("https://{0}/v1/route?appId={1}", router, applicationID); - // if (secure) - // { - // url += "&secure=1"; - // } - - // var request = new UnityWebRequest(url); - // request.downloadHandler = new DownloadHandlerBuffer(); - // yield return request.Send(); - - // if (request.isError) - // { - // throw new AVException(AVException.ErrorCode.ConnectionFailed, "can not reach router.", null); - // } - - // var result = request.downloadHandler.text; - // routerState = Json.Parse(result) as IDictionary; - // if (routerState.Keys.Count == 0) - // { - // throw new KeyNotFoundException("Can not get websocket url from server,please check the appId."); - // } - // var ttl = long.Parse(routerState["ttl"].ToString()); - // var expire = DateTime.Now.AddSeconds(ttl); - // routerState["expire"] = expire.ToUnixTimeStamp(UnixTimeStampUnit.Second); - // Server = routerState["server"].ToString(); - //} - - - } -}