* LCFile.cs:

* FileTest.cs:
* LCQiniuUploader.cs:
* LCProgressableStreamContent.cs:

* LCAWSUploader.cs: chore: 支持文件保存进度
oneRain 2020-03-03 11:55:57 +08:00
parent 4df8179e5a
commit 0809a9c558
5 changed files with 93 additions and 13 deletions

View File

@ -7,6 +7,7 @@ using LeanCloud.Storage;
namespace LeanCloud.Test {
public class FileTest {
static readonly string AvatarFilePath = "../../../assets/hello.png";
static readonly string APKFilePath = "../../../assets/test.apk";
[SetUp]
public void SetUp() {
@ -31,7 +32,9 @@ namespace LeanCloud.Test {
[Test]
public async Task SaveFromPath() {
LCFile file = new LCFile("avatar", AvatarFilePath);
await file.Save();
await file.Save((count, total) => {
TestContext.WriteLine($"progress: {count}/{total}");
});
TestContext.WriteLine(file.ObjectId);
Assert.NotNull(file.ObjectId);
}
@ -60,7 +63,7 @@ namespace LeanCloud.Test {
[Test]
public async Task Qiniu() {
LCFile file = new LCFile("avatar", AvatarFilePath);
LCFile file = new LCFile("avatar", APKFilePath);
await file.Save();
TestContext.WriteLine(file.ObjectId);
Assert.NotNull(file.ObjectId);
@ -70,7 +73,7 @@ namespace LeanCloud.Test {
public async Task AWS() {
Logger.LogDelegate += Utils.Print;
LeanCloud.Initialize("UlCpyvLm8aMzQsW6KnP6W3Wt-MdYXbMMI", "PyCTYoNoxCVoKKg394PBeS4r", "https://ulcpyvlm.api.lncldglobal.com");
LCFile file = new LCFile("avatar", "../../../assets/hello.png");
LCFile file = new LCFile("avatar", APKFilePath);
await file.Save();
TestContext.WriteLine(file.ObjectId);
Assert.NotNull(file.ObjectId);

View File

@ -19,11 +19,13 @@ namespace LeanCloud.Storage.Internal.File {
this.data = data;
}
internal async Task Upload(Action<int, int> onProgress) {
internal async Task Upload(Action<long, long> onProgress) {
LCProgressableStreamContent content = new LCProgressableStreamContent(new ByteArrayContent(data), onProgress);
HttpRequestMessage request = new HttpRequestMessage {
RequestUri = new Uri(uploadUrl),
Method = HttpMethod.Put,
Content = new ByteArrayContent(data)
Content = content
};
HttpClient client = new HttpClient();
request.Headers.CacheControl = new CacheControlHeaderValue {

View File

@ -0,0 +1,71 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal.File {
internal class LCProgressableStreamContent : HttpContent {
const int defaultBufferSize = 5 * 4096;
readonly HttpContent content;
readonly int bufferSize;
readonly Action<long, long> progress;
internal LCProgressableStreamContent(HttpContent content, Action<long, long> progress) : this(content, defaultBufferSize, progress) { }
internal LCProgressableStreamContent(HttpContent content, int bufferSize, Action<long, long> progress) {
if (content == null) {
throw new ArgumentNullException("content");
}
if (bufferSize <= 0) {
throw new ArgumentOutOfRangeException("bufferSize");
}
this.content = content;
this.bufferSize = bufferSize;
this.progress = progress;
foreach (var h in content.Headers) {
Headers.Add(h.Key, h.Value);
}
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) {
return Task.Run(async () => {
var buffer = new byte[bufferSize];
TryComputeLength(out long size);
var uploaded = 0;
using (var sinput = await content.ReadAsStreamAsync()) {
while (true) {
var length = sinput.Read(buffer, 0, buffer.Length);
if (length <= 0) break;
uploaded += length;
progress?.Invoke(uploaded, size);
stream.Write(buffer, 0, length);
stream.Flush();
}
}
stream.Flush();
});
}
protected override bool TryComputeLength(out long length) {
length = content.Headers.ContentLength.GetValueOrDefault();
return true;
}
protected override void Dispose(bool disposing) {
if (disposing) {
content.Dispose();
}
base.Dispose(disposing);
}
}
}

View File

@ -22,11 +22,14 @@ namespace LeanCloud.Storage.Internal.File {
this.data = data;
}
internal async Task Upload(Action<int, int> onProgress) {
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new StringContent(key), "key");
content.Add(new StringContent(token), "token");
content.Add(new ByteArrayContent(data), "file");
internal async Task Upload(Action<long, long> onProgress) {
MultipartFormDataContent dataContent = new MultipartFormDataContent();
dataContent.Add(new StringContent(key), "key");
dataContent.Add(new StringContent(token), "token");
dataContent.Add(new ByteArrayContent(data), "file");
LCProgressableStreamContent content = new LCProgressableStreamContent(dataContent, onProgress);
HttpRequestMessage request = new HttpRequestMessage {
RequestUri = new Uri(uploadUrl),
Method = HttpMethod.Post,

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using LeanCloud.Storage.Internal.File;
using LeanCloud.Storage.Internal.Object;
using LeanCloud.Common;
namespace LeanCloud.Storage {
public class LCFile : LCObject {
@ -67,7 +68,7 @@ namespace LeanCloud.Storage {
MetaData[key] = value;
}
public async Task<LCFile> Save() {
public async Task<LCFile> Save(Action<long, long> onProgress = null) {
if (!string.IsNullOrEmpty(Url)) {
// 外链方式
await base.Save();
@ -81,11 +82,11 @@ namespace LeanCloud.Storage {
if (provider == "s3") {
// AWS
LCAWSUploader uploader = new LCAWSUploader(uploadUrl, MimeType, data);
await uploader.Upload(null);
await uploader.Upload(onProgress);
} else if (provider == "qiniu") {
// Qiniu
LCQiniuUploader uploader = new LCQiniuUploader(uploadUrl, token, key, data);
await uploader.Upload(null);
await uploader.Upload(onProgress);
} else {
throw new Exception($"{provider} is not support.");
}