diff --git a/Storage/Storage.Test/AppRouterTest.cs b/Storage/Storage.Test/AppRouterTest.cs
deleted file mode 100644
index 5d4d5c2..0000000
--- a/Storage/Storage.Test/AppRouterTest.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using NUnit.Framework;
-using System.Threading.Tasks;
-using LeanCloud.Storage.Internal;
-
-namespace LeanCloud.Test {
- public class AppRouterTest {
- [Test]
- public async Task GetServers() {
-
- }
- }
-}
diff --git a/Storage/Storage/Internal/AVCorePlugins.cs b/Storage/Storage/Internal/AVCorePlugins.cs
index 4b94af5..3f7b9f4 100644
--- a/Storage/Storage/Internal/AVCorePlugins.cs
+++ b/Storage/Storage/Internal/AVCorePlugins.cs
@@ -1,4 +1,5 @@
-
+using LeanCloud.Common;
+
namespace LeanCloud.Storage.Internal {
public class AVPlugins {
private static readonly object instanceMutex = new object();
@@ -52,7 +53,8 @@ namespace LeanCloud.Storage.Internal {
public AppRouterController AppRouterController {
get {
lock (mutex) {
- appRouterController = appRouterController ?? new AppRouterController();
+ var conf = AVClient.CurrentConfiguration;
+ appRouterController = appRouterController ?? new AppRouterController(conf.ApplicationId, conf.ApiServer);
return appRouterController;
}
}
diff --git a/Storage/Storage/Internal/Command/AVCommandRunner.cs b/Storage/Storage/Internal/Command/AVCommandRunner.cs
index c40bec5..bbd6887 100644
--- a/Storage/Storage/Internal/Command/AVCommandRunner.cs
+++ b/Storage/Storage/Internal/Command/AVCommandRunner.cs
@@ -5,9 +5,9 @@ using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
-using System.Text;
using System.Linq;
using Newtonsoft.Json;
+using LeanCloud.Common;
namespace LeanCloud.Storage.Internal {
///
@@ -44,6 +44,7 @@ namespace LeanCloud.Storage.Internal {
httpClient.DefaultRequestHeaders.Add("X-LC-Prod", AVClient.UseProduction ? USE_PRODUCTION : USE_DEVELOPMENT);
}
+
///
///
///
@@ -71,14 +72,14 @@ namespace LeanCloud.Storage.Internal {
!string.IsNullOrEmpty(AVUser.CurrentUser.SessionToken)) {
request.Headers.Add("X-LC-Session", AVUser.CurrentUser.SessionToken);
}
- PrintRequest(httpClient, request, content);
+ HttpUtils.PrintRequest(httpClient, request, content);
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
request.Dispose();
var resultString = await response.Content.ReadAsStringAsync();
response.Dispose();
- PrintResponse(response, resultString);
+ HttpUtils.PrintResponse(response, resultString);
var ret = new Tuple(response.StatusCode, resultString);
@@ -115,33 +116,65 @@ namespace LeanCloud.Storage.Internal {
return new Tuple(responseCode, default);
}
- static void PrintRequest(HttpClient client, HttpRequestMessage request, string content) {
- 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())}");
+
+ // TODO (hallucinogen): move this out to a class to be used by Analytics
+ private const int MaximumBatchSize = 50;
+
+ internal async Task>> ExecuteBatchRequests(IList requests,
+ CancellationToken cancellationToken) {
+ var results = new List>();
+ int batchSize = requests.Count;
+
+ IEnumerable remaining = requests;
+ while (batchSize > MaximumBatchSize) {
+ var process = remaining.Take(MaximumBatchSize).ToList();
+ remaining = remaining.Skip(MaximumBatchSize);
+
+ results.AddRange(await ExecuteBatchRequest(process, cancellationToken));
+
+ batchSize = remaining.Count();
}
- foreach (var header in request.Headers) {
- sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}");
- }
- foreach (var header in request.Content.Headers) {
- sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}");
- }
- sb.AppendLine($"Content: {content}");
- sb.AppendLine("=== HTTP Request End ===");
- AVClient.PrintLog(sb.ToString());
+ results.AddRange(await ExecuteBatchRequest(remaining.ToList(), cancellationToken));
+
+ return results;
}
- static void PrintResponse(HttpResponseMessage response, string content) {
- StringBuilder sb = new StringBuilder();
- sb.AppendLine("=== HTTP Response Start ===");
- sb.AppendLine($"URL: {response.RequestMessage.RequestUri}");
- sb.AppendLine($"Content: {content}");
- sb.AppendLine("=== HTTP Response End ===");
- AVClient.PrintLog(sb.ToString());
+ internal async Task>> ExecuteBatchRequest(IList requests, CancellationToken cancellationToken) {
+ var tasks = new List>>();
+ int batchSize = requests.Count;
+ var tcss = new List>>();
+ for (int i = 0; i < batchSize; ++i) {
+ var tcs = new TaskCompletionSource>();
+ tcss.Add(tcs);
+ tasks.Add(tcs.Task);
+ }
+
+ var encodedRequests = requests.Select(r => {
+ var results = new Dictionary {
+ { "method", r.Method.Method },
+ { "path", $"/{AVClient.APIVersion}/{r.Path}" },
+ };
+
+ if (r.Content != null) {
+ results["body"] = r.Content;
+ }
+ return results;
+ }).Cast
/// The objects to delete.
- public static Task DeleteAllAsync(IEnumerable objects, CancellationToken cancellationToken = default)
+ public static async Task DeleteAllAsync(IEnumerable objects, CancellationToken cancellationToken = default)
where T : AVObject {
var uniqueObjects = new HashSet(objects.OfType().ToList(),
new IdentityEqualityComparer());
- return EnqueueForAll(uniqueObjects, toAwait => {
- var states = uniqueObjects.Select(t => t.state).ToList();
- return toAwait.OnSuccess(_ => {
- var deleteTasks = ObjectController.DeleteAllAsync(states, cancellationToken);
- return Task.WhenAll(deleteTasks);
- }).Unwrap().OnSuccess(t => {
- // Dirty all objects in memory.
- foreach (var obj in uniqueObjects) {
- obj.IsDirty = true;
- }
-
- return (object)null;
- });
- }, cancellationToken);
+ var states = uniqueObjects.Select(t => t.state).ToList();
+ await ObjectController.DeleteAllAsync(states, cancellationToken);
+ foreach (var obj in uniqueObjects) {
+ obj.IsDirty = true;
+ }
}
#endregion
diff --git a/Storage/Storage/Public/AVObject2.cs b/Storage/Storage/Public/AVObject2.cs
deleted file mode 100644
index fe68ca3..0000000
--- a/Storage/Storage/Public/AVObject2.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Concurrent;
-using System.Collections;
-
-namespace Storage.Public {
- public class AVObject2 : IDictionary {
- ConcurrentDictionary data;
-
- public object this[string key] { get => ((IDictionary)data)[key]; set => ((IDictionary)data)[key] = value; }
-
- public ICollection Keys => ((IDictionary)data).Keys;
-
- public ICollection Values => ((IDictionary)data).Values;
-
- public int Count => ((IDictionary)data).Count;
-
- public bool IsReadOnly => ((IDictionary)data).IsReadOnly;
-
- public void Add(string key, object value) {
- ((IDictionary)data).Add(key, value);
- }
-
- public void Add(KeyValuePair item) {
- ((IDictionary)data).Add(item);
- }
-
- public void Clear() {
- ((IDictionary)data).Clear();
- }
-
- public bool Contains(KeyValuePair item) {
- return ((IDictionary)data).Contains(item);
- }
-
- public bool ContainsKey(string key) {
- return ((IDictionary)data).ContainsKey(key);
- }
-
- public void CopyTo(KeyValuePair[] array, int arrayIndex) {
- ((IDictionary)data).CopyTo(array, arrayIndex);
- }
-
- public IEnumerator> GetEnumerator() {
- return ((IDictionary)data).GetEnumerator();
- }
-
- public bool Remove(string key) {
- return ((IDictionary)data).Remove(key);
- }
-
- public bool Remove(KeyValuePair item) {
- return ((IDictionary)data).Remove(item);
- }
-
- public bool TryGetValue(string key, out object value) {
- return ((IDictionary)data).TryGetValue(key, out value);
- }
-
- IEnumerator IEnumerable.GetEnumerator() {
- return ((IDictionary)data).GetEnumerator();
- }
- }
-}
diff --git a/Test/Common.Test/Test.cs b/Test/Common.Test/Test.cs
new file mode 100644
index 0000000..0951d12
--- /dev/null
+++ b/Test/Common.Test/Test.cs
@@ -0,0 +1,7 @@
+using System;
+namespace Common.Test {
+ public class Test {
+ public Test() {
+ }
+ }
+}