123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- using Vinno.IUS.Common.IO;
- using Vinno.IUS.Common.Log;
- using Vinno.IUS.Common.Network.Leaf;
- using Vinno.IUS.Common.Network.Tcp;
- using Vinno.IUS.Common.Utilities;
- using Vinno.vCloud.Common.Storage.Upload;
- using Vinno.vCloud.Protocol.Infrastructures;
- using Vinno.vCloud.Protocol.Messages.Client.Storage;
- namespace Vinno.vCloud.Common.Storage
- {
- public class VCloudStorageUploader : IUploader
- {
- /// <summary>
- ///when app running ,set cache folder path
- /// </summary>
- private readonly List<IUploadStorageFileInfo> UploadStorageFileInfoList =
- new List<IUploadStorageFileInfo>();
- private const int MinBlockSize = 1048576; //4Mb
- private const int BlockSize = 4194304; //4mb
- /// <summary>
- /// Upload one file and return the file token.
- /// </summary>
- /// <param name="creator">The TcpCrerator for newtwork connection</param>
- /// <param name="fileData">The file data to be uploaded</param>
- /// <param name="progress">The upload progress</param>
- /// <param name="cancelTokenSource">The token to cancel the upload</param>
- /// <returns>The file token in server</returns>
- public string UploadFile(StorageInfo storageInfo, byte[] fileData, Action<double> progress = null, CancellationTokenSource cancelTokenSource = null, bool isReturnCDNUrl = true, bool isCopyFileToOtherNode = false, Func<string, string> GetAuthentication = null, Func<string, List<KeyValuePair<string, string>>, string> GetCopyAuthentication = null)
- {
- var storageUrl = storageInfo.Url;
- if (string.IsNullOrEmpty(storageUrl)) { throw new Exception("Storage url is empty"); }
- var creator = new TcpCreator(storageUrl);
- var storageLeaf = new ClientLeaf(new LeafIdContext(), LeafMode.Single, creator);
- try
- {
- using (var stream = new MemoryStream(fileData))
- {
- if (stream.Length <= BlockSize)
- {
- var size = (int)stream.Length;
- var data = new byte[size];
- stream.Read(data, 0, size);
- var buffer = new ByteBuffer(data);
- var token = storageLeaf.ApplyToken();
- var result = storageLeaf.Send(token, new StoreFileRequest { FileData = buffer });
- var storeFileSuccess = StoreFileSuccess.Convert(result);
- if (storeFileSuccess != null)
- {
- progress?.Invoke(1.0);
- return storeFileSuccess.FileToken;
- }
- }
- else
- {
- var size = (int)stream.Length;
- var count = size / BlockSize;
- var totalCount = size % BlockSize != 0 ? count + 1 : count;
- for (int i = 0; i < count; i++)
- {
- if (cancelTokenSource != null && cancelTokenSource.IsCancellationRequested)
- {
- return null;
- }
- var data = new byte[BlockSize];
- stream.Read(data, 0, BlockSize);
- var buffer = new ByteBuffer(data);
- var token = storageLeaf.ApplyToken();
- var result = storageLeaf.Send(token, new StoreFileRequest { FileData = buffer, Index = i, Count = totalCount });
- var storeFileSuccess = StoreFileSuccess.Convert(result);
- if (storeFileSuccess == null)
- {
- throw new InvalidOperationException("Store file error");
- }
- progress?.Invoke(((double)i + 1) / totalCount);
- var isDone = totalCount == count && i == count - 1;
- size -= BlockSize;
- if (isDone)
- {
- return storeFileSuccess.FileToken;
- }
- }
- if (size > 0)
- {
- if (cancelTokenSource != null && cancelTokenSource.IsCancellationRequested)
- {
- return null;
- }
- var data = new byte[size];
- stream.Read(data, 0, size);
- var buffer = new ByteBuffer(data);
- var token = storageLeaf.ApplyToken();
- var result = storageLeaf.Send(token, new StoreFileRequest
- { FileData = buffer, Index = totalCount - 1, Count = totalCount });
- var storeFileSuccess = StoreFileSuccess.Convert(result);
- if (storeFileSuccess == null)
- {
- throw new InvalidOperationException("Store file error");
- }
- progress?.Invoke(1.0);
- return storeFileSuccess.FileToken;
- }
- }
- }
- }
- finally
- {
- storageLeaf.Close();
- }
- throw new InvalidOperationException("Store file failed.");
- }
- /// <summary>
- /// new upload file(Breakpoint continuingly)
- /// </summary>
- /// <param name="creator"></param>
- /// <param name="filePath"></param>
- /// <param name="accountId">current account id</param>
- /// <param name="progress"> UI action progress</param>
- /// <param name="cancelTokenSource"></param>
- /// <returns>file token</returns>
- public string UploadFile(StorageInfo storageInfo, string filePath, string accountId,
- Action<double> progress = null,
- CancellationTokenSource cancelTokenSource = null,bool isReturnCDNUrl = true, bool isCopyFileToOtherNode = false, Func<string, string> GetAuthentication = null, Func<string, List<KeyValuePair<string, string>>, string> GetCopyAuthentication = null)
- {
- var storageUrl = storageInfo.Url;
- var creator = new TcpCreator(storageUrl);
- var storageLeaf = new ClientLeaf(new LeafIdContext(), LeafMode.Single, creator);
- try
- {
- if (!storageLeaf.Online)
- {
- throw new Exception($"storageLeaf is offline for upload file,url:{storageInfo}");
- }
- using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- Logger.WriteLineInfo($"UploadStoreFile:filePath{filePath} begin");
- var uploadFileToken = UploadFileFromStream(stream,
- accountId, progress, storageLeaf, cancelTokenSource);
- return uploadFileToken;
- }
- }
- finally
- {
- storageLeaf.Close();
- }
- }
- /// <summary>
- /// new upload file(Breakpoint continuingly)
- /// </summary>
- /// <param name="filePath">The upload file path</param>
- /// <param name="fileName">The file name in file server.</param>
- /// <param name="accountId">The account id</param>
- /// <param name="storageInfo">The storage info.</param>
- /// <param name="progress"> UI action progress</param>
- /// <param name="cancelTokenSource"></param>
- /// <returns>file token</returns>
- public string UploadFile(StorageInfo storageInfo, string filePath, string fileName, string accountId, Action<double> progress, CancellationTokenSource cancelTokenSource, bool isReturnCDNUrl, bool isCopyFileToOtherNode, Func<string, string> GetAuthentication, Func<string, List<KeyValuePair<string, string>>, string> GetCopyAuthentication = null)
- {
- var storageUrl = storageInfo.Url;
- var creator = new TcpCreator(storageUrl);
- var storageLeaf = new ClientLeaf(new LeafIdContext(), LeafMode.Single, creator);
- try
- {
- if (!storageLeaf.Online)
- {
- throw new Exception($"storageLeaf is offline for upload file,url:{storageInfo}");
- }
- using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- Logger.WriteLineInfo($"UploadStoreFile:filePath{filePath} begin");
- var uploadFileToken = UploadFileFromStream(fileName,stream,
- progress, storageLeaf, cancelTokenSource);
- return uploadFileToken;
- }
- }
- finally
- {
- storageLeaf.Close();
- }
- }
- /// <summary>
- /// Upload file to server by stream
- /// </summary>
- /// <param name="stream"></param>
- /// <param name="accountId"></param>
- /// <param name="progress"></param>
- /// <param name="storageLeaf"></param>
- /// <param name="cancelTokenSource"></param>
- /// <returns>file token</returns>
- private string UploadFileFromStream(string fileName,Stream stream,Action<double> progress, ClientLeaf storageLeaf,
- CancellationTokenSource cancelTokenSource = null)
- {
- progress?.Invoke(0.01);
- var fileSize = (int)stream.Length;
- var md5 = MD5.GetHashString(stream);
- var currentUploadFileInfo = new UploadStorageFileInfo()
- {
- CacheFileName = fileName,
- FilePosition = 0,
- FileSize = fileSize,
- Id = string.Empty,
- MD5 = md5
- };
- while (fileSize > currentUploadFileInfo.FilePosition + 1)
- {
- if (cancelTokenSource != null && cancelTokenSource.IsCancellationRequested)
- {
- //upload file canceled
- return null;
- }
- var token = storageLeaf.ApplyToken();
- var createuploadRequest = CreateUploadRequest(stream, "", currentUploadFileInfo, fileSize);
- var result = storageLeaf.Send(token, createuploadRequest);
- var storeFileResult = UploadStoreFileResult.Convert(result);
- if (storeFileResult != null)
- {
- var storeFileInfoMessage = storeFileResult.ClientUploadStorageFileInfoMessage;
- currentUploadFileInfo.Id = storeFileInfoMessage.Id;
- currentUploadFileInfo.CacheFileName = storeFileInfoMessage.CacheFileName;
- currentUploadFileInfo.FilePosition = storeFileInfoMessage.FilePosition;
- if (!string.IsNullOrWhiteSpace(storeFileInfoMessage.FileToken))
- {
- // upload file success
- currentUploadFileInfo.FileToken = storeFileInfoMessage.FileToken;
- progress?.Invoke(1.0);
- return currentUploadFileInfo.FileToken;
- }
- progress?.Invoke((double)currentUploadFileInfo.FilePosition / fileSize);
- }
- else
- {
- throw new InvalidOperationException("Store file error");
- }
- }
- return currentUploadFileInfo.FileToken;
- }
- /// <summary>
- /// Upload file to server by stream
- /// </summary>
- /// <param name="stream"></param>
- /// <param name="accountId"></param>
- /// <param name="progress"></param>
- /// <param name="storageLeaf"></param>
- /// <param name="cancelTokenSource"></param>
- /// <returns>file token</returns>
- private string UploadFileFromStream(Stream stream,
- string accountId, Action<double> progress, ClientLeaf storageLeaf,
- CancellationTokenSource cancelTokenSource = null)
- {
- progress?.Invoke(0.01);
- var fileSize = (int)stream.Length;
- var md5 = MD5.GetHashString(stream);
- var currentUploadFileInfo = new UploadStorageFileInfo()
- {
- CacheFileName = string.Empty,
- FilePosition = 0,
- FileSize = fileSize,
- Id = string.Empty,
- MD5 = md5
- };
- currentUploadFileInfo.FileSize = fileSize;
- while (fileSize > currentUploadFileInfo.FilePosition + 1)
- {
- if (cancelTokenSource != null && cancelTokenSource.IsCancellationRequested)
- {
- //upload file canceled
- return null;
- }
- var token = storageLeaf.ApplyToken();
- var createuploadRequest = CreateUploadRequest(stream, accountId, currentUploadFileInfo, fileSize);
- var result = storageLeaf.Send(token, createuploadRequest);
- var storeFileResult = UploadStoreFileResult.Convert(result);
- if (storeFileResult != null)
- {
- var storeFileInfoMessage = storeFileResult.ClientUploadStorageFileInfoMessage;
- currentUploadFileInfo.Id = storeFileInfoMessage.Id;
- currentUploadFileInfo.CacheFileName = storeFileInfoMessage.CacheFileName;
- currentUploadFileInfo.FilePosition = storeFileInfoMessage.FilePosition;
- if (!string.IsNullOrWhiteSpace(storeFileInfoMessage.FileToken))
- {
- // upload file success
- currentUploadFileInfo.FileToken = storeFileInfoMessage.FileToken;
- progress?.Invoke(1.0);
- return currentUploadFileInfo.FileToken;
- }
- progress?.Invoke((double)currentUploadFileInfo.FilePosition / fileSize);
- }
- else
- {
- throw new InvalidOperationException("Store file error");
- }
- }
- return currentUploadFileInfo.FileToken;
- }
- private async Task<string> UploadFileFromStreamAsync(Stream stream,
- string accountId, Action<double> progress, ClientLeaf storageLeaf,
- CancellationTokenSource cancelTokenSource = null)
- {
- progress?.Invoke(0.01);
- var fileSize = (int)stream.Length;
- var md5 = MD5.GetHashString(stream);
- var currentUploadFileInfo = UploadStorageFileInfoList.FirstOrDefault(v => v.MD5 == md5);
- if (currentUploadFileInfo == null)
- {
- currentUploadFileInfo = new UploadStorageFileInfo()
- {
- CacheFileName = string.Empty,
- FilePosition = 0,
- FileSize = fileSize,
- Id = string.Empty,
- MD5 = md5
- };
- UploadStorageFileInfoList.Add(currentUploadFileInfo);
- }
- currentUploadFileInfo.FileSize = fileSize;
- while (fileSize > currentUploadFileInfo.FilePosition + 1)
- {
- if (cancelTokenSource != null && cancelTokenSource.IsCancellationRequested)
- {
- //upload file canceled
- return null;
- }
- var token = storageLeaf.ApplyToken();
- var result = await storageLeaf.SendAsync(token, CreateUploadRequest(
- stream, accountId, currentUploadFileInfo, fileSize));
- var storeFileResult = UploadStoreFileResult.Convert(result);
- if (storeFileResult != null)
- {
- var storeFileInfoMessage = storeFileResult.ClientUploadStorageFileInfoMessage;
- currentUploadFileInfo.Id = storeFileInfoMessage.Id;
- currentUploadFileInfo.FileToken = storeFileInfoMessage.FileToken;
- currentUploadFileInfo.CacheFileName = storeFileInfoMessage.CacheFileName;
- currentUploadFileInfo.FilePosition = storeFileInfoMessage.FilePosition;
- if (!string.IsNullOrEmpty(currentUploadFileInfo.FileToken))
- {
- // upload file success
- progress?.Invoke(1.0);
- return currentUploadFileInfo.FileToken;
- }
- progress?.Invoke((double)currentUploadFileInfo.FilePosition / fileSize);
- }
- else
- {
- throw new InvalidOperationException("Store file error");
- }
- Thread.Sleep(10);
- }
- return currentUploadFileInfo.FileToken;
- }
- private UploadStoreFileRequest CreateUploadRequest(Stream stream, string accountId,
- IUploadStorageFileInfo currentUploadFileInfo, int fileSize)
- {
- Logger.WriteLineInfo($"UploadStoreFile CreateUploadRequest begin");
- //set this upload file end position byte
- var lastPosition = currentUploadFileInfo.FilePosition + BlockSize - 1;
- var fileSizePostion = fileSize - 1;
- if (lastPosition > fileSizePostion)
- {
- int offet = fileSizePostion - currentUploadFileInfo.FilePosition;
- if (offet > MinBlockSize)
- {
- lastPosition = currentUploadFileInfo.FilePosition + MinBlockSize;
- }
- else
- {
- lastPosition = fileSizePostion;
- }
- }
- if (lastPosition == fileSizePostion)
- {
- lastPosition = fileSizePostion;
- }
- //set this upload file byte size
- var blockSize = lastPosition - currentUploadFileInfo.FilePosition + 1;
- stream.Position = currentUploadFileInfo.FilePosition;
- var data = new byte[blockSize];
- stream.Read(data, 0, blockSize);
- var buffer = new ByteBuffer(data);
- Logger.WriteLineInfo($"UploadStoreFile blockSize: {blockSize} filePosition:{currentUploadFileInfo.FilePosition}");
- // upload to server
- var uploadmessage = new ClientUploadStorageFileInfoMessage
- {
- FileData = buffer,
- Id = currentUploadFileInfo.Id,
- FileMd5 = currentUploadFileInfo.MD5,
- AccountId = accountId ?? string.Empty,
- FileSize = currentUploadFileInfo.FileSize,
- FilePosition = currentUploadFileInfo.FilePosition,
- FileToken = currentUploadFileInfo.FileToken,
- CacheFileName = currentUploadFileInfo.CacheFileName
- };
- return new UploadStoreFileRequest { ClientUploadStorageFileInfoMessage = uploadmessage };
- }
-
- /// <summary>
- /// upload file async
- /// </summary>
- /// <param name="storageUrl"></param>
- /// <param name="fileData"></param>
- /// <param name="progress"></param>
- /// <param name="cancelTokenSource"></param>
- /// <returns></returns>
- public async Task<string> UploadFileAsync(StorageInfo storageInfo, byte[] fileData, Action<double> progress, CancellationTokenSource cancelTokenSource, bool isReturnCDNUrl = true, bool isCopyFileToOtherNode = false, Func<string, string> GetAuthentication = null, Func<string, List<KeyValuePair<string, string>>, string> GetCopyAuthentication = null)
- {
- var storageUrl = storageInfo.Url;
- if (string.IsNullOrEmpty(storageUrl)) { throw new Exception($"Storage url is empty, {storageInfo}"); }
- var creator = new TcpCreator(storageUrl);
- var storageLeaf = new ClientLeaf(new LeafIdContext(), LeafMode.Single, creator);
- try
- {
- using (var stream = new MemoryStream(fileData))
- {
- if (stream.Length <= BlockSize)
- {
- var size = (int)stream.Length;
- var data = new byte[size];
- await stream.ReadAsync(data, 0, size);
- var buffer = new ByteBuffer(data);
- var token = storageLeaf.ApplyToken();
- var result = await storageLeaf.SendAsync(token, new StoreFileRequest { FileData = buffer });
- var storeFileSuccess = StoreFileSuccess.Convert(result);
- if (storeFileSuccess != null)
- {
- progress?.Invoke(1.0);
- return storeFileSuccess.FileToken;
- }
- }
- else
- {
- var size = (int)stream.Length;
- var count = size / BlockSize;
- var totalCount = size % BlockSize != 0 ? count + 1 : count;
- for (int i = 0; i < count; i++)
- {
- if (cancelTokenSource != null && cancelTokenSource.IsCancellationRequested)
- {
- return null;
- }
- var data = new byte[BlockSize];
- await stream.ReadAsync(data, 0, BlockSize);
- var buffer = new ByteBuffer(data);
- var token = storageLeaf.ApplyToken();
- var result = await storageLeaf.SendAsync(token, new StoreFileRequest { FileData = buffer, Index = i, Count = totalCount });
- var storeFileSuccess = StoreFileSuccess.Convert(result);
- if (storeFileSuccess == null)
- {
- throw new InvalidOperationException("Store file error");
- }
- progress?.Invoke(((double)i + 1) / totalCount);
- var isDone = totalCount == count && i == count - 1;
- size -= BlockSize;
- if (isDone)
- {
- return storeFileSuccess.FileToken;
- }
- }
- if (size > 0)
- {
- if (cancelTokenSource != null && cancelTokenSource.IsCancellationRequested)
- {
- return null;
- }
- var data = new byte[size];
- stream.Read(data, 0, size);
- var buffer = new ByteBuffer(data);
- var token = storageLeaf.ApplyToken();
- var result = await storageLeaf.SendAsync(token, new StoreFileRequest
- { FileData = buffer, Index = totalCount - 1, Count = totalCount });
- var storeFileSuccess = StoreFileSuccess.Convert(result);
- if (storeFileSuccess == null)
- {
- throw new InvalidOperationException("Store file error");
- }
- progress?.Invoke(1.0);
- return storeFileSuccess.FileToken;
- }
- }
- }
- }
- finally
- {
- storageLeaf.Close();
- }
- throw new InvalidOperationException("Store file failed.");
- }
- /// <summary>
- /// new upload file(Breakpoint continuingly)
- /// </summary>
- /// <param name="filePath">The upload file path</param>
- /// <param name="fileName">The file name in file server.</param>
- /// <param name="storageInfo">The storage info.</param>
- /// <returns>file token</returns>
- public List<string> CopydFile(StorageInfo storageInfo, string filePath, string fileName, string destinationServer, Func<string, List<KeyValuePair<string, string>>, string> GetCopyAuthentication = null)
- {
- return new List<string>();
- }
- }
- }
|