UploadController.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. using MiniWebApi.Handler;
  2. using MiniWebApi.Network;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net.Http;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using Vinno.vCloud.Disk.Database;
  11. using Vinno.vCloud.Disk.Database.Dto;
  12. using Vinno.vCloud.Disk.UFile;
  13. using Vinno.vCloud.Common.Storage.ObjectStorageInfo.Authorization;
  14. using Vinno.vCloud.Common.Storage.ObjectStorageInfo.Solid;
  15. using System.Collections.Concurrent;
  16. using Vinno.IUS.Common.Log;
  17. using Vinno.vCloud.Protocol.Infrastructures.Storage;
  18. using Vinno.vCloud.Common.Storage.ObjectStorageInfo;
  19. using Vinno.vCloud.Disk.Tencent;
  20. namespace Vinno.vCloud.Disk.Controllers
  21. {
  22. [WebApiHandler("Upload")]
  23. class UploadController : BaseHandler
  24. {
  25. private ConcurrentDictionary<string, ConcurrentQueue<int>> _uploadProgressDic = new ConcurrentDictionary<string, ConcurrentQueue<int>>();
  26. private string _filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TempFiles");
  27. /// <summary>
  28. /// 上传文件
  29. /// </summary>
  30. /// <param name="context"></param>
  31. [Post]
  32. public void UploadFile(WebApiHttpContext context)
  33. {
  34. try
  35. {
  36. var contentType = context.Request.GetHeader().Get("ContentType");
  37. var param = context.Request.GetFormDataValues();
  38. var buffer = param.GetValue<byte[]>("fileData");
  39. var fileMd5 = param.GetValue<string>("fileMd5");
  40. var chunk = param.GetValue<string>("chunk");
  41. SaveFile(buffer, fileMd5, chunk);
  42. context.Response.Json(new { Success = true, Msg = string.Empty }, true);
  43. }
  44. catch (Exception ex)
  45. {
  46. FileHelper.AppendWriteFile("Log.txt", ex.Message + "|" + ex.StackTrace);
  47. context.Response.Json(new { Success = false, Msg = "Fail to upload!" }, true);
  48. }
  49. }
  50. /// <summary>
  51. /// 保存临时文件
  52. /// </summary>
  53. /// <param name="enc"></param>
  54. /// <param name="boundary"></param>
  55. /// <param name="inputArg"></param>
  56. /// <param name="filePath"></param>
  57. private void SaveFile(byte[] fileData, string fileMd5, string chunk)
  58. {
  59. //设置文件路径
  60. string tempFileName;
  61. Directory.CreateDirectory(_filePath);
  62. if (chunk==null)
  63. {
  64. tempFileName = Path.Combine(_filePath, fileMd5 + ".zip");
  65. }
  66. else
  67. {
  68. tempFileName = Path.Combine(_filePath, $"{fileMd5}.{chunk}.temp");
  69. }
  70. try
  71. {
  72. bool isTempFileAdd = true;
  73. using (FileStream tempStream = new FileStream(tempFileName, FileMode.OpenOrCreate, FileAccess.Write))
  74. {
  75. tempStream.Seek(0, SeekOrigin.Begin);
  76. if (fileData.Length > 0)
  77. {
  78. tempStream.Write(fileData, 0, fileData.Length);
  79. }
  80. tempStream.Flush();
  81. if (tempStream.Length == 0)
  82. {
  83. isTempFileAdd = false;
  84. }
  85. }
  86. if (!isTempFileAdd)
  87. {
  88. File.Delete(tempFileName);
  89. }
  90. }
  91. catch
  92. {
  93. File.Delete(tempFileName);
  94. }
  95. }
  96. /// <summary>
  97. /// 合并临时文件
  98. /// </summary>
  99. /// <param name="fileName"></param>
  100. /// <param name="fileMd5"></param>
  101. /// <param name="userName"></param>
  102. /// <returns></returns>
  103. [Post]
  104. public void Merge(WebApiHttpContext context)
  105. {
  106. try
  107. {
  108. var param = context.GetParams();
  109. var guid = param.GetValue<string>("guid");
  110. var fileName = param.GetValue<string>("fileName");
  111. var fileMd5 = param.GetValue<string>("fileMd5");
  112. var userName = param.GetValue<string>("userName");
  113. var currId = param.GetValue<string>("currId");
  114. var currUser = param.GetValue<string>("currUser");
  115. var fileSize = param.GetValue<string>("fileSize").ToFloat();
  116. if (!string.IsNullOrWhiteSpace(fileMd5))
  117. {
  118. var files = Directory.GetFiles(_filePath);//获得下面的所有文件
  119. files = files.Where(path => path.IndexOf(fileMd5, StringComparison.Ordinal) > -1).ToArray();
  120. if (files.Length > 0)
  121. {
  122. bool isHadEmptyFiles = false;
  123. using (var ms = new MemoryStream())
  124. {
  125. var sortedFiles = files.OrderBy(x => x.Length).ThenBy(x => x);
  126. foreach (var part in sortedFiles)//排一下序,保证从0-N Write
  127. {
  128. var bytes = File.ReadAllBytes(part);
  129. if (bytes.Length == 0)
  130. {
  131. File.Delete(part);
  132. isHadEmptyFiles = true;
  133. }
  134. if (!isHadEmptyFiles)
  135. {
  136. ms.Write(bytes, 0, bytes.Length);
  137. }
  138. }
  139. ms.Flush();
  140. if (isHadEmptyFiles)
  141. {
  142. throw new Exception("Has empty files!");
  143. }
  144. var fileExtension = Path.GetExtension(fileName);
  145. var mimeType = HttpClientHelper.GetMimeType(fileExtension);
  146. var fileUrl = CosUploadHelper.UploadFile(ms.ToArray(), fileMd5 + fileExtension, mimeType, f => UploadProgressCallback((int)f, guid));
  147. var isSuccess = false;
  148. if (!string.IsNullOrEmpty(fileUrl))
  149. {
  150. Task.Run(() =>
  151. {
  152. foreach (var part in files)
  153. {
  154. File.Delete(part);//删除分块
  155. }
  156. });
  157. FoldersAndFiles foldersAndFiles = new FoldersAndFiles();
  158. foldersAndFiles.Name = fileName;
  159. foldersAndFiles.Password = string.Empty;
  160. foldersAndFiles.Type = 0;
  161. foldersAndFiles.FileUrl = fileUrl;
  162. foldersAndFiles.FatherId = currId.ToInt();
  163. foldersAndFiles.FileMd5 = fileMd5;
  164. foldersAndFiles.Creater = currUser;
  165. foldersAndFiles.CreateTime = DateTime.UtcNow;
  166. foldersAndFiles.FileSize = fileSize;
  167. isSuccess = SqlExecute.DB.Insert(foldersAndFiles) > 0;
  168. }
  169. bool isRemoveQueue = _uploadProgressDic.TryRemove(guid,out _);
  170. Logger.WriteLineInfo($"Remove queue { (isRemoveQueue ? "success" : "fail") } guid:{guid}");
  171. context.Response.Json(new { Success = isSuccess, Msg = string.Empty }, true);
  172. return;
  173. }
  174. }
  175. }
  176. }
  177. catch (Exception ex)
  178. {
  179. FileHelper.AppendWriteFile("Log.txt", ex.Message + "|" + ex.StackTrace);
  180. }
  181. context.Response.Json(new { Success = false, Msg = string.Empty }, true);
  182. }
  183. /// <summary>
  184. /// 检查上传文件Md5
  185. /// </summary>
  186. /// <param name="fileMd5"></param>
  187. /// <returns></returns>
  188. [Post]
  189. public void CheckUpload(WebApiHttpContext context)
  190. {
  191. var param = context.GetParams();
  192. var fileMd5 = param.GetValue<string>("fileMd5");
  193. if (!CheckMd5(fileMd5))
  194. {
  195. List<string> filesPath = new List<string>();
  196. if (Directory.Exists(_filePath))
  197. {
  198. var files = Directory.GetFiles(_filePath);//获得下面的所有文件
  199. files = files.Where(path => path.IndexOf(fileMd5, StringComparison.Ordinal) > -1).ToArray();
  200. foreach (var file in files)
  201. {
  202. var chunk = RegexHelper.MatchSub(file, $"{fileMd5}.([0-9]*).temp");
  203. filesPath.Add(chunk);
  204. }
  205. context.Response.Json(new { Chunks = string.Join(",", filesPath) }, true);
  206. return;
  207. }
  208. context.Response.Json(new { Chunks = string.Empty }, true);
  209. return;
  210. }
  211. context.Response.Json(new { Chunks = "%%%" }, true);
  212. }
  213. [Post]
  214. public void GetUploadProgress(WebApiHttpContext context)
  215. {
  216. var param = context.GetParams();
  217. var guid = param.GetValue<string>("guid");
  218. if (!string.IsNullOrWhiteSpace(guid))
  219. {
  220. var progress = GetProgressValue(guid);
  221. context.Response.Json(new { Progress = progress }, true);
  222. return;
  223. }
  224. context.Response.Json(new { Progress = 0 }, true);
  225. }
  226. private static bool CheckMd5(string fileMd5)
  227. {
  228. var data = SqlExecute.DB.Query(SqlExecute.DB.GetMapping<FoldersAndFiles>(), "select * from FoldersAndFiles where FileMd5 like ?", $"{fileMd5}%");
  229. if (data == null || data.Count == 0)
  230. {
  231. return false;
  232. }
  233. return true;
  234. }
  235. private void UploadProgressCallback(int progress,string guid)
  236. {
  237. var queue = _uploadProgressDic.GetValueOrDefault(guid);
  238. if (queue == null)
  239. {
  240. queue = new ConcurrentQueue<int>();
  241. _uploadProgressDic.TryAdd(guid, queue);
  242. }
  243. queue.Enqueue(progress);
  244. }
  245. private int GetProgressValue(string guid)
  246. {
  247. var queue = _uploadProgressDic.GetValueOrDefault(guid);
  248. if (queue != null)
  249. {
  250. int getTime = queue.Count;
  251. int progress = 0;
  252. while (getTime>0)
  253. {
  254. queue.TryDequeue(out progress);
  255. getTime--;
  256. }
  257. return progress;
  258. }
  259. return 0;
  260. }
  261. }
  262. }