diff --git a/Storage/Storage.Test/ObjectControllerTests.cs b/Storage/Storage.Test/ObjectControllerTests.cs index 2be9b9e..f03e848 100644 --- a/Storage/Storage.Test/ObjectControllerTests.cs +++ b/Storage/Storage.Test/ObjectControllerTests.cs @@ -10,6 +10,7 @@ namespace LeanCloudTests { AVClient.Initialize(new AVClient.Configuration { ApplicationId = "BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz", ApplicationKey = "pbf6Nk5seyjilexdpyrPwjSp", + ApiServer = "https://avoscloud.com" }); AVClient.HttpLog(TestContext.Out.WriteLine); } diff --git a/Storage/Storage.Test/QueryTest.cs b/Storage/Storage.Test/QueryTest.cs new file mode 100644 index 0000000..005e0ad --- /dev/null +++ b/Storage/Storage.Test/QueryTest.cs @@ -0,0 +1,26 @@ +using NUnit.Framework; +using System; +using System.Threading.Tasks; +using LeanCloud; + +namespace LeanCloudTests { + public class QueryTest { + [SetUp] + public void SetUp() { + AVClient.Initialize(new AVClient.Configuration { + ApplicationId = "BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz", + ApplicationKey = "pbf6Nk5seyjilexdpyrPwjSp", + RTMServer = "https://router-g0-push.avoscloud.com", + }); + AVClient.HttpLog(TestContext.Out.WriteLine); + } + + [Test] + public async Task TestQuery() { + var query = new AVQuery("Foo"); + query.WhereEqualTo("content", "hello, world"); + var count = await query.CountAsync(); + Assert.Greater(count, 8); + } + } +} diff --git a/Storage/Storage/Internal/Cloud/Controller/AVCloudCodeController.cs b/Storage/Storage/Internal/Cloud/Controller/AVCloudCodeController.cs index c6fa216..947ac08 100644 --- a/Storage/Storage/Internal/Cloud/Controller/AVCloudCodeController.cs +++ b/Storage/Storage/Internal/Cloud/Controller/AVCloudCodeController.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using LeanCloud.Utilities; -using LeanCloud.Storage.Internal; +using System.Net.Http; namespace LeanCloud.Storage.Internal { @@ -21,11 +21,11 @@ namespace LeanCloud.Storage.Internal string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand(string.Format("functions/{0}", Uri.EscapeUriString(name)), - method: "POST", - sessionToken: sessionToken, - data: NoObjectsEncoder.Instance.Encode(parameters) as IDictionary); - + var command = new EngineCommand { + Path = $"functions/{Uri.EscapeUriString(name)}", + Method = HttpMethod.Post, + Content = parameters + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary; @@ -39,11 +39,11 @@ namespace LeanCloud.Storage.Internal public Task RPCFunction(string name, IDictionary parameters, string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand(string.Format("call/{0}", Uri.EscapeUriString(name)), - method: "POST", - sessionToken: sessionToken, - data: PointerOrLocalIdEncoder.Instance.Encode(parameters) as IDictionary); - + var command = new EngineCommand { + Path = $"call/{Uri.EscapeUriString(name)}", + Method = HttpMethod.Post, + Content = parameters + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary; diff --git a/Storage/Storage/Internal/Command/AVCommand.cs b/Storage/Storage/Internal/Command/AVCommand.cs index 3a373ca..43a972f 100644 --- a/Storage/Storage/Internal/Command/AVCommand.cs +++ b/Storage/Storage/Internal/Command/AVCommand.cs @@ -12,158 +12,30 @@ namespace LeanCloud.Storage.Internal /// AVCommand is an with pre-populated /// headers. /// - public class AVCommand : HttpRequest - { - public object Body { + public class AVCommand { + // 不同服务对应的服务器地址不同 + public virtual string Server => AVClient.CurrentConfiguration.ApiServer; + + public string Path { get; set; } - public override Stream Data { + public HttpMethod Method { + get; set; + } + + public Dictionary Headers { + get; set; + } + + public object Content { + get; set; + } + + public Uri Uri { get { - return new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(Body))); + return new Uri($"{Server}/{AVClient.APIVersion}/{Path}"); } } - - public AVCommand(string relativeUri, - string method, - string sessionToken = null, - IList> headers = null, - object data = null) - { - var state = AVPlugins.Instance.AppRouterController.Get(); - var urlTemplate = "https://{0}/{1}/{2}"; - AVClient.Configuration configuration = AVClient.CurrentConfiguration; - var apiVersion = "1.1"; - if (relativeUri.StartsWith("push", StringComparison.Ordinal) || - relativeUri.StartsWith("installations", StringComparison.Ordinal)) { - Uri = new Uri(string.Format(urlTemplate, state.PushServer, apiVersion, relativeUri)); - if (configuration.PushServer != null) { - Uri = new Uri(string.Format("{0}{1}/{2}", configuration.PushServer, apiVersion, relativeUri)); - } - } else if (relativeUri.StartsWith("stats", StringComparison.Ordinal) || - relativeUri.StartsWith("always_collect", StringComparison.Ordinal) || - relativeUri.StartsWith("statistics", StringComparison.Ordinal)) { - Uri = new Uri(string.Format(urlTemplate, state.StatsServer, apiVersion, relativeUri)); - if (configuration.StatsServer != null) { - Uri = new Uri(string.Format("{0}{1}/{2}", configuration.StatsServer, apiVersion, relativeUri)); - } - } else if (relativeUri.StartsWith("functions", StringComparison.Ordinal) || - relativeUri.StartsWith("call", StringComparison.Ordinal)) { - Uri = new Uri(string.Format(urlTemplate, state.EngineServer, apiVersion, relativeUri)); - - if (configuration.EngineServer != null) { - Uri = new Uri(string.Format("{0}{1}/{2}", configuration.EngineServer, apiVersion, relativeUri)); - } - } else { - Uri = new Uri(string.Format(urlTemplate, state.ApiServer, apiVersion, relativeUri)); - - if (configuration.ApiServer != null) { - Uri = new Uri(string.Format("{0}{1}/{2}", configuration.ApiServer, apiVersion, relativeUri)); - } - } - switch (method) { - case "GET": - Method = HttpMethod.Get; - break; - case "POST": - Method = HttpMethod.Post; - break; - case "DELETE": - Method = HttpMethod.Delete; - break; - case "PUT": - Method = HttpMethod.Put; - break; - case "HEAD": - Method = HttpMethod.Head; - break; - case "TRACE": - Method = HttpMethod.Trace; - break; - default: - break; - } - Body = data; - Headers = new List>(headers ?? Enumerable.Empty>()); - - string useProduction = AVClient.UseProduction ? "1" : "0"; - Headers.Add(new KeyValuePair("X-LC-Prod", useProduction)); - - if (!string.IsNullOrEmpty(sessionToken)) { - Headers.Add(new KeyValuePair("X-LC-Session", sessionToken)); - } - - Headers.Add(new KeyValuePair("Content-Type", "application/json")); - } - - //public AVCommand(string relativeUri, - // string method, - // string sessionToken = null, - // IList> headers = null, - // Stream stream = null, - // string contentType = null) - //{ - // var state = AVPlugins.Instance.AppRouterController.Get(); - // var urlTemplate = "https://{0}/{1}/{2}"; - // AVClient.Configuration configuration = AVClient.CurrentConfiguration; - // var apiVersion = "1.1"; - // if (relativeUri.StartsWith("push") || relativeUri.StartsWith("installations")) - // { - // Uri = new Uri(string.Format(urlTemplate, state.PushServer, apiVersion, relativeUri)); - // if (configuration.PushServer != null) - // { - // Uri = new Uri(string.Format("{0}{1}/{2}", configuration.PushServer, apiVersion, relativeUri)); - // } - // } - // else if (relativeUri.StartsWith("stats") || relativeUri.StartsWith("always_collect") || relativeUri.StartsWith("statistics")) - // { - // Uri = new Uri(string.Format(urlTemplate, state.StatsServer, apiVersion, relativeUri)); - // if (configuration.StatsServer != null) - // { - // Uri = new Uri(string.Format("{0}{1}/{2}", configuration.StatsServer, apiVersion, relativeUri)); - // } - // } - // else if (relativeUri.StartsWith("functions") || relativeUri.StartsWith("call")) - // { - // Uri = new Uri(string.Format(urlTemplate, state.EngineServer, apiVersion, relativeUri)); - - // if (configuration.EngineServer != null) - // { - // Uri = new Uri(string.Format("{0}{1}/{2}", configuration.EngineServer, apiVersion, relativeUri)); - // } - // } - // else - // { - // Uri = new Uri(string.Format(urlTemplate, state.ApiServer, apiVersion, relativeUri)); - - // if (configuration.ApiServer != null) - // { - // Uri = new Uri(string.Format("{0}{1}/{2}", configuration.ApiServer, apiVersion, relativeUri)); - // } - // } - // Method = method; - // Data = stream; - // Headers = new List>(headers ?? Enumerable.Empty>()); - - // string useProduction = AVClient.UseProduction ? "1" : "0"; - // Headers.Add(new KeyValuePair("X-LC-Prod", useProduction)); - - // if (!string.IsNullOrEmpty(sessionToken)) - // { - // Headers.Add(new KeyValuePair("X-LC-Session", sessionToken)); - // } - // if (!string.IsNullOrEmpty(contentType)) - // { - // Headers.Add(new KeyValuePair("Content-Type", contentType)); - // } - //} - - public AVCommand(AVCommand other) - { - this.Uri = other.Uri; - this.Method = other.Method; - this.Headers = new List>(other.Headers); - this.Body = other.Data; - } } } diff --git a/Storage/Storage/Internal/Command/AVCommandRunner.cs b/Storage/Storage/Internal/Command/AVCommandRunner.cs index ab2dbef..bbbd835 100644 --- a/Storage/Storage/Internal/Command/AVCommandRunner.cs +++ b/Storage/Storage/Internal/Command/AVCommandRunner.cs @@ -1,19 +1,22 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; -using LeanCloud.Storage.Internal; +using System.Text; +using Newtonsoft.Json; namespace LeanCloud.Storage.Internal { /// /// Command Runner. /// - public class AVCommandRunner : IAVCommandRunner - { - private readonly IHttpClient httpClient; + public class AVCommandRunner : IAVCommandRunner { + public const string APPLICATION_JSON = "application/json"; + + private readonly System.Net.Http.HttpClient httpClient; private readonly IInstallationIdController installationIdController; /// @@ -23,7 +26,7 @@ namespace LeanCloud.Storage.Internal /// public AVCommandRunner(IHttpClient httpClient, IInstallationIdController installationIdController) { - this.httpClient = httpClient; + this.httpClient = new System.Net.Http.HttpClient(); this.installationIdController = installationIdController; } @@ -35,133 +38,113 @@ namespace LeanCloud.Storage.Internal /// /// /// - public Task>> RunCommandAsync(HttpRequest command, + public async Task>> RunCommandAsync(AVCommand command, IProgress uploadProgress = null, IProgress downloadProgress = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - return PrepareCommand(command).ContinueWith(commandTask => - { - var requestLog = commandTask.Result.ToLog(); - AVClient.PrintLog("http=>" + requestLog); + CancellationToken cancellationToken = default(CancellationToken)) { + + var request = new HttpRequestMessage { + RequestUri = command.Uri, + Method = command.Method, + Content = new StringContent(Json.Encode(command.Content)) + }; - return httpClient.ExecuteAsync(commandTask.Result, uploadProgress, downloadProgress, cancellationToken).OnSuccess(t => - { - cancellationToken.ThrowIfCancellationRequested(); + var headers = await GetHeadersAsync(); + foreach (var header in headers) { + if (!string.IsNullOrEmpty(header.Value)) { + request.Headers.Add(header.Key, header.Value); + } + } + request.Content.Headers.ContentType = new MediaTypeHeaderValue(APPLICATION_JSON); - var response = t.Result; - var contentString = response.Item2; - int responseCode = (int)response.Item1; + PrintRequest(command, headers); + var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + request.Dispose(); - var responseLog = responseCode + ";" + contentString; - AVClient.PrintLog("http<=" + responseLog); + var resultString = await response.Content.ReadAsStringAsync(); + response.Dispose(); + PrintResponse(response, resultString); - if (responseCode >= 500) - { - // Server error, return InternalServerError. - throw new AVException(AVException.ErrorCode.InternalServerError, response.Item2); + var ret = new Tuple(response.StatusCode, resultString); + + var responseCode = ret.Item1; + var contentString = ret.Item2; + + if (responseCode >= HttpStatusCode.InternalServerError) { + // Server error, return InternalServerError. + throw new AVException(AVException.ErrorCode.InternalServerError, contentString); + } + + if (contentString != null) { + IDictionary contentJson = null; + try { + if (contentString.StartsWith("[", StringComparison.Ordinal)) { + var arrayJson = Json.Parse(contentString); + contentJson = new Dictionary { { "results", arrayJson } }; + } else { + contentJson = Json.Parse(contentString) as IDictionary; } - else if (contentString != null) - { - IDictionary contentJson = null; - try - { - if (contentString.StartsWith("[")) - { - var arrayJson = Json.Parse(contentString); - contentJson = new Dictionary { { "results", arrayJson } }; - } - else - { - contentJson = Json.Parse(contentString) as IDictionary; - } - } - catch (Exception e) - { - throw new AVException(AVException.ErrorCode.OtherCause, - "Invalid response from server", e); - } - if (responseCode < 200 || responseCode > 299) - { - AVClient.PrintLog("error response code:" + responseCode); - int code = (int)(contentJson.ContainsKey("code") ? (int)contentJson["code"] : (int)AVException.ErrorCode.OtherCause); - string error = contentJson.ContainsKey("error") ? - contentJson["error"] as string : contentString; - AVException.ErrorCode ec = (AVException.ErrorCode)code; - throw new AVException(ec, error); - } - return new Tuple>(response.Item1, - contentJson); - } - return new Tuple>(response.Item1, null); - }); - }).Unwrap(); + } catch (Exception e) { + throw new AVException(AVException.ErrorCode.OtherCause, + "Invalid response from server", e); + } + if (responseCode < HttpStatusCode.OK || responseCode > HttpStatusCode.PartialContent) { + AVClient.PrintLog("error response code:" + responseCode); + int code = (int)(contentJson.ContainsKey("code") ? (int)contentJson["code"] : (int)AVException.ErrorCode.OtherCause); + string error = contentJson.ContainsKey("error") ? + contentJson["error"] as string : contentString; + AVException.ErrorCode ec = (AVException.ErrorCode)code; + throw new AVException(ec, error); + } + return new Tuple>(responseCode, contentJson); + } + + return new Tuple>(responseCode, null); } private const string revocableSessionTokenTrueValue = "1"; - private Task PrepareCommand(HttpRequest command) - { - HttpRequest newCommand = command; - - Task installationIdTask = installationIdController.GetAsync().ContinueWith(t => - { - newCommand.Headers.Add(new KeyValuePair("X-LC-Installation-Id", t.Result.ToString())); - return newCommand; - }); - - AVClient.Configuration configuration = AVClient.CurrentConfiguration; - newCommand.Headers.Add(new KeyValuePair("X-LC-Id", configuration.ApplicationId)); + async Task> GetHeadersAsync() { + var headers = new Dictionary(); + var installationId = await installationIdController.GetAsync(); + headers.Add("X-LC-Installation-Id", installationId.ToString()); + var conf = AVClient.CurrentConfiguration; + headers.Add("X-LC-Id", conf.ApplicationId); long timestamp = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds; - if (!string.IsNullOrEmpty(configuration.MasterKey) && AVClient.UseMasterKey) - { - string sign = MD5.GetMd5String(timestamp + configuration.MasterKey); - newCommand.Headers.Add(new KeyValuePair("X-LC-Sign", string.Format("{0},{1},master", sign, timestamp))); - } - else - { - string sign = MD5.GetMd5String(timestamp + configuration.ApplicationKey); - newCommand.Headers.Add(new KeyValuePair("X-LC-Sign", string.Format("{0},{1}", sign, timestamp))); + if (!string.IsNullOrEmpty(conf.MasterKey) && AVClient.UseMasterKey) { + string sign = MD5.GetMd5String(timestamp + conf.MasterKey); + headers.Add("X-LC-Sign", $"{sign},{timestamp},master"); + } else { + string sign = MD5.GetMd5String(timestamp + conf.ApplicationKey); + headers.Add("X-LC-Sign", $"{sign},{timestamp}"); } + // TODO 重新设计版本号 + headers.Add("X-LC-Client-Version", AVClient.VersionString); + headers.Add("X-LC-App-Build-Version", conf.VersionInfo.BuildVersion); + headers.Add("X-LC-App-Display-Version", conf.VersionInfo.DisplayVersion); + headers.Add("X-LC-OS-Version", conf.VersionInfo.OSVersion); + headers.Add("X-LeanCloud-Revocable-Session", revocableSessionTokenTrueValue); + return headers; + } - newCommand.Headers.Add(new KeyValuePair("X-LC-Client-Version", AVClient.VersionString)); + static void PrintRequest(AVCommand request, Dictionary headers) { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("=== HTTP Request Start ==="); + sb.AppendLine($"URL: {request.Uri}"); + sb.AppendLine($"Method: {request.Method}"); + sb.AppendLine($"Headers: {JsonConvert.SerializeObject(headers)}"); + sb.AppendLine($"Content: {JsonConvert.SerializeObject(request.Content)}"); + sb.AppendLine("=== HTTP Request End ==="); + AVClient.PrintLog(sb.ToString()); + } - if (!string.IsNullOrEmpty(configuration.VersionInfo.BuildVersion)) - { - newCommand.Headers.Add(new KeyValuePair("X-LC-App-Build-Version", configuration.VersionInfo.BuildVersion)); - } - if (!string.IsNullOrEmpty(configuration.VersionInfo.DisplayVersion)) - { - newCommand.Headers.Add(new KeyValuePair("X-LC-App-Display-Version", configuration.VersionInfo.DisplayVersion)); - } - if (!string.IsNullOrEmpty(configuration.VersionInfo.OSVersion)) - { - newCommand.Headers.Add(new KeyValuePair("X-LC-OS-Version", configuration.VersionInfo.OSVersion)); - } - - if (AVUser.IsRevocableSessionEnabled) - { - newCommand.Headers.Add(new KeyValuePair("X-LeanCloud-Revocable-Session", revocableSessionTokenTrueValue)); - } - - if (configuration.AdditionalHTTPHeaders != null) - { - var headersDictionary = newCommand.Headers.ToDictionary(kv => kv.Key, kv => kv.Value); - foreach (var header in configuration.AdditionalHTTPHeaders) - { - if (headersDictionary.ContainsKey(header.Key)) - { - headersDictionary[header.Key] = header.Value; - } - else - { - newCommand.Headers.Add(header); - } - } - newCommand.Headers = headersDictionary.ToList(); - } - - return installationIdTask; + 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()); } } } diff --git a/Storage/Storage/Internal/Command/EngineCommand.cs b/Storage/Storage/Internal/Command/EngineCommand.cs new file mode 100644 index 0000000..506ba27 --- /dev/null +++ b/Storage/Storage/Internal/Command/EngineCommand.cs @@ -0,0 +1,7 @@ +using System; + +namespace LeanCloud.Storage.Internal { + public class EngineCommand : AVCommand { + public override string Server => AVClient.CurrentConfiguration.EngineServer; + } +} diff --git a/Storage/Storage/Internal/Command/IAVCommandRunner.cs b/Storage/Storage/Internal/Command/IAVCommandRunner.cs index 0776da8..081623b 100644 --- a/Storage/Storage/Internal/Command/IAVCommandRunner.cs +++ b/Storage/Storage/Internal/Command/IAVCommandRunner.cs @@ -16,7 +16,7 @@ namespace LeanCloud.Storage.Internal /// Download progress callback. /// The cancellation token for the request. /// - Task>> RunCommandAsync(HttpRequest command, + Task>> RunCommandAsync(AVCommand command, IProgress uploadProgress = null, IProgress downloadProgress = null, CancellationToken cancellationToken = default(CancellationToken)); diff --git a/Storage/Storage/Internal/Command/RTMCommand.cs b/Storage/Storage/Internal/Command/RTMCommand.cs new file mode 100644 index 0000000..a73ffc8 --- /dev/null +++ b/Storage/Storage/Internal/Command/RTMCommand.cs @@ -0,0 +1,7 @@ +using LeanCloud; + +namespace LeanCloud.Storage.Internal { + public class RTMCommand : AVCommand { + public override string Server => AVClient.CurrentConfiguration.RTMServer; + } +} diff --git a/Storage/Storage/Internal/Config/Controller/AVConfigController.cs b/Storage/Storage/Internal/Config/Controller/AVConfigController.cs index 15d34ff..a674a98 100644 --- a/Storage/Storage/Internal/Config/Controller/AVConfigController.cs +++ b/Storage/Storage/Internal/Config/Controller/AVConfigController.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; using System.Threading; -using LeanCloud.Storage.Internal; +using System.Net.Http; namespace LeanCloud.Storage.Internal { /// @@ -22,10 +22,10 @@ namespace LeanCloud.Storage.Internal { public IAVCurrentConfigController CurrentConfigController { get; internal set; } public Task FetchConfigAsync(String sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand("config", - method: "GET", - sessionToken: sessionToken, - data: null); + var command = new AVCommand { + Path = "config", + Method = HttpMethod.Post, + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(task => { cancellationToken.ThrowIfCancellationRequested(); diff --git a/Storage/Storage/Internal/File/Controller/AVFileController.cs b/Storage/Storage/Internal/File/Controller/AVFileController.cs index 1923407..5b5e574 100644 --- a/Storage/Storage/Internal/File/Controller/AVFileController.cs +++ b/Storage/Storage/Internal/File/Controller/AVFileController.cs @@ -15,7 +15,7 @@ namespace LeanCloud.Storage.Internal /// public class AVFileController : IAVFileController { - private readonly IAVCommandRunner commandRunner; + protected readonly IAVCommandRunner commandRunner; /// /// Initializes a new instance of the class. /// @@ -66,14 +66,13 @@ namespace LeanCloud.Storage.Internal } public Task DeleteAsync(FileState state, string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand("files/" + state.ObjectId, - method: "DELETE", - sessionToken: sessionToken, - data: null); - + var command = new AVCommand { + Path = $"files/{state.ObjectId}", + Method = HttpMethod.Delete + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken); } - internal static Task>> GetFileToken(FileState fileState, CancellationToken cancellationToken) + internal Task>> GetFileToken(FileState fileState, CancellationToken cancellationToken) { Task>> rtn; string currentSessionToken = AVUser.CurrentSessionToken; @@ -85,17 +84,19 @@ namespace LeanCloud.Storage.Internal parameters.Add("mime_type", AVFile.GetMIMEType(str)); parameters.Add("metaData", fileState.MetaData); - rtn = AVClient.RequestAsync("POST", new Uri("fileTokens", UriKind.Relative), currentSessionToken, parameters, cancellationToken); - - return rtn; + var command = new AVCommand { + Path = "fileTokens", + Method = HttpMethod.Post, + Content = parameters + }; + return commandRunner.RunCommandAsync(command); } public Task GetAsync(string objectId, string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand("files/" + objectId, - method: "GET", - sessionToken: sessionToken, - data: null); - + var command = new AVCommand { + Path = $"files/{objectId}", + Method = HttpMethod.Get + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(_ => { var result = _.Result; diff --git a/Storage/Storage/Internal/File/Controller/QiniuFileController.cs b/Storage/Storage/Internal/File/Controller/QiniuFileController.cs index 10ead4c..028ea44 100644 --- a/Storage/Storage/Internal/File/Controller/QiniuFileController.cs +++ b/Storage/Storage/Internal/File/Controller/QiniuFileController.cs @@ -161,9 +161,12 @@ namespace LeanCloud.Storage.Internal parameters.Add("metaData", state.MetaData); - rtn = AVClient.RequestAsync("POST", new Uri("qiniu", UriKind.Relative), currentSessionToken, parameters, cancellationToken); - - return rtn; + var command = new AVCommand { + Path = "qiniu", + Method = HttpMethod.Post, + Content = parameters + }; + return commandRunner.RunCommandAsync(command); } IList> GetQiniuRequestHeaders(FileState state) { diff --git a/Storage/Storage/Internal/Object/Controller/AVObjectController.cs b/Storage/Storage/Internal/Object/Controller/AVObjectController.cs index 21da0c6..edf5993 100644 --- a/Storage/Storage/Internal/Object/Controller/AVObjectController.cs +++ b/Storage/Storage/Internal/Object/Controller/AVObjectController.cs @@ -4,32 +4,24 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using LeanCloud.Utilities; -using LeanCloud.Storage.Internal; +using System.Net.Http; -namespace LeanCloud.Storage.Internal -{ - public class AVObjectController : IAVObjectController - { +namespace LeanCloud.Storage.Internal { + public class AVObjectController : IAVObjectController { private readonly IAVCommandRunner commandRunner; - public AVObjectController(IAVCommandRunner commandRunner) - { + public AVObjectController(IAVCommandRunner commandRunner) { this.commandRunner = commandRunner; } public Task FetchAsync(IObjectState state, string sessionToken, - CancellationToken cancellationToken) - { - var command = new AVCommand(string.Format("classes/{0}/{1}", - Uri.EscapeDataString(state.ClassName), - Uri.EscapeDataString(state.ObjectId)), - method: "GET", - sessionToken: sessionToken, - data: null); - - return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => - { + CancellationToken cancellationToken) { + var command = new AVCommand { + Path = $"classes/{Uri.EscapeDataString(state.ClassName)}/{Uri.EscapeDataString(state.ObjectId)}", + Method = HttpMethod.Get + }; + return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); }); } @@ -37,18 +29,12 @@ namespace LeanCloud.Storage.Internal public Task FetchAsync(IObjectState state, IDictionary queryString, string sessionToken, - CancellationToken cancellationToken) - { - var command = new AVCommand(string.Format("classes/{0}/{1}?{2}", - Uri.EscapeDataString(state.ClassName), - Uri.EscapeDataString(state.ObjectId), - AVClient.BuildQueryString(queryString)), - method: "GET", - sessionToken: sessionToken, - data: null); - - return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => - { + CancellationToken cancellationToken) { + var command = new AVCommand { + Path = $"classes/{Uri.EscapeDataString(state.ClassName)}/{Uri.EscapeDataString(state.ObjectId)}?{AVClient.BuildQueryString(queryString)}", + Method = HttpMethod.Get + }; + return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); }); } @@ -56,22 +42,16 @@ namespace LeanCloud.Storage.Internal public Task SaveAsync(IObjectState state, IDictionary operations, string sessionToken, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { var objectJSON = AVObject.ToJSONObjectForSaving(operations); - - var command = new AVCommand((state.ObjectId == null ? - string.Format("classes/{0}", Uri.EscapeDataString(state.ClassName)) : - string.Format("classes/{0}/{1}", Uri.EscapeDataString(state.ClassName), state.ObjectId)), - method: (state.ObjectId == null ? "POST" : "PUT"), - sessionToken: sessionToken, - data: objectJSON); - - return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => - { + var command = new AVCommand { + Path = state.ObjectId == null ? $"classes/{Uri.EscapeDataString(state.ClassName)}" : $"classes/{Uri.EscapeDataString(state.ClassName)}/{state.ObjectId}", + Method = state.ObjectId == null ? HttpMethod.Post : HttpMethod.Put, + Content = objectJSON + }; + return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); - serverState = serverState.MutatedClone(mutableClone => - { + serverState = serverState.MutatedClone(mutableClone => { mutableClone.IsNew = t.Result.Item1 == System.Net.HttpStatusCode.Created; }); return serverState; @@ -81,24 +61,20 @@ namespace LeanCloud.Storage.Internal public IList> SaveAllAsync(IList states, IList> operationsList, string sessionToken, - CancellationToken cancellationToken) - { - + CancellationToken cancellationToken) { + var requests = states - .Zip(operationsList, (item, ops) => new AVCommand( - item.ObjectId == null - ? string.Format("classes/{0}", Uri.EscapeDataString(item.ClassName)) - : string.Format("classes/{0}/{1}", Uri.EscapeDataString(item.ClassName), Uri.EscapeDataString(item.ObjectId)), - method: item.ObjectId == null ? "POST" : "PUT", - data: AVObject.ToJSONObjectForSaving(ops))) + .Zip(operationsList, (item, ops) => new AVCommand { + Path = item.ObjectId == null ? $"classes/{Uri.EscapeDataString(item.ClassName)}" : $"classes/{Uri.EscapeDataString(item.ClassName)}/{Uri.EscapeDataString(item.ObjectId)}", + Method = item.ObjectId == null ? HttpMethod.Post : HttpMethod.Put, + Content = AVObject.ToJSONObjectForSaving(ops) + }) .ToList(); var batchTasks = ExecuteBatchRequests(requests, sessionToken, cancellationToken); var stateTasks = new List>(); - foreach (var task in batchTasks) - { - stateTasks.Add(task.OnSuccess(t => - { + foreach (var task in batchTasks) { + stateTasks.Add(task.OnSuccess(t => { return AVObjectCoder.Instance.Decode(t.Result, AVDecoder.Instance); })); } @@ -108,27 +84,23 @@ namespace LeanCloud.Storage.Internal public Task DeleteAsync(IObjectState state, string sessionToken, - CancellationToken cancellationToken) - { - var command = new AVCommand(string.Format("classes/{0}/{1}", - state.ClassName, state.ObjectId), - method: "DELETE", - sessionToken: sessionToken, - data: null); - + CancellationToken cancellationToken) { + var command = new AVCommand { + Path = $"classes/{state.ClassName}/{state.ObjectId}", + Method = HttpMethod.Delete + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken); } public IList DeleteAllAsync(IList states, string sessionToken, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { var requests = states .Where(item => item.ObjectId != null) - .Select(item => new AVCommand( - string.Format("classes/{0}/{1}", Uri.EscapeDataString(item.ClassName), Uri.EscapeDataString(item.ObjectId)), - method: "DELETE", - data: null)) + .Select(item => new AVCommand { + Path = $"classes/{Uri.EscapeDataString(item.ClassName)}/{Uri.EscapeDataString(item.ObjectId)}", + Method = HttpMethod.Delete + }) .ToList(); return ExecuteBatchRequests(requests, sessionToken, cancellationToken).Cast().ToList(); } @@ -137,14 +109,12 @@ namespace LeanCloud.Storage.Internal private const int MaximumBatchSize = 50; internal IList>> ExecuteBatchRequests(IList requests, string sessionToken, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { var tasks = new List>>(); int batchSize = requests.Count; IEnumerable remaining = requests; - while (batchSize > MaximumBatchSize) - { + while (batchSize > MaximumBatchSize) { var process = remaining.Take(MaximumBatchSize).ToList(); remaining = remaining.Skip(MaximumBatchSize); @@ -159,48 +129,40 @@ namespace LeanCloud.Storage.Internal private IList>> ExecuteBatchRequest(IList requests, string sessionToken, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { var tasks = new List>>(); int batchSize = requests.Count; var tcss = new List>>(); - for (int i = 0; i < batchSize; ++i) - { + for (int i = 0; i < batchSize; ++i) { var tcs = new TaskCompletionSource>(); tcss.Add(tcs); tasks.Add(tcs.Task); } - var encodedRequests = requests.Select(r => - { + var encodedRequests = requests.Select(r => { var results = new Dictionary { { "method", r.Method }, - { "path", r.Uri.AbsolutePath }, + { "path", r.Path }, }; - if (r.Body != null) - { - results["body"] = r.Body; + if (r.Content != null) { + results["body"] = r.Content; } return results; }).Cast().ToList(); - var command = new AVCommand("batch", - method: "POST", - sessionToken: sessionToken, - data: new Dictionary { { "requests", encodedRequests } }); - - commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => - { - if (t.IsFaulted || t.IsCanceled) - { - foreach (var tcs in tcss) - { - if (t.IsFaulted) - { + var command = new AVCommand { + Path = "batch", + Method = HttpMethod.Post, + Content = new Dictionary { + { "requests", encodedRequests } + } + }; + commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => { + if (t.IsFaulted || t.IsCanceled) { + foreach (var tcs in tcss) { + if (t.IsFaulted) { tcs.TrySetException(t.Exception); - } - else if (t.IsCanceled) - { + } else if (t.IsCanceled) { tcs.TrySetCanceled(); } } @@ -209,33 +171,25 @@ namespace LeanCloud.Storage.Internal var resultsArray = Conversion.As>(t.Result.Item2["results"]); int resultLength = resultsArray.Count; - if (resultLength != batchSize) - { - foreach (var tcs in tcss) - { + 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) - { + for (int i = 0; i < batchSize; ++i) { var result = resultsArray[i] as Dictionary; var tcs = tcss[i]; - if (result.ContainsKey("success")) - { + if (result.ContainsKey("success")) { tcs.TrySetResult(result["success"] as IDictionary); - } - else if (result.ContainsKey("error")) - { + } else if (result.ContainsKey("error")) { var error = result["error"] as IDictionary; long errorCode = long.Parse(error["code"].ToString()); tcs.TrySetException(new AVException((AVException.ErrorCode)errorCode, error["error"] as string)); - } - else - { + } else { tcs.TrySetException(new InvalidOperationException( "Invalid batch command response.")); } diff --git a/Storage/Storage/Internal/Query/Controller/AVQueryController.cs b/Storage/Storage/Internal/Query/Controller/AVQueryController.cs index 42c1869..507e899 100644 --- a/Storage/Storage/Internal/Query/Controller/AVQueryController.cs +++ b/Storage/Storage/Internal/Query/Controller/AVQueryController.cs @@ -1,10 +1,9 @@ using System; using System.Linq; using System.Collections.Generic; -using System.Collections.ObjectModel; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using LeanCloud.Storage.Internal; namespace LeanCloud.Storage.Internal { @@ -75,14 +74,10 @@ namespace LeanCloud.Storage.Internal string sessionToken, CancellationToken cancellationToken) { - - var command = new AVCommand(string.Format("{0}?{1}", - relativeUri, - AVClient.BuildQueryString(parameters)), - method: "GET", - sessionToken: sessionToken, - data: null); - + var command = new AVCommand { + Path = $"{relativeUri}?{AVClient.BuildQueryString(parameters)}", + Method = HttpMethod.Get + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { return t.Result.Item2; diff --git a/Storage/Storage/Internal/Session/Controller/AVSessionController.cs b/Storage/Storage/Internal/Session/Controller/AVSessionController.cs index fd40711..6e82904 100644 --- a/Storage/Storage/Internal/Session/Controller/AVSessionController.cs +++ b/Storage/Storage/Internal/Session/Controller/AVSessionController.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using LeanCloud.Storage.Internal; +using System.Net.Http; namespace LeanCloud.Storage.Internal { public class AVSessionController : IAVSessionController { @@ -13,31 +13,28 @@ namespace LeanCloud.Storage.Internal { } public Task GetSessionAsync(string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand("sessions/me", - method: "GET", - sessionToken: sessionToken, - data: null); - + var command = new AVCommand { + Path = "sessions/me", + Method = HttpMethod.Get + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); }); } public Task RevokeAsync(string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand("logout", - method: "POST", - sessionToken: sessionToken, - data: new Dictionary()); - + var command = new AVCommand { + Path = "logout", + Method = HttpMethod.Post + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken); } public Task UpgradeToRevocableSessionAsync(string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand("upgradeToRevocableSession", - method: "POST", - sessionToken: sessionToken, - data: new Dictionary()); - + var command = new AVCommand { + Path = "upgradeToRevocableSession", + Method = HttpMethod.Post, + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); }); diff --git a/Storage/Storage/Internal/User/Controller/AVUserController.cs b/Storage/Storage/Internal/User/Controller/AVUserController.cs index c74f602..5fbc602 100644 --- a/Storage/Storage/Internal/User/Controller/AVUserController.cs +++ b/Storage/Storage/Internal/User/Controller/AVUserController.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using LeanCloud.Storage.Internal; +using System.Net.Http; namespace LeanCloud.Storage.Internal { @@ -20,11 +20,11 @@ namespace LeanCloud.Storage.Internal CancellationToken cancellationToken) { var objectJSON = AVObject.ToJSONObjectForSaving(operations); - - var command = new AVCommand("classes/_User", - method: "POST", - data: objectJSON); - + var command = new AVCommand { + Path = "classes/_User", + Method = HttpMethod.Post, + Content = objectJSON + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); @@ -49,11 +49,11 @@ namespace LeanCloud.Storage.Internal if (email != null) { data.Add("email", email); } - - var command = new AVCommand("login", - method: "POST", - data: data); - + var command = new AVCommand { + Path = "login", + Method = HttpMethod.Post, + Content = data + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); @@ -73,12 +73,13 @@ namespace LeanCloud.Storage.Internal var authData = new Dictionary(); authData[authType] = data; var path = failOnNotExist ? "users?failOnNotExist=true" : "users"; - var command = new AVCommand(path, - method: "POST", - data: new Dictionary { + var command = new AVCommand { + Path = path, + Method = HttpMethod.Post, + Content = new Dictionary { { "authData", authData} - }); - + } + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); @@ -92,11 +93,10 @@ namespace LeanCloud.Storage.Internal public Task GetUserAsync(string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand("users/me", - method: "GET", - sessionToken: sessionToken, - data: null); - + var command = new AVCommand { + Path = "users/me", + Method = HttpMethod.Get + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); @@ -105,22 +105,24 @@ namespace LeanCloud.Storage.Internal public Task RequestPasswordResetAsync(string email, CancellationToken cancellationToken) { - var command = new AVCommand("requestPasswordReset", - method: "POST", - data: new Dictionary { + var command = new AVCommand { + Path = "requestPasswordReset", + Method = HttpMethod.Post, + Content = new Dictionary { { "email", email} - }); - + } + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken); } public Task LogInWithParametersAsync(string relativeUrl, IDictionary data, CancellationToken cancellationToken) { - var command = new AVCommand(string.Format("{0}", relativeUrl), - method: "POST", - data: data); - + var command = new AVCommand { + Path = relativeUrl, + Method = HttpMethod.Post, + Content = data + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); @@ -134,23 +136,24 @@ namespace LeanCloud.Storage.Internal public Task UpdatePasswordAsync(string userId, string sessionToken, string oldPassword, string newPassword, CancellationToken cancellationToken) { - var command = new AVCommand(String.Format("users/{0}/updatePassword", userId), - method: "PUT", - sessionToken: sessionToken, - data: new Dictionary { - {"old_password", oldPassword}, - {"new_password", newPassword}, - }); + var command = new AVCommand { + Path = $"users/{userId}/updatePassword", + Method = HttpMethod.Put, + Content = new Dictionary { + { "old_password", oldPassword }, + { "new_password", newPassword }, + } + }; return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken); } public Task RefreshSessionTokenAsync(string userId, string sessionToken, CancellationToken cancellationToken) { - var command = new AVCommand(String.Format("users/{0}/refreshSessionToken", userId), - method: "PUT", - sessionToken: sessionToken, - data: null); + var command = new AVCommand { + Path = $"users/{userId}/refreshSessionToken", + Method = HttpMethod.Put + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance); diff --git a/Storage/Storage/Public/AVClient.cs b/Storage/Storage/Public/AVClient.cs index 5cfaa40..eb145bf 100644 --- a/Storage/Storage/Public/AVClient.cs +++ b/Storage/Storage/Public/AVClient.cs @@ -190,6 +190,12 @@ namespace LeanCloud } } + internal static string APIVersion { + get { + return "1.1"; + } + } + private static readonly string versionString; /// /// 当前 SDK 版本号 @@ -431,16 +437,6 @@ namespace LeanCloud cancellationToken.ThrowIfCancellationRequested(); return new Tuple>(code, strs); } - internal static Task>> RequestAsync(string method, Uri relativeUri, string sessionToken, IDictionary data, CancellationToken cancellationToken) - { - - var command = new AVCommand(relativeUri.ToString(), - method: method, - sessionToken: sessionToken, - data: data); - - return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken); - } internal static Task>> RunCommandAsync(AVCommand command) { @@ -452,42 +448,5 @@ namespace LeanCloud var codeValue = (int)responseStatus; return (codeValue > 199) && (codeValue < 204); } - - public static string ToLog(this HttpRequest request) - { - StringBuilder sb = new StringBuilder(); - var start = "===HTTP Request Start==="; - sb.AppendLine(start); - var urlLog = "Url: " + request.Uri; - sb.AppendLine(urlLog); - - var methodLog = "Method: " + request.Method; - sb.AppendLine(methodLog); - - try - { - var headers = request.Headers.ToDictionary(x => x.Key, x => x.Value as object); - var headersLog = "Headers: " + Json.Encode(headers); - sb.AppendLine(headersLog); - } - catch (Exception) - { - - } - - try - { - var bodyLog = "Body:" + Json.Encode(request.Data); - sb.AppendLine(bodyLog); - } - catch (Exception) - { - - } - - var end = "===HTTP Request End==="; - sb.AppendLine(end); - return sb.ToString(); - } } } diff --git a/Storage/Storage/Public/AVCloud.cs b/Storage/Storage/Public/AVCloud.cs index 76b3a13..51a7b57 100644 --- a/Storage/Storage/Public/AVCloud.cs +++ b/Storage/Storage/Public/AVCloud.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using LeanCloud.Storage.Internal; +using System.Net.Http; namespace LeanCloud { /// @@ -77,37 +78,6 @@ namespace LeanCloud { }).Unwrap(); } - /// - /// 获取 LeanCloud 服务器的时间 - /// - /// 如果获取失败,将返回 DateTime.MinValue - /// - /// - /// 服务器的时间 - public static Task GetServerDateTimeAsync() - { - var command = new AVCommand(relativeUri: "date", - method: "GET", - sessionToken: null, - data: null); - return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => - { - DateTime rtn = DateTime.MinValue; - if (AVClient.IsSuccessStatusCode(t.Result.Item1)) - { - var date = AVDecoder.Instance.Decode(t.Result.Item2); - if (date != null) - { - if (date is DateTime) - { - rtn = (DateTime)date; - } - } - } - return rtn; - }); - } - /// /// 请求短信认证。 /// @@ -154,10 +124,11 @@ namespace LeanCloud { { strs.Add("TTL", ttl); } - var command = new AVCommand("requestSmsCode", - method: "POST", - sessionToken: null, - data: strs); + var command = new EngineCommand { + Path = "requestSmsCode", + Method = HttpMethod.Post, + Content = strs + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -227,10 +198,11 @@ namespace LeanCloud { { strs.Add(key, env[key]); } - var command = new AVCommand("requestSmsCode", - method: "POST", - sessionToken: null, - data: strs); + var command = new EngineCommand { + Path = "requestSmsCode", + Method = HttpMethod.Post, + Content = strs + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -248,17 +220,18 @@ namespace LeanCloud { { throw new AVException(AVException.ErrorCode.MobilePhoneInvalid, "Moblie Phone number is invalid.", null); } - Dictionary strs = new Dictionary() + Dictionary body = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, { "smsType", "voice" }, - { "IDD","+86" } + { "IDD", "+86" } }; - var command = new AVCommand("requestSmsCode", - method: "POST", - sessionToken: null, - data: strs); + var command = new EngineCommand { + Path = "requestSmsCode", + Method = HttpMethod.Post, + Content = body + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { @@ -286,11 +259,9 @@ namespace LeanCloud { /// Cancellation token. public static Task VerifySmsCodeAsync(string code, string mobilePhoneNumber, CancellationToken cancellationToken) { - var command = new AVCommand("verifySmsCode/" + code.Trim() + "?mobilePhoneNumber=" + mobilePhoneNumber.Trim(), - method: "POST", - sessionToken: null, - data: null); - + var command = new AVCommand { + Path = $"verifySmsCode/{code.Trim()}?mobilePhoneNumber={mobilePhoneNumber.Trim()}", + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -334,7 +305,10 @@ namespace LeanCloud { public static Task RequestCaptchaAsync(int width = 85, int height = 30, CancellationToken cancellationToken = default(CancellationToken)) { var path = String.Format("requestCaptcha?width={0}&height={1}", width, height); - var command = new AVCommand(path, method: "GET", sessionToken: null, data: null); + var command = new AVCommand { + Path = $"requestCaptcha?width={width}&height={height}", + Method = HttpMethod.Get + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary; @@ -355,12 +329,15 @@ namespace LeanCloud { /// public static Task VerifyCaptchaAsync(string code, string token, CancellationToken cancellationToken = default(CancellationToken)) { - var data = new Dictionary - { + var data = new Dictionary { { "captcha_token", token }, { "captcha_code", code }, }; - var command = new AVCommand("verifyCaptcha", method: "POST", sessionToken: null, data: data); + var command = new AVCommand { + Path = "verifyCaptcha", + Method = HttpMethod.Post, + Content = data + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => { if (!t.Result.Item2.ContainsKey("validate_token")) @@ -376,11 +353,10 @@ namespace LeanCloud { /// public static Task> GetCustomParametersAsync(CancellationToken cancellationToken = default(CancellationToken)) { - var command = new AVCommand(string.Format("statistics/apps/{0}/sendPolicy", AVClient.CurrentConfiguration.ApplicationId), - method: "GET", - sessionToken: null, - data: null); - + var command = new AVCommand { + Path = $"statistics/apps/{AVClient.CurrentConfiguration.ApplicationId}/sendPolicy", + Method = HttpMethod.Get + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var settings = t.Result.Item2; @@ -407,14 +383,13 @@ namespace LeanCloud { public static Task RequestRealtimeSignatureAsync(AVUser user, CancellationToken cancellationToken = default(CancellationToken)) { - var command = new AVCommand(string.Format("rtm/sign"), - method: "POST", - sessionToken: null, - data: new Dictionary - { - { "session_token", user.SessionToken }, - } - ); + var command = new AVCommand { + Path = "rtm/sign", + Method = HttpMethod.Post, + Content = new Dictionary { + { "session_token", user.SessionToken } + } + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => { var body = t.Result.Item2; @@ -517,12 +492,11 @@ namespace LeanCloud { { var user = t.Result; var encodedParameters = Encode(parameters); - var command = new AVCommand( - string.Format("call/{0}", Uri.EscapeUriString(this.FunctionName)), - method: "POST", - sessionToken: user != null ? user.SessionToken : null, - data: encodedParameters); - + var command = new EngineCommand { + Path = $"call/{Uri.EscapeUriString(FunctionName)}", + Method = HttpMethod.Post, + Content = encodedParameters + }; return AVClient.RunCommandAsync(command); }).Unwrap().OnSuccess(s => diff --git a/Storage/Storage/Public/AVFile.cs b/Storage/Storage/Public/AVFile.cs index 6d05995..79f84fb 100644 --- a/Storage/Storage/Public/AVFile.cs +++ b/Storage/Storage/Public/AVFile.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.IO; -using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -355,14 +355,18 @@ namespace LeanCloud }; AVCommand cmd = null; - if (!string.IsNullOrEmpty(this.ObjectId)) - { - cmd = new AVCommand("files/" + this.ObjectId, - method: "PUT", sessionToken: AVUser.CurrentSessionToken, data: strs); - } - else - { - cmd = new AVCommand("files", method: "POST", sessionToken: AVUser.CurrentSessionToken, data: strs); + if (!string.IsNullOrEmpty(this.ObjectId)) { + cmd = new AVCommand { + Path = $"files/{ObjectId}", + Method = HttpMethod.Put, + Content = strs + }; + } else { + cmd = new AVCommand { + Path = "files", + Method = HttpMethod.Post, + Content = strs + }; } return AVPlugins.Instance.CommandRunner.RunCommandAsync(cmd).ContinueWith(t => diff --git a/Storage/Storage/Public/AVQuery.cs b/Storage/Storage/Public/AVQuery.cs index 5a0b341..5d6a85d 100644 --- a/Storage/Storage/Public/AVQuery.cs +++ b/Storage/Storage/Public/AVQuery.cs @@ -1,12 +1,11 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using LeanCloud.Storage.Internal; +using System.Net.Http; namespace LeanCloud { @@ -209,7 +208,7 @@ namespace LeanCloud }).Unwrap().OnSuccess(t => { IObjectState state = t.Result; - return state == null ? default(T) : AVObject.FromState(state, ClassName); + return state == null ? default : AVObject.FromState(state, ClassName); }); } @@ -310,11 +309,10 @@ namespace LeanCloud internal static Task> rebuildObjectFromCloudQueryResult(string queryString) { - var command = new AVCommand(queryString, - method: "GET", - sessionToken: AVUser.CurrentSessionToken, - data: null); - + var command = new AVCommand { + Path = queryString, + Method = HttpMethod.Get + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: CancellationToken.None).OnSuccess(t => { var items = t.Result.Item2["results"] as IList; diff --git a/Storage/Storage/Public/AVUser.cs b/Storage/Storage/Public/AVUser.cs index 62aee39..cecbc45 100644 --- a/Storage/Storage/Public/AVUser.cs +++ b/Storage/Storage/Public/AVUser.cs @@ -1,9 +1,7 @@ using LeanCloud.Storage.Internal; using System; using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -69,9 +67,10 @@ namespace LeanCloud return Task.FromResult(false); } } - var command = new AVCommand(String.Format("users/me?session_token={0}", CurrentSessionToken), - method: "GET", - data: null); + var command = new AVCommand { + Path = $"users/me?session_token={CurrentSessionToken}", + Method = HttpMethod.Get + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -297,10 +296,11 @@ namespace LeanCloud { data = this.EncodeForSaving(data); } - var command = new AVCommand(string.Format("users/{0}/friendship/{1}", this.ObjectId, userObjectId), - method: "POST", - sessionToken: CurrentSessionToken, - data: data); + var command = new AVCommand { + Path = $"users/{ObjectId}/friendship/{userObjectId}", + Method = HttpMethod.Post, + Content = data + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -314,10 +314,10 @@ namespace LeanCloud /// public Task UnfollowAsync(string userObjectId) { - var command = new AVCommand(string.Format("users/{0}/friendship/{1}", this.ObjectId, userObjectId), - method: "DELETE", - sessionToken: CurrentSessionToken, - data: null); + var command = new AVCommand { + Path = $"users/{ObjectId}/friendship/{userObjectId}", + Method = HttpMethod.Delete + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -1045,10 +1045,11 @@ namespace LeanCloud { strs.Add("validate_token", validateToken); } - var command = new AVCommand("requestLoginSmsCode", - method: "POST", - sessionToken: CurrentSessionToken, - data: strs); + var command = new AVCommand { + Path = "requestLoginSmsCode", + Method = HttpMethod.Post, + Content = strs + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -1183,10 +1184,11 @@ namespace LeanCloud { strs.Add("validate_token", validateToken); } - var command = new AVCommand("requestPasswordResetBySmsCode", - method: "POST", - sessionToken: currentSessionToken, - data: strs); + var command = new AVCommand { + Path = "requestPasswordResetBySmsCode", + Method = HttpMethod.Post, + Content = strs + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -1218,10 +1220,11 @@ namespace LeanCloud { { "password", newPassword } }; - var command = new AVCommand("resetPasswordBySmsCode/" + smsCode, - method: "PUT", - sessionToken: currentSessionToken, - data: strs); + var command = new AVCommand { + Path = $"resetPasswordBySmsCode/{smsCode}", + Method = HttpMethod.Put, + Content = strs + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -1278,10 +1281,11 @@ namespace LeanCloud { strs.Add("validate_token", validateToken); } - var command = new AVCommand("requestMobilePhoneVerify", - method: "POST", - sessionToken: currentSessionToken, - data: strs); + var command = new AVCommand { + Path = "requestMobilePhoneVerify", + Method = HttpMethod.Post, + Content = strs + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -1308,10 +1312,10 @@ namespace LeanCloud /// public static Task VerifyMobilePhoneAsync(string code, string mobilePhoneNumber, CancellationToken cancellationToken) { - var command = new AVCommand("verifyMobilePhone/" + code.Trim() + "?mobilePhoneNumber=" + mobilePhoneNumber.Trim(), - method: "POST", - sessionToken: null, - data: null); + var command = new AVCommand { + Path = $"verifyMobilePhone/{code.Trim()}?mobilePhoneNumber={mobilePhoneNumber.Trim()}", + Method = HttpMethod.Post + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -1325,11 +1329,10 @@ namespace LeanCloud /// public static Task VerifyMobilePhoneAsync(string code) { - var command = new AVCommand("verifyMobilePhone/" + code.Trim(), - method: "POST", - sessionToken: null, - data: null); - + var command = new AVCommand { + Path = $"verifyMobilePhone/{code.Trim()}", + Method = HttpMethod.Post + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); @@ -1363,10 +1366,11 @@ namespace LeanCloud { { "email", email } }; - var command = new AVCommand("requestEmailVerify", - method: "POST", - sessionToken: null, - data: strs); + var command = new AVCommand { + Path = "requestEmailVerify", + Method = HttpMethod.Post, + Content = strs + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); diff --git a/Storage/Storage/Public/LeaderBoard/AVLeaderboard.cs b/Storage/Storage/Public/LeaderBoard/AVLeaderboard.cs index aeb83f3..de0a3ce 100644 --- a/Storage/Storage/Public/LeaderBoard/AVLeaderboard.cs +++ b/Storage/Storage/Public/LeaderBoard/AVLeaderboard.cs @@ -2,8 +2,7 @@ using System.Threading.Tasks; using System.Collections.Generic; using LeanCloud.Storage.Internal; -using System.IO; -using System.Text; +using System.Net.Http; namespace LeanCloud { /// @@ -153,7 +152,11 @@ namespace LeanCloud { { "versionChangeInterval", versionChangeInterval.ToString().ToLower() }, { "updateStrategy", updateStrategy.ToString().ToLower() }, }; - var command = new AVCommand("leaderboard/leaderboards", "POST", data: data); + var command = new AVCommand { + Path = "leaderboard/leaderboards", + Method = HttpMethod.Post, + Content = data + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { var leaderboard = Parse(t.Result.Item2); @@ -211,7 +214,11 @@ namespace LeanCloud { if (overwrite) { path = string.Format("{0}?overwrite=1", path); } - var command = new AVCommand(path, "POST", user.SessionToken, data: data); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Post, + Content = data + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { List statisticList = new List(); @@ -242,7 +249,10 @@ namespace LeanCloud { path = string.Format("{0}?statistics={1}", path, names); } var sessionToken = AVUser.CurrentUser?.SessionToken; - var command = new AVCommand(path, "GET", sessionToken, data: null); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Post + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { List statisticList = new List(); @@ -272,7 +282,10 @@ namespace LeanCloud { var path = string.Format("leaderboard/users/{0}/statistics", user.ObjectId); var names = string.Join(",", statisticNames.ToArray()); path = string.Format("{0}?statistics={1}", path, names); - var command = new AVCommand(path, "DELETE", sessionToken: user.SessionToken, data: null); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Delete, + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command); } @@ -285,7 +298,10 @@ namespace LeanCloud { public Task> GetArchives(int skip = 0, int limit = 10) { var path = string.Format("leaderboard/leaderboards/{0}/archives", StatisticName); path = string.Format("{0}?skip={1}&limit={2}", path, skip, limit); - var command = new AVCommand(path, "GET", data: null); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Get + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { List archives = new List(); List list = t.Result.Item2["results"] as List; @@ -342,7 +358,10 @@ namespace LeanCloud { var statistics = string.Join(",", includeStatistics.ToArray()); path = string.Format("{0}&includeStatistics={1}", path, statistics); } - var command = new AVCommand(path, "GET", data: null); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Get + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { List rankingList = new List(); @@ -389,7 +408,11 @@ namespace LeanCloud { Task> Update(Dictionary data) { var path = string.Format("leaderboard/leaderboards/{0}", StatisticName); - var command = new AVCommand(path, "PUT", data: data); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Put, + Content = data + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { return t.Result.Item2; }); @@ -401,7 +424,10 @@ namespace LeanCloud { /// 排行榜对象 public Task Fetch() { var path = string.Format("leaderboard/leaderboards/{0}", StatisticName); - var command = new AVCommand(path, "GET", data: null); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Get + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { // 反序列化 Leaderboard 对象 @@ -419,7 +445,10 @@ namespace LeanCloud { /// 排行榜对象 public Task Reset() { var path = string.Format("leaderboard/leaderboards/{0}/incrementVersion", StatisticName); - var command = new AVCommand(path, "PUT", data: null); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Put + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { Init(t.Result.Item2); @@ -435,7 +464,10 @@ namespace LeanCloud { /// public Task Destroy() { var path = string.Format("leaderboard/leaderboards/{0}", StatisticName); - var command = new AVCommand(path, "DELETE", data: null); + var command = new AVCommand { + Path = path, + Method = HttpMethod.Delete + }; return AVPlugins.Instance.CommandRunner.RunCommandAsync(command); }