chore: 重构网络模块
parent
fdfec81181
commit
d19f389e2a
|
@ -1,7 +1,6 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using LeanCloud;
|
using LeanCloud;
|
||||||
|
|
||||||
namespace LeanCloudTests {
|
namespace LeanCloudTests {
|
||||||
|
@ -16,7 +15,6 @@ namespace LeanCloudTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[AsyncStateMachine(typeof(ObjectControllerTests))]
|
|
||||||
public async Task TestSave() {
|
public async Task TestSave() {
|
||||||
TestContext.Out.WriteLine($"before at {Thread.CurrentThread.ManagedThreadId}");
|
TestContext.Out.WriteLine($"before at {Thread.CurrentThread.ManagedThreadId}");
|
||||||
var obj = AVObject.Create("Foo");
|
var obj = AVObject.Create("Foo");
|
||||||
|
@ -26,7 +24,6 @@ namespace LeanCloudTests {
|
||||||
Assert.NotNull(obj.ObjectId);
|
Assert.NotNull(obj.ObjectId);
|
||||||
Assert.NotNull(obj.CreatedAt);
|
Assert.NotNull(obj.CreatedAt);
|
||||||
Assert.NotNull(obj.UpdatedAt);
|
Assert.NotNull(obj.UpdatedAt);
|
||||||
await Task.Delay(10000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal
|
||||||
{
|
{
|
||||||
|
@ -43,7 +44,13 @@ namespace LeanCloud.Storage.Internal
|
||||||
string appId = AVClient.CurrentConfiguration.ApplicationId;
|
string appId = AVClient.CurrentConfiguration.ApplicationId;
|
||||||
string url = string.Format("https://app-router.leancloud.cn/2/route?appId={0}", appId);
|
string url = string.Format("https://app-router.leancloud.cn/2/route?appId={0}", appId);
|
||||||
|
|
||||||
var ret = await AVClient.HttpGetAsync(new Uri(url));
|
var request = new HttpRequest {
|
||||||
|
Uri = new Uri(url),
|
||||||
|
Method = HttpMethod.Get,
|
||||||
|
Headers = null,
|
||||||
|
Data = null
|
||||||
|
};
|
||||||
|
var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None);
|
||||||
if (ret.Item1 != HttpStatusCode.OK) {
|
if (ret.Item1 != HttpStatusCode.OK) {
|
||||||
throw new AVException(AVException.ErrorCode.ConnectionFailed, "can not reach router.", null);
|
throw new AVException(AVException.ErrorCode.ConnectionFailed, "can not reach router.", null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using LeanCloud.Storage.Internal;
|
using LeanCloud.Storage.Internal;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal
|
||||||
{
|
{
|
||||||
|
@ -14,105 +15,154 @@ namespace LeanCloud.Storage.Internal
|
||||||
public class AVCommand : HttpRequest
|
public class AVCommand : HttpRequest
|
||||||
{
|
{
|
||||||
public IDictionary<string, object> DataObject { get; private set; }
|
public IDictionary<string, object> DataObject { get; private set; }
|
||||||
public override Stream Data
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (base.Data != null)
|
|
||||||
{
|
|
||||||
return base.Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.Data = (DataObject != null
|
public object Body {
|
||||||
? new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(DataObject)))
|
get; set;
|
||||||
: null);
|
}
|
||||||
|
|
||||||
|
public override Stream Data {
|
||||||
|
get {
|
||||||
|
return new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(Body)));
|
||||||
}
|
}
|
||||||
set { base.Data = value; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVCommand(string relativeUri,
|
public AVCommand(string relativeUri,
|
||||||
string method,
|
string method,
|
||||||
string sessionToken = null,
|
string sessionToken = null,
|
||||||
IList<KeyValuePair<string, string>> headers = null,
|
IList<KeyValuePair<string, string>> headers = null,
|
||||||
IDictionary<string, object> data = null) : this(relativeUri: relativeUri,
|
object data = null)
|
||||||
method: method,
|
|
||||||
sessionToken: sessionToken,
|
|
||||||
headers: headers,
|
|
||||||
stream: null,
|
|
||||||
contentType: data != null ? "application/json" : null)
|
|
||||||
{
|
|
||||||
DataObject = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AVCommand(string relativeUri,
|
|
||||||
string method,
|
|
||||||
string sessionToken = null,
|
|
||||||
IList<KeyValuePair<string, string>> headers = null,
|
|
||||||
Stream stream = null,
|
|
||||||
string contentType = null)
|
|
||||||
{
|
{
|
||||||
var state = AVPlugins.Instance.AppRouterController.Get();
|
var state = AVPlugins.Instance.AppRouterController.Get();
|
||||||
var urlTemplate = "https://{0}/{1}/{2}";
|
var urlTemplate = "https://{0}/{1}/{2}";
|
||||||
AVClient.Configuration configuration = AVClient.CurrentConfiguration;
|
AVClient.Configuration configuration = AVClient.CurrentConfiguration;
|
||||||
var apiVersion = "1.1";
|
var apiVersion = "1.1";
|
||||||
if (relativeUri.StartsWith("push") || relativeUri.StartsWith("installations"))
|
if (relativeUri.StartsWith("push") || relativeUri.StartsWith("installations")) {
|
||||||
{
|
|
||||||
Uri = new Uri(string.Format(urlTemplate, state.PushServer, apiVersion, relativeUri));
|
Uri = new Uri(string.Format(urlTemplate, state.PushServer, apiVersion, relativeUri));
|
||||||
if (configuration.PushServer != null)
|
if (configuration.PushServer != null) {
|
||||||
{
|
|
||||||
Uri = new Uri(string.Format("{0}{1}/{2}", configuration.PushServer, apiVersion, relativeUri));
|
Uri = new Uri(string.Format("{0}{1}/{2}", configuration.PushServer, apiVersion, relativeUri));
|
||||||
}
|
}
|
||||||
}
|
} else if (relativeUri.StartsWith("stats") || relativeUri.StartsWith("always_collect") || relativeUri.StartsWith("statistics")) {
|
||||||
else if (relativeUri.StartsWith("stats") || relativeUri.StartsWith("always_collect") || relativeUri.StartsWith("statistics"))
|
|
||||||
{
|
|
||||||
Uri = new Uri(string.Format(urlTemplate, state.StatsServer, apiVersion, relativeUri));
|
Uri = new Uri(string.Format(urlTemplate, state.StatsServer, apiVersion, relativeUri));
|
||||||
if (configuration.StatsServer != null)
|
if (configuration.StatsServer != null) {
|
||||||
{
|
|
||||||
Uri = new Uri(string.Format("{0}{1}/{2}", configuration.StatsServer, apiVersion, relativeUri));
|
Uri = new Uri(string.Format("{0}{1}/{2}", configuration.StatsServer, apiVersion, relativeUri));
|
||||||
}
|
}
|
||||||
}
|
} else if (relativeUri.StartsWith("functions") || relativeUri.StartsWith("call")) {
|
||||||
else if (relativeUri.StartsWith("functions") || relativeUri.StartsWith("call"))
|
|
||||||
{
|
|
||||||
Uri = new Uri(string.Format(urlTemplate, state.EngineServer, apiVersion, relativeUri));
|
Uri = new Uri(string.Format(urlTemplate, state.EngineServer, apiVersion, relativeUri));
|
||||||
|
|
||||||
if (configuration.EngineServer != null)
|
if (configuration.EngineServer != null) {
|
||||||
{
|
|
||||||
Uri = new Uri(string.Format("{0}{1}/{2}", configuration.EngineServer, apiVersion, relativeUri));
|
Uri = new Uri(string.Format("{0}{1}/{2}", configuration.EngineServer, apiVersion, relativeUri));
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Uri = new Uri(string.Format(urlTemplate, state.ApiServer, apiVersion, relativeUri));
|
Uri = new Uri(string.Format(urlTemplate, state.ApiServer, apiVersion, relativeUri));
|
||||||
|
|
||||||
if (configuration.ApiServer != null)
|
if (configuration.ApiServer != null) {
|
||||||
{
|
|
||||||
Uri = new Uri(string.Format("{0}{1}/{2}", configuration.ApiServer, apiVersion, relativeUri));
|
Uri = new Uri(string.Format("{0}{1}/{2}", configuration.ApiServer, apiVersion, relativeUri));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Method = method;
|
switch (method) {
|
||||||
Data = stream;
|
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<KeyValuePair<string, string>>(headers ?? Enumerable.Empty<KeyValuePair<string, string>>());
|
Headers = new List<KeyValuePair<string, string>>(headers ?? Enumerable.Empty<KeyValuePair<string, string>>());
|
||||||
|
|
||||||
string useProduction = AVClient.UseProduction ? "1" : "0";
|
string useProduction = AVClient.UseProduction ? "1" : "0";
|
||||||
Headers.Add(new KeyValuePair<string, string>("X-LC-Prod", useProduction));
|
Headers.Add(new KeyValuePair<string, string>("X-LC-Prod", useProduction));
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(sessionToken))
|
if (!string.IsNullOrEmpty(sessionToken)) {
|
||||||
{
|
|
||||||
Headers.Add(new KeyValuePair<string, string>("X-LC-Session", sessionToken));
|
Headers.Add(new KeyValuePair<string, string>("X-LC-Session", sessionToken));
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(contentType))
|
|
||||||
{
|
Headers.Add(new KeyValuePair<string, string>("Content-Type", "application/json"));
|
||||||
Headers.Add(new KeyValuePair<string, string>("Content-Type", contentType));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//public AVCommand(string relativeUri,
|
||||||
|
// string method,
|
||||||
|
// string sessionToken = null,
|
||||||
|
// IList<KeyValuePair<string, string>> 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<KeyValuePair<string, string>>(headers ?? Enumerable.Empty<KeyValuePair<string, string>>());
|
||||||
|
|
||||||
|
// string useProduction = AVClient.UseProduction ? "1" : "0";
|
||||||
|
// Headers.Add(new KeyValuePair<string, string>("X-LC-Prod", useProduction));
|
||||||
|
|
||||||
|
// if (!string.IsNullOrEmpty(sessionToken))
|
||||||
|
// {
|
||||||
|
// Headers.Add(new KeyValuePair<string, string>("X-LC-Session", sessionToken));
|
||||||
|
// }
|
||||||
|
// if (!string.IsNullOrEmpty(contentType))
|
||||||
|
// {
|
||||||
|
// Headers.Add(new KeyValuePair<string, string>("Content-Type", contentType));
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
public AVCommand(AVCommand other)
|
public AVCommand(AVCommand other)
|
||||||
{
|
{
|
||||||
this.Uri = other.Uri;
|
this.Uri = other.Uri;
|
||||||
this.Method = other.Method;
|
this.Method = other.Method;
|
||||||
this.DataObject = other.DataObject;
|
this.DataObject = other.DataObject;
|
||||||
this.Headers = new List<KeyValuePair<string, string>>(other.Headers);
|
this.Headers = new List<KeyValuePair<string, string>>(other.Headers);
|
||||||
this.Data = other.Data;
|
this.Body = other.Data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace LeanCloud.Storage.Internal
|
||||||
/// <param name="downloadProgress"></param>
|
/// <param name="downloadProgress"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<Tuple<HttpStatusCode, IDictionary<string, object>>> RunCommandAsync(AVCommand command,
|
public Task<Tuple<HttpStatusCode, IDictionary<string, object>>> RunCommandAsync(HttpRequest command,
|
||||||
IProgress<AVUploadProgressEventArgs> uploadProgress = null,
|
IProgress<AVUploadProgressEventArgs> uploadProgress = null,
|
||||||
IProgress<AVDownloadProgressEventArgs> downloadProgress = null,
|
IProgress<AVDownloadProgressEventArgs> downloadProgress = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
@ -99,11 +99,11 @@ namespace LeanCloud.Storage.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string revocableSessionTokenTrueValue = "1";
|
private const string revocableSessionTokenTrueValue = "1";
|
||||||
private Task<AVCommand> PrepareCommand(AVCommand command)
|
private Task<HttpRequest> PrepareCommand(HttpRequest command)
|
||||||
{
|
{
|
||||||
AVCommand newCommand = new AVCommand(command);
|
HttpRequest newCommand = command;
|
||||||
|
|
||||||
Task<AVCommand> installationIdTask = installationIdController.GetAsync().ContinueWith(t =>
|
Task<HttpRequest> installationIdTask = installationIdController.GetAsync().ContinueWith(t =>
|
||||||
{
|
{
|
||||||
newCommand.Headers.Add(new KeyValuePair<string, string>("X-LC-Installation-Id", t.Result.ToString()));
|
newCommand.Headers.Add(new KeyValuePair<string, string>("X-LC-Installation-Id", t.Result.ToString()));
|
||||||
return newCommand;
|
return newCommand;
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace LeanCloud.Storage.Internal
|
||||||
/// <param name="downloadProgress">Download progress callback.</param>
|
/// <param name="downloadProgress">Download progress callback.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token for the request.</param>
|
/// <param name="cancellationToken">The cancellation token for the request.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Tuple<HttpStatusCode, IDictionary<string, object>>> RunCommandAsync(AVCommand command,
|
Task<Tuple<HttpStatusCode, IDictionary<string, object>>> RunCommandAsync(HttpRequest command,
|
||||||
IProgress<AVUploadProgressEventArgs> uploadProgress = null,
|
IProgress<AVUploadProgressEventArgs> uploadProgress = null,
|
||||||
IProgress<AVDownloadProgressEventArgs> downloadProgress = null,
|
IProgress<AVDownloadProgressEventArgs> downloadProgress = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken));
|
CancellationToken cancellationToken = default(CancellationToken));
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LeanCloud.Storage.Internal;
|
using LeanCloud.Storage.Internal;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -32,55 +33,36 @@ namespace LeanCloud.Storage.Internal
|
||||||
/// <param name="sessionToken">Session token.</param>
|
/// <param name="sessionToken">Session token.</param>
|
||||||
/// <param name="progress">Progress.</param>
|
/// <param name="progress">Progress.</param>
|
||||||
/// <param name="cancellationToken">Cancellation token.</param>
|
/// <param name="cancellationToken">Cancellation token.</param>
|
||||||
public virtual Task<FileState> SaveAsync(FileState state,
|
public virtual async Task<FileState> SaveAsync(FileState state,
|
||||||
Stream dataStream,
|
Stream dataStream,
|
||||||
String sessionToken,
|
String sessionToken,
|
||||||
IProgress<AVUploadProgressEventArgs> progress,
|
IProgress<AVUploadProgressEventArgs> progress,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken)) {
|
||||||
{
|
if (state.Url != null) {
|
||||||
if (state.Url != null)
|
|
||||||
{
|
|
||||||
// !isDirty
|
// !isDirty
|
||||||
return Task<FileState>.FromResult(state);
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested) {
|
||||||
{
|
return null;
|
||||||
var tcs = new TaskCompletionSource<FileState>();
|
|
||||||
tcs.TrySetCanceled();
|
|
||||||
return tcs.Task;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldPosition = dataStream.Position;
|
var oldPosition = dataStream.Position;
|
||||||
var command = new AVCommand("files/" + state.Name,
|
|
||||||
method: "POST",
|
|
||||||
sessionToken: sessionToken,
|
|
||||||
contentType: state.MimeType,
|
|
||||||
stream: dataStream);
|
|
||||||
|
|
||||||
return commandRunner.RunCommandAsync(command,
|
var request = new HttpRequest {
|
||||||
uploadProgress: progress,
|
Uri = new Uri("files/" + state.Name),
|
||||||
cancellationToken: cancellationToken).OnSuccess(uploadTask =>
|
Method = HttpMethod.Post,
|
||||||
{
|
Headers = new List<KeyValuePair<string, string>> {
|
||||||
var result = uploadTask.Result;
|
new KeyValuePair<string, string>("Content-Type", state.MimeType)
|
||||||
var jsonData = result.Item2;
|
}
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
};
|
||||||
|
var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None);
|
||||||
return new FileState
|
var jsonData = Json.Parse(ret.Item2) as Dictionary<string, object>;
|
||||||
{
|
return new FileState {
|
||||||
Name = jsonData["name"] as string,
|
Name = jsonData["name"] as string,
|
||||||
Url = new Uri(jsonData["url"] as string, UriKind.Absolute),
|
Url = new Uri(jsonData["url"] as string, UriKind.Absolute),
|
||||||
MimeType = state.MimeType
|
MimeType = state.MimeType
|
||||||
};
|
};
|
||||||
}).ContinueWith(t =>
|
|
||||||
{
|
|
||||||
// Rewind the stream on failure or cancellation (if possible)
|
|
||||||
if ((t.IsFaulted || t.IsCanceled) && dataStream.CanSeek)
|
|
||||||
{
|
|
||||||
dataStream.Seek(oldPosition, SeekOrigin.Begin);
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
}).Unwrap();
|
|
||||||
}
|
}
|
||||||
public Task DeleteAsync(FileState state, string sessionToken, CancellationToken cancellationToken)
|
public Task DeleteAsync(FileState state, string sessionToken, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Threading;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using LeanCloud.Storage.Internal;
|
using LeanCloud.Storage.Internal;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal
|
||||||
{
|
{
|
||||||
|
@ -40,15 +41,18 @@ namespace LeanCloud.Storage.Internal
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Task<FileState> PutFile(FileState state, string uploadUrl, Stream dataStream)
|
internal async Task<FileState> PutFile(FileState state, string uploadUrl, Stream dataStream)
|
||||||
{
|
{
|
||||||
IList<KeyValuePair<string, string>> makeBlockHeaders = new List<KeyValuePair<string, string>>();
|
IList<KeyValuePair<string, string>> makeBlockHeaders = new List<KeyValuePair<string, string>>();
|
||||||
makeBlockHeaders.Add(new KeyValuePair<string, string>("Content-Type", state.MimeType));
|
makeBlockHeaders.Add(new KeyValuePair<string, string>("Content-Type", state.MimeType));
|
||||||
|
var request = new HttpRequest {
|
||||||
return AVClient.RequestAsync(new Uri(uploadUrl), "PUT", makeBlockHeaders, dataStream, state.MimeType, CancellationToken.None).OnSuccess(t =>
|
Uri = new Uri(uploadUrl),
|
||||||
{
|
Method = HttpMethod.Put,
|
||||||
return state;
|
Headers = makeBlockHeaders,
|
||||||
});
|
Data = dataStream
|
||||||
|
};
|
||||||
|
await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None);
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -159,7 +160,7 @@ namespace LeanCloud.Storage.Internal
|
||||||
|
|
||||||
return HexStringFromBytes(hashBytes);
|
return HexStringFromBytes(hashBytes);
|
||||||
}
|
}
|
||||||
Task<Tuple<HttpStatusCode, IDictionary<string, object>>> PostToQCloud(
|
async Task<Tuple<HttpStatusCode, IDictionary<string, object>>> PostToQCloud(
|
||||||
Dictionary<string, object> body,
|
Dictionary<string, object> body,
|
||||||
byte[] sliceFile,
|
byte[] sliceFile,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
|
@ -174,14 +175,15 @@ namespace LeanCloud.Storage.Internal
|
||||||
|
|
||||||
sliceHeaders.Add(new KeyValuePair<string, string>("Content-Type", contentType));
|
sliceHeaders.Add(new KeyValuePair<string, string>("Content-Type", contentType));
|
||||||
|
|
||||||
var rtn = AVClient.RequestAsync(new Uri(this.uploadUrl), "POST", sliceHeaders, tempStream, null, cancellationToken).OnSuccess(_ =>
|
var request = new HttpRequest {
|
||||||
{
|
Uri = new Uri(this.uploadUrl),
|
||||||
var dic = AVClient.ReponseResolve(_.Result, CancellationToken.None);
|
Method = HttpMethod.Post,
|
||||||
|
Headers = sliceHeaders,
|
||||||
return dic;
|
Data = tempStream
|
||||||
});
|
};
|
||||||
|
var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None);
|
||||||
return rtn;
|
var result = new Tuple<HttpStatusCode, IDictionary<string, object>>(ret.Item1, Json.Parse(ret.Item2) as Dictionary<string, object>);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
public static Stream HttpUploadFile(byte[] file, string fileName, out string contentType, out long contentLength, IDictionary<string, object> nvc)
|
public static Stream HttpUploadFile(byte[] file, string fileName, out string contentType, out long contentLength, IDictionary<string, object> nvc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@ using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal
|
||||||
{
|
{
|
||||||
|
@ -173,20 +174,32 @@ namespace LeanCloud.Storage.Internal
|
||||||
return makeBlockHeaders;
|
return makeBlockHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task<Tuple<HttpStatusCode, string>> MakeBlock(FileState state, byte[] firstChunkBinary, long blcokSize = 4194304)
|
async Task<Tuple<HttpStatusCode, string>> MakeBlock(FileState state, byte[] firstChunkBinary, long blcokSize = 4194304) {
|
||||||
{
|
|
||||||
MemoryStream firstChunkData = new MemoryStream(firstChunkBinary, 0, firstChunkBinary.Length);
|
MemoryStream firstChunkData = new MemoryStream(firstChunkBinary, 0, firstChunkBinary.Length);
|
||||||
return AVClient.RequestAsync(new Uri(new Uri(UP_HOST) + string.Format("mkblk/{0}", blcokSize)), "POST", GetQiniuRequestHeaders(state), firstChunkData, "application/octet-stream", CancellationToken.None);
|
var headers = GetQiniuRequestHeaders(state);
|
||||||
|
headers.Add(new KeyValuePair<string, string>("Content-Type", "application/octet-stream"));
|
||||||
|
var request = new HttpRequest {
|
||||||
|
Uri = new Uri(new Uri(UP_HOST) + string.Format("mkblk/{0}", blcokSize)),
|
||||||
|
Method = HttpMethod.Post,
|
||||||
|
Headers = headers,
|
||||||
|
Data = firstChunkData
|
||||||
|
};
|
||||||
|
return await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None);
|
||||||
}
|
}
|
||||||
Task<Tuple<HttpStatusCode, string>> PutChunk(FileState state, byte[] chunkBinary, string LastChunkctx, long currentChunkOffsetInBlock)
|
|
||||||
{
|
async Task<Tuple<HttpStatusCode, string>> PutChunk(FileState state, byte[] chunkBinary, string LastChunkctx, long currentChunkOffsetInBlock) {
|
||||||
MemoryStream chunkData = new MemoryStream(chunkBinary, 0, chunkBinary.Length);
|
MemoryStream chunkData = new MemoryStream(chunkBinary, 0, chunkBinary.Length);
|
||||||
return AVClient.RequestAsync(new Uri(new Uri(UP_HOST) + string.Format("bput/{0}/{1}", LastChunkctx,
|
var request = new HttpRequest {
|
||||||
currentChunkOffsetInBlock)), "POST",
|
Uri = new Uri(new Uri(UP_HOST) + string.Format("bput/{0}/{1}", LastChunkctx, currentChunkOffsetInBlock)),
|
||||||
GetQiniuRequestHeaders(state), chunkData,
|
Method = HttpMethod.Post,
|
||||||
"application/octet-stream", CancellationToken.None);
|
Headers = GetQiniuRequestHeaders(state),
|
||||||
|
Data = chunkData
|
||||||
|
};
|
||||||
|
var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
internal Task<Tuple<HttpStatusCode, string>> QiniuMakeFile(FileState state, Stream dataStream, string upToken, string key, long fsize, string[] ctxes, CancellationToken cancellationToken)
|
|
||||||
|
internal async Task<Tuple<HttpStatusCode, string>> QiniuMakeFile(FileState state, Stream dataStream, string upToken, string key, long fsize, string[] ctxes, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
StringBuilder urlBuilder = new StringBuilder();
|
StringBuilder urlBuilder = new StringBuilder();
|
||||||
urlBuilder.AppendFormat("{0}/mkfile/{1}", UP_HOST, fsize);
|
urlBuilder.AppendFormat("{0}/mkfile/{1}", UP_HOST, fsize);
|
||||||
|
@ -208,6 +221,7 @@ namespace LeanCloud.Storage.Internal
|
||||||
|
|
||||||
string authHead = "UpToken " + upToken;
|
string authHead = "UpToken " + upToken;
|
||||||
headers.Add(new KeyValuePair<string, string>("Authorization", authHead));
|
headers.Add(new KeyValuePair<string, string>("Authorization", authHead));
|
||||||
|
headers.Add(new KeyValuePair<string, string>("Content-Type", "text/plain"));
|
||||||
int proCount = ctxes.Length;
|
int proCount = ctxes.Length;
|
||||||
Stream body = new MemoryStream();
|
Stream body = new MemoryStream();
|
||||||
|
|
||||||
|
@ -221,13 +235,14 @@ namespace LeanCloud.Storage.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body.Seek(0, SeekOrigin.Begin);
|
body.Seek(0, SeekOrigin.Begin);
|
||||||
|
var request = new HttpRequest {
|
||||||
var rtn = AVClient.RequestAsync(new Uri(urlBuilder.ToString()), "POST", headers, body, "text/plain", cancellationToken).OnSuccess(_ =>
|
Uri = new Uri(urlBuilder.ToString()),
|
||||||
{
|
Method = HttpMethod.Post,
|
||||||
var dic = AVClient.ReponseResolve(_.Result, CancellationToken.None);
|
Headers = headers,
|
||||||
return _.Result;
|
Data = body
|
||||||
});
|
};
|
||||||
return rtn;
|
var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
internal void MergeFromJSON(FileState state, IDictionary<string, object> jsonData)
|
internal void MergeFromJSON(FileState state, IDictionary<string, object> jsonData)
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,18 +41,17 @@ namespace LeanCloud.Storage.Internal {
|
||||||
IProgress<AVUploadProgressEventArgs> uploadProgress,
|
IProgress<AVUploadProgressEventArgs> uploadProgress,
|
||||||
IProgress<AVDownloadProgressEventArgs> downloadProgress,
|
IProgress<AVDownloadProgressEventArgs> downloadProgress,
|
||||||
CancellationToken cancellationToken) {
|
CancellationToken cancellationToken) {
|
||||||
|
|
||||||
HttpMethod httpMethod = new HttpMethod(httpRequest.Method);
|
HttpMethod httpMethod = httpRequest.Method;
|
||||||
HttpRequestMessage message = new HttpRequestMessage(httpMethod, httpRequest.Uri);
|
HttpRequestMessage message = new HttpRequestMessage(httpMethod, httpRequest.Uri);
|
||||||
|
|
||||||
// Fill in zero-length data if method is post.
|
// Fill in zero-length data if method is post.
|
||||||
Stream data = httpRequest.Data;
|
if (httpRequest.Data == null && httpRequest.Method == HttpMethod.Post) {
|
||||||
if (httpRequest.Data == null && httpRequest.Method.ToLower().Equals("post")) {
|
message.Content = new StreamContent(new MemoryStream(new byte[0]));
|
||||||
data = new MemoryStream(new byte[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data != null) {
|
if (httpRequest.Data != null) {
|
||||||
message.Content = new StreamContent(data);
|
message.Content = new StreamContent(httpRequest.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (httpRequest.Headers != null) {
|
if (httpRequest.Headers != null) {
|
||||||
|
@ -74,6 +73,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
uploadProgress?.Report(new AVUploadProgressEventArgs { Progress = 0 });
|
uploadProgress?.Report(new AVUploadProgressEventArgs { Progress = 0 });
|
||||||
var response = await client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
var response = await client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||||||
uploadProgress?.Report(new AVUploadProgressEventArgs { Progress = 1 });
|
uploadProgress?.Report(new AVUploadProgressEventArgs { Progress = 1 });
|
||||||
|
message.Dispose();
|
||||||
|
|
||||||
var resultString = await response.Content.ReadAsStringAsync();
|
var resultString = await response.Content.ReadAsStringAsync();
|
||||||
response.Dispose();
|
response.Dispose();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal
|
||||||
{
|
{
|
||||||
|
@ -10,16 +11,12 @@ namespace LeanCloud.Storage.Internal
|
||||||
public class HttpRequest
|
public class HttpRequest
|
||||||
{
|
{
|
||||||
public Uri Uri { get; set; }
|
public Uri Uri { get; set; }
|
||||||
|
|
||||||
public IList<KeyValuePair<string, string>> Headers { get; set; }
|
public IList<KeyValuePair<string, string>> Headers { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
// HttpMethod
|
||||||
/// Data stream to be uploaded.
|
public HttpMethod Method { get; set; }
|
||||||
/// </summary>
|
|
||||||
public virtual Stream Data { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public virtual Stream Data { get; set; }
|
||||||
/// HTTP method. One of <c>DELETE</c>, <c>GET</c>, <c>HEAD</c>, <c>POST</c> or <c>PUT</c>
|
|
||||||
/// </summary>
|
|
||||||
public string Method { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace LeanCloud
|
||||||
/// AVClient contains static functions that handle global
|
/// AVClient contains static functions that handle global
|
||||||
/// configuration for the LeanCloud library.
|
/// configuration for the LeanCloud library.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static partial class AVClient
|
public static class AVClient
|
||||||
{
|
{
|
||||||
public static readonly string[] DateFormatStrings = {
|
public static readonly string[] DateFormatStrings = {
|
||||||
// Official ISO format
|
// Official ISO format
|
||||||
|
@ -367,37 +367,37 @@ namespace LeanCloud
|
||||||
return Json.Encode(jsonData);
|
return Json.Encode(jsonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<Tuple<HttpStatusCode, string>> HttpGetAsync(Uri uri)
|
//public static Task<Tuple<HttpStatusCode, string>> HttpGetAsync(Uri uri)
|
||||||
{
|
//{
|
||||||
return RequestAsync(uri, "GET", null, body: null, contentType: null, cancellationToken: CancellationToken.None);
|
// return RequestAsync(uri, "GET", null, body: null, contentType: null, cancellationToken: CancellationToken.None);
|
||||||
}
|
//}
|
||||||
|
|
||||||
public static Task<Tuple<HttpStatusCode, string>> RequestAsync(Uri uri, string method, IList<KeyValuePair<string, string>> headers, IDictionary<string, object> body, string contentType, CancellationToken cancellationToken)
|
//public static Task<Tuple<HttpStatusCode, string>> RequestAsync(Uri uri, string method, IList<KeyValuePair<string, string>> headers, IDictionary<string, object> body, string contentType, CancellationToken cancellationToken)
|
||||||
{
|
//{
|
||||||
var dataStream = body != null ? new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(body))) : null;
|
// var dataStream = body != null ? new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(body))) : null;
|
||||||
return AVClient.RequestAsync(uri, method, headers, dataStream, contentType, cancellationToken);
|
// return AVClient.RequestAsync(uri, method, headers, dataStream, contentType, cancellationToken);
|
||||||
//return AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, cancellationToken);
|
// //return AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, cancellationToken);
|
||||||
}
|
//}
|
||||||
|
|
||||||
public static Task<Tuple<HttpStatusCode, string>> RequestAsync(Uri uri, string method, IList<KeyValuePair<string, string>> headers, Stream data, string contentType, CancellationToken cancellationToken)
|
//public static Task<Tuple<HttpStatusCode, string>> RequestAsync(Uri uri, string method, IList<KeyValuePair<string, string>> headers, Stream data, string contentType, CancellationToken cancellationToken)
|
||||||
{
|
//{
|
||||||
HttpRequest request = new HttpRequest()
|
// HttpRequest request = new HttpRequest()
|
||||||
{
|
// {
|
||||||
Data = data != null ? data : null,
|
// Data = data != null ? data : null,
|
||||||
Headers = headers,
|
// Headers = headers,
|
||||||
Method = method,
|
// Method = method,
|
||||||
Uri = uri
|
// Uri = uri
|
||||||
};
|
// };
|
||||||
return AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, cancellationToken).OnSuccess(t =>
|
// return AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, cancellationToken).OnSuccess(t =>
|
||||||
{
|
// {
|
||||||
var response = t.Result;
|
// var response = t.Result;
|
||||||
var contentString = response.Item2;
|
// var contentString = response.Item2;
|
||||||
int responseCode = (int)response.Item1;
|
// int responseCode = (int)response.Item1;
|
||||||
var responseLog = responseCode + ";" + contentString;
|
// var responseLog = responseCode + ";" + contentString;
|
||||||
PrintLog(responseLog);
|
// PrintLog(responseLog);
|
||||||
return response;
|
// return response;
|
||||||
});
|
// });
|
||||||
}
|
//}
|
||||||
|
|
||||||
internal static Tuple<HttpStatusCode, IDictionary<string, object>> ReponseResolve(Tuple<HttpStatusCode, string> response, CancellationToken cancellationToken)
|
internal static Tuple<HttpStatusCode, IDictionary<string, object>> ReponseResolve(Tuple<HttpStatusCode, string> response, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
@ -477,21 +477,8 @@ namespace LeanCloud
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (request is AVCommand)
|
var bodyLog = "Body:" + Json.Encode(request.Data);
|
||||||
{
|
sb.AppendLine(bodyLog);
|
||||||
var command = (AVCommand)request;
|
|
||||||
if (command.DataObject != null)
|
|
||||||
{
|
|
||||||
var bodyLog = "Body:" + Json.Encode(command.DataObject);
|
|
||||||
sb.AppendLine(bodyLog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
StreamReader reader = new StreamReader(request.Data);
|
|
||||||
string bodyLog = reader.ReadToEnd();
|
|
||||||
sb.AppendLine(bodyLog);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
|
|
@ -211,9 +211,7 @@ namespace LeanCloud {
|
||||||
if (overwrite) {
|
if (overwrite) {
|
||||||
path = string.Format("{0}?overwrite=1", path);
|
path = string.Format("{0}?overwrite=1", path);
|
||||||
}
|
}
|
||||||
var dataStr = Json.Encode(data);
|
var command = new AVCommand(path, "POST", user.SessionToken, data: data);
|
||||||
var dataStream = new MemoryStream(Encoding.UTF8.GetBytes(dataStr));
|
|
||||||
var command = new AVCommand(path, "POST", contentType: "application/json", sessionToken: user.SessionToken, stream: dataStream);
|
|
||||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => {
|
return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => {
|
||||||
try {
|
try {
|
||||||
List<AVStatistic> statisticList = new List<AVStatistic>();
|
List<AVStatistic> statisticList = new List<AVStatistic>();
|
||||||
|
|
Loading…
Reference in New Issue