* LCFile.cs:
* FileTest.cs: * LCQiniuUploader.cs: * LCProgressableStreamContent.cs: * LCAWSUploader.cs: chore: 支持文件保存进度
parent
4df8179e5a
commit
0809a9c558
|
@ -7,6 +7,7 @@ using LeanCloud.Storage;
|
||||||
namespace LeanCloud.Test {
|
namespace LeanCloud.Test {
|
||||||
public class FileTest {
|
public class FileTest {
|
||||||
static readonly string AvatarFilePath = "../../../assets/hello.png";
|
static readonly string AvatarFilePath = "../../../assets/hello.png";
|
||||||
|
static readonly string APKFilePath = "../../../assets/test.apk";
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() {
|
public void SetUp() {
|
||||||
|
@ -31,7 +32,9 @@ namespace LeanCloud.Test {
|
||||||
[Test]
|
[Test]
|
||||||
public async Task SaveFromPath() {
|
public async Task SaveFromPath() {
|
||||||
LCFile file = new LCFile("avatar", AvatarFilePath);
|
LCFile file = new LCFile("avatar", AvatarFilePath);
|
||||||
await file.Save();
|
await file.Save((count, total) => {
|
||||||
|
TestContext.WriteLine($"progress: {count}/{total}");
|
||||||
|
});
|
||||||
TestContext.WriteLine(file.ObjectId);
|
TestContext.WriteLine(file.ObjectId);
|
||||||
Assert.NotNull(file.ObjectId);
|
Assert.NotNull(file.ObjectId);
|
||||||
}
|
}
|
||||||
|
@ -60,7 +63,7 @@ namespace LeanCloud.Test {
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Qiniu() {
|
public async Task Qiniu() {
|
||||||
LCFile file = new LCFile("avatar", AvatarFilePath);
|
LCFile file = new LCFile("avatar", APKFilePath);
|
||||||
await file.Save();
|
await file.Save();
|
||||||
TestContext.WriteLine(file.ObjectId);
|
TestContext.WriteLine(file.ObjectId);
|
||||||
Assert.NotNull(file.ObjectId);
|
Assert.NotNull(file.ObjectId);
|
||||||
|
@ -70,7 +73,7 @@ namespace LeanCloud.Test {
|
||||||
public async Task AWS() {
|
public async Task AWS() {
|
||||||
Logger.LogDelegate += Utils.Print;
|
Logger.LogDelegate += Utils.Print;
|
||||||
LeanCloud.Initialize("UlCpyvLm8aMzQsW6KnP6W3Wt-MdYXbMMI", "PyCTYoNoxCVoKKg394PBeS4r", "https://ulcpyvlm.api.lncldglobal.com");
|
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();
|
await file.Save();
|
||||||
TestContext.WriteLine(file.ObjectId);
|
TestContext.WriteLine(file.ObjectId);
|
||||||
Assert.NotNull(file.ObjectId);
|
Assert.NotNull(file.ObjectId);
|
||||||
|
|
|
@ -19,11 +19,13 @@ namespace LeanCloud.Storage.Internal.File {
|
||||||
this.data = data;
|
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 {
|
HttpRequestMessage request = new HttpRequestMessage {
|
||||||
RequestUri = new Uri(uploadUrl),
|
RequestUri = new Uri(uploadUrl),
|
||||||
Method = HttpMethod.Put,
|
Method = HttpMethod.Put,
|
||||||
Content = new ByteArrayContent(data)
|
Content = content
|
||||||
};
|
};
|
||||||
HttpClient client = new HttpClient();
|
HttpClient client = new HttpClient();
|
||||||
request.Headers.CacheControl = new CacheControlHeaderValue {
|
request.Headers.CacheControl = new CacheControlHeaderValue {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,11 +22,14 @@ namespace LeanCloud.Storage.Internal.File {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task Upload(Action<int, int> onProgress) {
|
internal async Task Upload(Action<long, long> onProgress) {
|
||||||
MultipartFormDataContent content = new MultipartFormDataContent();
|
MultipartFormDataContent dataContent = new MultipartFormDataContent();
|
||||||
content.Add(new StringContent(key), "key");
|
dataContent.Add(new StringContent(key), "key");
|
||||||
content.Add(new StringContent(token), "token");
|
dataContent.Add(new StringContent(token), "token");
|
||||||
content.Add(new ByteArrayContent(data), "file");
|
dataContent.Add(new ByteArrayContent(data), "file");
|
||||||
|
|
||||||
|
LCProgressableStreamContent content = new LCProgressableStreamContent(dataContent, onProgress);
|
||||||
|
|
||||||
HttpRequestMessage request = new HttpRequestMessage {
|
HttpRequestMessage request = new HttpRequestMessage {
|
||||||
RequestUri = new Uri(uploadUrl),
|
RequestUri = new Uri(uploadUrl),
|
||||||
Method = HttpMethod.Post,
|
Method = HttpMethod.Post,
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LeanCloud.Storage.Internal.File;
|
using LeanCloud.Storage.Internal.File;
|
||||||
using LeanCloud.Storage.Internal.Object;
|
using LeanCloud.Storage.Internal.Object;
|
||||||
|
using LeanCloud.Common;
|
||||||
|
|
||||||
namespace LeanCloud.Storage {
|
namespace LeanCloud.Storage {
|
||||||
public class LCFile : LCObject {
|
public class LCFile : LCObject {
|
||||||
|
@ -67,7 +68,7 @@ namespace LeanCloud.Storage {
|
||||||
MetaData[key] = value;
|
MetaData[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<LCFile> Save() {
|
public async Task<LCFile> Save(Action<long, long> onProgress = null) {
|
||||||
if (!string.IsNullOrEmpty(Url)) {
|
if (!string.IsNullOrEmpty(Url)) {
|
||||||
// 外链方式
|
// 外链方式
|
||||||
await base.Save();
|
await base.Save();
|
||||||
|
@ -81,11 +82,11 @@ namespace LeanCloud.Storage {
|
||||||
if (provider == "s3") {
|
if (provider == "s3") {
|
||||||
// AWS
|
// AWS
|
||||||
LCAWSUploader uploader = new LCAWSUploader(uploadUrl, MimeType, data);
|
LCAWSUploader uploader = new LCAWSUploader(uploadUrl, MimeType, data);
|
||||||
await uploader.Upload(null);
|
await uploader.Upload(onProgress);
|
||||||
} else if (provider == "qiniu") {
|
} else if (provider == "qiniu") {
|
||||||
// Qiniu
|
// Qiniu
|
||||||
LCQiniuUploader uploader = new LCQiniuUploader(uploadUrl, token, key, data);
|
LCQiniuUploader uploader = new LCQiniuUploader(uploadUrl, token, key, data);
|
||||||
await uploader.Upload(null);
|
await uploader.Upload(onProgress);
|
||||||
} else {
|
} else {
|
||||||
throw new Exception($"{provider} is not support.");
|
throw new Exception($"{provider} is not support.");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue