From f171cee759d47a9d8ee9dc1761ac8671abf9a9fd Mon Sep 17 00:00:00 2001 From: oneRain Date: Fri, 1 Nov 2019 18:19:35 +0800 Subject: [PATCH] =?UTF-8?q?*=20AppRouterController.cs:=20chore:=20?= =?UTF-8?q?=E6=8F=90=E5=8F=96=E5=85=AC=E5=85=B1=E6=A8=A1=E5=9D=97=EF=BC=8C?= =?UTF-8?q?=E5=92=8C=20Play=20=E5=85=B1=E4=BA=AB=E3=80=82=E5=8C=85?= =?UTF-8?q?=E6=8B=AC=20=20=20AppRouter=EF=BC=8CJson=EF=BC=8C=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * csharp-sdk.sln: * RTM.csproj: * Common.csproj: * HttpUtils.cs: * Tests.cs: * JsonExtensions.cs: * Storage.csproj: * JustTest.cs: * AppRouterTest.cs: * AppRouterState.cs: * ObjectTest.cs: * Common.Test.csproj: * Common.Test.csproj: * AppRouterTest.cs: * Storage.Test.csproj: * AVObjectController.cs: --- .../Internal/AppRouter/AppRouterController.cs | 64 --------------- Common/AppRouter/AppRouterController.cs | 77 +++++++++++++++++++ .../AppRouter/AppRouterState.cs | 3 +- Common/Common.csproj | 14 ++++ Common/Http/HttpUtils.cs | 49 ++++++++++++ .../Json}/JsonExtensions.cs | 5 +- RTM/RTM/RTM.csproj | 2 +- Storage/Storage.Test/AppRouterTest.cs | 6 +- Storage/Storage.Test/JustTest.cs | 10 +++ Storage/Storage.Test/ObjectTest.cs | 12 ++- Storage/Storage.Test/Storage.Test.csproj | 1 - .../Object/Controller/AVObjectController.cs | 26 +++---- Storage/Storage/Storage.csproj | 2 +- Test/Common.Test/AppRouterTest.cs | 45 +++++++++++ Test/Common.Test/Common.Test.csproj | 18 +++++ csharp-sdk.sln | 24 +++--- 16 files changed, 254 insertions(+), 104 deletions(-) delete mode 100644 AppRouter/AppRouter/Internal/AppRouter/AppRouterController.cs create mode 100644 Common/AppRouter/AppRouterController.cs rename {AppRouter/AppRouter/Internal => Common}/AppRouter/AppRouterState.cs (98%) create mode 100644 Common/Common.csproj create mode 100644 Common/Http/HttpUtils.cs rename {Storage/Storage/Internal/Utilities => Common/Json}/JsonExtensions.cs (93%) create mode 100644 Test/Common.Test/AppRouterTest.cs create mode 100644 Test/Common.Test/Common.Test.csproj diff --git a/AppRouter/AppRouter/Internal/AppRouter/AppRouterController.cs b/AppRouter/AppRouter/Internal/AppRouter/AppRouterController.cs deleted file mode 100644 index f56933a..0000000 --- a/AppRouter/AppRouter/Internal/AppRouter/AppRouterController.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Net.Http; -using Newtonsoft.Json; - -namespace LeanCloud.Storage.Internal { - public class AppRouterController { - private AppRouterState currentState; - - private readonly SemaphoreSlim locker = new SemaphoreSlim(1); - - public async Task Get(string appId) { - if (string.IsNullOrEmpty(appId)) { - throw new ArgumentNullException(nameof(appId)); - } - - if (currentState != null && !currentState.IsExpired) { - return currentState; - } - - await locker.WaitAsync(); - try { - if (currentState == null) { - try { - currentState = await QueryAsync(appId); - } catch (Exception) { - currentState = AppRouterState.GetFallbackServers(appId); - } - } - return currentState; - } finally { - locker.Release(); - } - } - - async Task QueryAsync(string appId) { - Console.WriteLine("QueryAsync"); - - string url = string.Format("https://app-router.com/2/route?appId={0}", appId); - - HttpClient client = new HttpClient(); - HttpRequestMessage request = new HttpRequestMessage { - RequestUri = new Uri(url), - Method = HttpMethod.Get - }; - - HttpResponseMessage response = await client.SendAsync(request); - client.Dispose(); - request.Dispose(); - - string content = await response.Content.ReadAsStringAsync(); - response.Dispose(); - - AppRouterState state = JsonConvert.DeserializeObject(content); - state.Source = "router"; - return state; - } - - public void Clear() { - currentState = null; - } - } -} diff --git a/Common/AppRouter/AppRouterController.cs b/Common/AppRouter/AppRouterController.cs new file mode 100644 index 0000000..6a8ea2b --- /dev/null +++ b/Common/AppRouter/AppRouterController.cs @@ -0,0 +1,77 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Net.Http; +using Newtonsoft.Json; + +namespace LeanCloud.Common { + public class AppRouterController { + private AppRouterState currentState; + + private readonly SemaphoreSlim locker = new SemaphoreSlim(1); + + public async Task Get(string appId) { + if (string.IsNullOrEmpty(appId)) { + throw new ArgumentNullException(nameof(appId)); + } + + if (currentState != null && !currentState.IsExpired) { + return currentState; + } + + await locker.WaitAsync(); + try { + if (currentState == null) { + try { + currentState = await QueryAsync(appId); + } catch (Exception) { + currentState = AppRouterState.GetFallbackServers(appId); + } + } + return currentState; + } finally { + locker.Release(); + } + } + + async Task QueryAsync(string appId) { + HttpClient client = null; + HttpRequestMessage request = null; + HttpResponseMessage response = null; + + try { + string url = string.Format("https://app-router.com/2/route?appId={0}", appId); + + client = new HttpClient(); + request = new HttpRequestMessage { + RequestUri = new Uri(url), + Method = HttpMethod.Get + }; + HttpUtils.PrintRequest(client, request); + + response = await client.SendAsync(request); + string content = await response.Content.ReadAsStringAsync(); + HttpUtils.PrintResponse(response); + + AppRouterState state = JsonConvert.DeserializeObject(content); + state.Source = "router"; + + return state; + } finally { + if (client != null) { + client.Dispose(); + } + if (request != null) { + request.Dispose(); + } + if (response != null) { + response.Dispose(); + } + } + } + + public void Clear() { + currentState = null; + } + } +} diff --git a/AppRouter/AppRouter/Internal/AppRouter/AppRouterState.cs b/Common/AppRouter/AppRouterState.cs similarity index 98% rename from AppRouter/AppRouter/Internal/AppRouter/AppRouterState.cs rename to Common/AppRouter/AppRouterState.cs index 16533ba..f163ec7 100644 --- a/AppRouter/AppRouter/Internal/AppRouter/AppRouterState.cs +++ b/Common/AppRouter/AppRouterState.cs @@ -1,7 +1,7 @@ using System; using Newtonsoft.Json; -namespace LeanCloud.Storage.Internal { +namespace LeanCloud.Common { public class AppRouterState { const string EAST_CHINA_SUFFIX = "-9Nh9j0Va"; const string US_SUFFIX = "-MdYXbMMI"; @@ -93,6 +93,5 @@ namespace LeanCloud.Storage.Internal { }; } } - } } \ No newline at end of file diff --git a/Common/Common.csproj b/Common/Common.csproj new file mode 100644 index 0000000..74f5fd0 --- /dev/null +++ b/Common/Common.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0 + + + + + + + + + + diff --git a/Common/Http/HttpUtils.cs b/Common/Http/HttpUtils.cs new file mode 100644 index 0000000..22f2d6e --- /dev/null +++ b/Common/Http/HttpUtils.cs @@ -0,0 +1,49 @@ +using System.Linq; +using System.Text; +using System.Net.Http; + +namespace LeanCloud.Common { + public class HttpUtils { + public static void PrintRequest(HttpClient client, HttpRequestMessage request, string content = null) { + if (client == null) { + return; + } + if (request == null) { + return; + } + StringBuilder sb = new StringBuilder(); + sb.AppendLine("=== HTTP Request Start ==="); + sb.AppendLine($"URL: {request.RequestUri}"); + sb.AppendLine($"Method: {request.Method}"); + sb.AppendLine($"Headers: "); + foreach (var header in client.DefaultRequestHeaders) { + sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}"); + } + foreach (var header in request.Headers) { + sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}"); + } + if (request.Content != null) { + foreach (var header in request.Content.Headers) { + sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}"); + } + } + if (!string.IsNullOrEmpty(content)) { + sb.AppendLine($"Content: {content}"); + } + sb.AppendLine("=== HTTP Request End ==="); + Logger.Debug(sb.ToString()); + } + + public static void PrintResponse(HttpResponseMessage response, string content = null) { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("=== HTTP Response Start ==="); + sb.AppendLine($"URL: {response.RequestMessage.RequestUri}"); + sb.AppendLine($"Status Code: {response.StatusCode}"); + if (!string.IsNullOrEmpty(content)) { + sb.AppendLine($"Content: {content}"); + } + sb.AppendLine("=== HTTP Response End ==="); + Logger.Debug(sb.ToString()); + } + } +} diff --git a/Storage/Storage/Internal/Utilities/JsonExtensions.cs b/Common/Json/JsonExtensions.cs similarity index 93% rename from Storage/Storage/Internal/Utilities/JsonExtensions.cs rename to Common/Json/JsonExtensions.cs index 43fe197..d0a131b 100644 --- a/Storage/Storage/Internal/Utilities/JsonExtensions.cs +++ b/Common/Json/JsonExtensions.cs @@ -1,8 +1,7 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; using System.Threading.Tasks; -namespace LeanCloud.Storage.Internal { +namespace LeanCloud.Common { /// /// 为 Json 解析提供异步接口 /// diff --git a/RTM/RTM/RTM.csproj b/RTM/RTM/RTM.csproj index ffa2b30..5f49628 100644 --- a/RTM/RTM/RTM.csproj +++ b/RTM/RTM/RTM.csproj @@ -2,6 +2,7 @@ netstandard2.0 + 0.1.0 @@ -9,7 +10,6 @@ - diff --git a/Storage/Storage.Test/AppRouterTest.cs b/Storage/Storage.Test/AppRouterTest.cs index 05ed299..5d4d5c2 100644 --- a/Storage/Storage.Test/AppRouterTest.cs +++ b/Storage/Storage.Test/AppRouterTest.cs @@ -6,11 +6,7 @@ namespace LeanCloud.Test { public class AppRouterTest { [Test] public async Task GetServers() { - var appRouter = new AppRouterController(); - for (int i = 0; i < 1000; i++) { - var state = await appRouter.Get("BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz"); - TestContext.Out.WriteLine(state.ApiServer); - } + } } } diff --git a/Storage/Storage.Test/JustTest.cs b/Storage/Storage.Test/JustTest.cs index a8f142c..ef36b6d 100644 --- a/Storage/Storage.Test/JustTest.cs +++ b/Storage/Storage.Test/JustTest.cs @@ -27,6 +27,16 @@ namespace LeanCloud.Test { } } + [Test] + public void Zip() { + List l1 = new List { 1, 2, 3, 4 }; + List l2 = new List { 1, 1, 2 }; + var l3 = l1.Zip(l2, (e1, e2) => $"{e1}-{e2}"); + foreach (var e in l3) { + TestContext.Out.WriteLine($"{e}"); + } + } + [Test] public void GenericType() { List list = new List { 1, 1, 2, 3, 5, 8 }; diff --git a/Storage/Storage.Test/ObjectTest.cs b/Storage/Storage.Test/ObjectTest.cs index d1821b2..6b10b29 100644 --- a/Storage/Storage.Test/ObjectTest.cs +++ b/Storage/Storage.Test/ObjectTest.cs @@ -167,11 +167,21 @@ namespace LeanCloud.Test { List objList = new List(); for (int i = 0; i < 5; i++) { AVObject obj = AVObject.Create("Foo"); + obj.ACL = new AVACL { + PublicReadAccess = true, + PublicWriteAccess = i % 2 == 0 + }; obj["content"] = "batch object"; objList.Add(obj); } await objList.SaveAllAsync(); - await AVObject.DeleteAllAsync(objList); + try { + await AVObject.DeleteAllAsync(objList); + } catch (AggregateException e) { + foreach (AVException ie in e.InnerExceptions) { + TestContext.Out.WriteLine($"{ie.Code} : {ie.Message}"); + } + } } [Test] diff --git a/Storage/Storage.Test/Storage.Test.csproj b/Storage/Storage.Test/Storage.Test.csproj index 55e014f..99a9d07 100644 --- a/Storage/Storage.Test/Storage.Test.csproj +++ b/Storage/Storage.Test/Storage.Test.csproj @@ -16,6 +16,5 @@ - diff --git a/Storage/Storage/Internal/Object/Controller/AVObjectController.cs b/Storage/Storage/Internal/Object/Controller/AVObjectController.cs index 0938207..2269658 100644 --- a/Storage/Storage/Internal/Object/Controller/AVObjectController.cs +++ b/Storage/Storage/Internal/Object/Controller/AVObjectController.cs @@ -122,7 +122,7 @@ namespace LeanCloud.Storage.Internal { return tasks; } - private IList>> ExecuteBatchRequest(IList requests, + private async Task>>> ExecuteBatchRequest(IList requests, CancellationToken cancellationToken) { var tasks = new List>>(); int batchSize = requests.Count; @@ -151,26 +151,16 @@ namespace LeanCloud.Storage.Internal { { "requests", encodedRequests } } }; - AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken).ContinueWith(t => { - if (t.IsFaulted || t.IsCanceled) { - foreach (var tcs in tcss) { - if (t.IsFaulted) { - tcs.TrySetException(t.Exception); - } else if (t.IsCanceled) { - tcs.TrySetCanceled(); - } - } - return; - } - var resultsArray = t.Result.Item2; + try { + var response = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken); + var resultsArray = response.Item2; int resultLength = resultsArray.Count; if (resultLength != batchSize) { foreach (var tcs in tcss) { tcs.TrySetException(new InvalidOperationException( "Batch command result count expected: " + batchSize + " but was: " + resultLength + ".")); } - return; } for (int i = 0; i < batchSize; ++i) { @@ -188,9 +178,11 @@ namespace LeanCloud.Storage.Internal { "Invalid batch command response.")); } } - }); - - return tasks; + } catch (Exception e) { + foreach (var tcs in tcss) { + tcs.TrySetException(e); + } + } } } } diff --git a/Storage/Storage/Storage.csproj b/Storage/Storage/Storage.csproj index 47ae659..05ebf04 100644 --- a/Storage/Storage/Storage.csproj +++ b/Storage/Storage/Storage.csproj @@ -12,6 +12,6 @@ - + diff --git a/Test/Common.Test/AppRouterTest.cs b/Test/Common.Test/AppRouterTest.cs new file mode 100644 index 0000000..06a9038 --- /dev/null +++ b/Test/Common.Test/AppRouterTest.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using NUnit.Framework; +using LeanCloud.Common; + +namespace Common.Test { + public class Tests { + static void Print(LogLevel level, string info) { + switch (level) { + case LogLevel.Debug: + TestContext.Out.WriteLine($"[DEBUG] {info}"); + break; + case LogLevel.Warn: + TestContext.Out.WriteLine($"[WARNING] {info}"); + break; + case LogLevel.Error: + TestContext.Out.WriteLine($"[ERROR] {info}"); + break; + default: + TestContext.Out.WriteLine(info); + break; + } + } + + [SetUp] + public void SetUp() { + TestContext.Out.WriteLine("Set up"); + Logger.LogDelegate += Print; + } + + [TearDown] + public void TearDown() { + TestContext.Out.WriteLine("Tear down"); + Logger.LogDelegate -= Print; + } + + [Test] + public async Task AppRouter() { + var appRouter = new AppRouterController(); + for (int i = 0; i < 100; i++) { + var state = await appRouter.Get("BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz"); + TestContext.Out.WriteLine(state.ApiServer); + } + } + } +} \ No newline at end of file diff --git a/Test/Common.Test/Common.Test.csproj b/Test/Common.Test/Common.Test.csproj new file mode 100644 index 0000000..89c6f61 --- /dev/null +++ b/Test/Common.Test/Common.Test.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp3.0 + + false + + + + + + + + + + + + diff --git a/csharp-sdk.sln b/csharp-sdk.sln index 95fe199..b774817 100644 --- a/csharp-sdk.sln +++ b/csharp-sdk.sln @@ -27,14 +27,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiveQuery.Test", "LiveQuery EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage.Test", "Storage\Storage.Test\Storage.Test.csproj", "{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppRouter", "AppRouter", "{1F05195D-2CAA-4214-8DAE-FE14A6B905DD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppRouter", "AppRouter\AppRouter\AppRouter.csproj", "{D34FC092-042A-44CE-A9E2-56B996BDCF42}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage", "Storage\Storage\Storage.csproj", "{59DA32A0-4CD3-424A-8584-D08B8D1E2B98}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RTM", "RTM\RTM\RTM.csproj", "{D4A30F70-AAED-415D-B940-023B3D7241EE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{C827DA2F-6AB4-48D8-AB5B-6DAB925F8933}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Test", "Test\Common.Test\Common.Test.csproj", "{4DF4E0F4-1013-477F-ADA6-BFAFD9312335}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -77,10 +79,6 @@ Global {BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Release|Any CPU.Build.0 = Release|Any CPU - {D34FC092-042A-44CE-A9E2-56B996BDCF42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D34FC092-042A-44CE-A9E2-56B996BDCF42}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D34FC092-042A-44CE-A9E2-56B996BDCF42}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D34FC092-042A-44CE-A9E2-56B996BDCF42}.Release|Any CPU.Build.0 = Release|Any CPU {59DA32A0-4CD3-424A-8584-D08B8D1E2B98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {59DA32A0-4CD3-424A-8584-D08B8D1E2B98}.Debug|Any CPU.Build.0 = Debug|Any CPU {59DA32A0-4CD3-424A-8584-D08B8D1E2B98}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -89,6 +87,14 @@ Global {D4A30F70-AAED-415D-B940-023B3D7241EE}.Debug|Any CPU.Build.0 = Debug|Any CPU {D4A30F70-AAED-415D-B940-023B3D7241EE}.Release|Any CPU.ActiveCfg = Release|Any CPU {D4A30F70-AAED-415D-B940-023B3D7241EE}.Release|Any CPU.Build.0 = Release|Any CPU + {14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}.Release|Any CPU.Build.0 = Release|Any CPU + {4DF4E0F4-1013-477F-ADA6-BFAFD9312335}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DF4E0F4-1013-477F-ADA6-BFAFD9312335}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DF4E0F4-1013-477F-ADA6-BFAFD9312335}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DF4E0F4-1013-477F-ADA6-BFAFD9312335}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {659D19F0-9A40-42C0-886C-555E64F16848} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18} @@ -100,9 +106,9 @@ Global {3251B4D8-D11A-4D90-8626-27FEE266B066} = {5B895B7A-1F6E-40A5-8081-43B334D2C076} {F907012C-74DF-4575-AFE6-E8DAACC26D24} = {5B895B7A-1F6E-40A5-8081-43B334D2C076} {BE05B492-78CD-47CA-9F48-C3E9B4813AFF} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18} - {D34FC092-042A-44CE-A9E2-56B996BDCF42} = {1F05195D-2CAA-4214-8DAE-FE14A6B905DD} {59DA32A0-4CD3-424A-8584-D08B8D1E2B98} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18} {D4A30F70-AAED-415D-B940-023B3D7241EE} = {64D8F9A1-BA44-459C-817C-788B4EBC0B9F} + {4DF4E0F4-1013-477F-ADA6-BFAFD9312335} = {C827DA2F-6AB4-48D8-AB5B-6DAB925F8933} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution version = 0.1.0